代码之家  ›  专栏  ›  技术社区  ›  NullPointerException

使用SQLITE按最近的经纬度坐标排序

  •  9
  • NullPointerException  · 技术社区  · 14 年前

    我必须获得一个SQLite SQL语句,以便在给定初始位置的情况下,按最近的纬度和经度坐标进行排序。

    这是sqlite数据库中我的表的一个示例语句:

    SELECT id, name, lat, lng FROM items
    
    EXAMPLE RESULT: 1, Museu, 41375310.0, 2175970.0
    

    我必须用SQLite和那个表来实现这一点。我不能使用其他技术,因为这是针对我无法更改的现有SQlite数据库。

    有没有办法用Android和SQlite来实现这一点?我查了很多stackoverflow的帖子,但我没有找到实现这一点的方法

    谢谢

    5 回复  |  直到 14 年前
        1
  •  28
  •   chris    11 年前

    Darkwater的答案几乎是正确的。 为了正确,你需要使用差异的平方。 由于平方函数在SqLite上不可用,因此需要将差值相乘。 无需计算平方根。

    SELECT * AS distance FROM items ORDER BY ((location_lat-lat)*(location_lat-lat)) + ((location_lng - lng)*(location_lng - lng)) ASC
    
        2
  •  21
  •   Darkwater    14 年前
    SELECT * AS distance FROM items ORDER BY ABS(location_lat - lat) + ABS(location_lng - lng) ASC
    

    这应该大致对MySQL中的距离项目进行排序 应该 在SQLite中工作。
    如果你需要对它们进行更精确的排序,你可以尝试使用勾股定理(a^2+b^2=c^2)来获得精确的距离。

        3
  •  15
  •   Joonsoo Cris    8 年前

    Chris提出的解决方案:

    选择*作为距项目的距离ORDER BY((location_lat-lat)*(location_lat-lat)) +((location_lng-lng)*(location_lng-lng)ASC

    当我们接近赤道时是正确的。为了使其在其他纬度正确工作,我建议:

    选择*作为距项目的距离订购依据 ((location_lat-lat)*(location_lat-lat))+((location_lng -lng)*(位置lng)* 宇宙2号 )阿斯克

    其中我们必须预先计算:

    cos_lat_2 = cos(location_lat * PI / 180) ^ 2
    

    问题是:

    如果我们在赤道上,经度(东或西)移动一度,那么我们在40000公里的圆周上移动,代表40.000/360的距离。如果我们在纬度上移动一度(北或南),我们会在一个横跨两极的圆上移动,这也涉及40.000/360的距离(考虑到地球是一个球体)。

    但是,如果我们在英格兰南部,纬度为50°,经度(东或西)移动一度,我们就在50度平行线上移动,它的周长比赤道小。距离为perimet_parallel_50/360。计算这个周长很简单:perimeter_paralle_50=cos(50)*2*PI*EART_RADIUS=0.64*40000公里。如果我们向南或向北移动一度,就看不到距离的减少。我们移动的周长仍然有40000公里。

    解决方案:

    由于location_lat是预先已知的值,我们可以预先计算cos(location_lat)的值,以便将其用作比例因子,从而使经度和纬度上的位移相等。此外,我们对其进行预平方,以避免必须将其相乘两次。

    注意:

    这仍然是一个近似值,当移动很远的距离时,尤其是在两极附近和穿过第180子午线时,它会给出错误的结果。

        4
  •  5
  •   DanielFo    12 年前

    如果你知道,1度纬度大约是111111米,1度经度是111111*cos(纬度)米,那么你可以很容易地获得特定正方形内的所有位置。

    SELECT * FROM items WHERE latitude BETWEEN %f AND %f AND longitude BETWEEN %f AND %f
    

    这个查询非常快,即使有数百万行。但别忘了为纬度和经度创建一个索引:

    CREATE INDEX position ON items (latitude, longitude)
    

    我在Objective-C中使用它来获取当前位置周围3公里内的所有感兴趣的地方:

    double latDist = 1.0 / 111111.0 * 3.0;
    double lonDist = 1.0 / ABS(111111.0*cos(location.coordinate.latitude)) * 3.0;
    
    FMResultSet *results = [database executeQueryWithFormat:@"SELECT * FROM items WHERE latitude BETWEEN %f AND %f AND longitude BETWEEN %f AND %f", location.coordinate.latitude - latDist, location.coordinate.latitude + latDist, location.coordinate.longitude - lonDist, location.coordinate.longitude + lonDist];
    

    现在,您可以计算准确的距离并对结果进行排序。。。

        5
  •  3
  •   Paul D'Ambra    14 年前

    如果您能够加载记录;将它们转换为位置,然后 use the distanceTo function 我建议你这样做,但是。。。

    您可以使用普通SQL来近似两点之间的距离,各种方法如下 laid out clearly here 。如果使用简单的计算,您比较的点之间的距离越远,则您的值可能会变得越来越不正确

    如果你自己计算这些东西,并且你的位置可以在任何地方,那么如果你在比较国际日期线周围的位置,你可能需要意识到周围的值。