11

在我的 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、弧度、sin)不存在。有什么东西可以让我直接在数据库中计算距离吗?

但是,我有一个使用这种方法计算的 iPhone 应用程序。完美运行,但现在我需要在 Android 应用程序的数据库中执行相同的搜索。

提前致谢。

更新

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

4

5 回答 5

7

这是我要做的:

拿你给定的观点。测量一个(要细化的任意值)约 2 公里宽的正方形,并取东/西/北/南边界的值。

查询该正方形内的元素。这个很简单,你只需要

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

计算你的结果。没有足够的结果(显然小于 5,但我肯定会说两次),用更大的半径重试。太多(比如说,超过 100 个),用更小的半径再试一次。

一旦你有足够的,加载它们,确保你需要的所有 5 个元素不仅在 Xkm 宽的正方形中,而且在 Xkm 半径圆中(以避免之前的近似值没有检测到潜在的更近的元素)。

另一种方法

仅当您的给定点与您正在搜索的点相对接近时才有效。

测量平坦地球的局部近似值。接近您的观点,您可以考虑纬度、经度和距离之间的线性关系。这使您可以发出按简单演算排序的请求。(乘法和加法)。同样,选择更多点以便在 SQLite 请求之后进行正确的计算。

于 2012-04-12T15:47:38.013 回答
5

将 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);
}

查询,距离km

 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());
于 2016-01-07T10:03:23.760 回答
0
For windows:

Install minGw full options. modify environment variable: system variable path, including

c:\mingw\bin


test functionality command:

g++ --version

copy files: extension-functions.c, sqlite3.h, sqlite3ext.h in sqlite3 program directory. Go to sqlite3 directory and compile:

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

   (path = path of sqlite3ext.h; i.e. C:\sqlite3)

If the program is built so that loading extensions is permitted, the following will work:

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

   sqlite> select cos(radians(45));

   0.707106781186548

SQLite Distance implementation:

From:  https://www.movable-type.co.uk/scripts/latlong.html https://en.wikipedia.org/wiki/Haversine_formula

Distance
This uses the ‘haversine’ formula to calculate the great-circle distance between two points – that is, the shortest distance over the earth’s surface – giving an ‘as-the-crow-flies’ distance between the points (ignoring any hills they fly over, of course!).

Haversine
formula:    a = sin²(Δφ/2) + cos φ1 * cos φ2 * sin²(Δλ/2)
c = 2 * atan2( √a, √(1−a) )
c = 2 * 
d = R * c
where   φ is latitude, λ is longitude, R is earth’s radius (mean radius = 6,371km);
note that angles need to be in radians to pass to trig functions!
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 )))

Physical Properties of Earth https://en.wikipedia.org/wiki/Earth_ellipsoid :Ecuatorial radius: 6378.1366 Kms. Average radius: 6367 Kms


Constant = 2 * 6378136.6 = 12756273.2

SQLite query command with coordinates taken from table 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
于 2020-06-08T14:09:55.060 回答
0

Angel的回复并没有解决SQLite的问题,因为它仍然包含SQLite中不存在的ACOS功能

经过深入研究后,我得出的结论是,应该使用以下公式选择一个粗略的估计以在 SQLite 中使用:

公里的距离估计:

SQRT(SQUARE((TO_LAT-FROM_LAT)*110)+
     SQUARE((TO_LONG-FROM_LONG)*COS(TO_LAT)*111)) 
于 2018-05-31T11:44:35.247 回答
-3

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

参考这个链接

于 2012-04-12T15:16:03.390 回答