SQlite 获取最近的位置(带有纬度和经度)
我的 SQLite 数据库中存储有纬度和经度的数据,我想获取距我输入的参数最近的位置(例如我当前的位置 - 纬度/经度等)。
我知道这在 MySQL 中是可能的,并且我已经做了相当多的研究,SQLite 需要一个自定义外部函数来实现半正弦公式(计算球体上的距离),但我还没有找到任何用 Java 编写的并且可以工作的东西。
另外,如果我想添加自定义函数,我需要 org.sqlite .jar(用于 org.sqlite.Function),这会增加应用程序不必要的大小。
另一方面是,我需要 SQL 中的 Order by 函数,因为单独显示距离并不是什么大问题 - 我已经在自定义 SimpleCursorAdapter 中做到了这一点,但我无法对数据进行排序,因为我我的数据库中没有距离列。这意味着每次位置发生变化时都要更新数据库,这会浪费电池和性能。因此,如果有人有任何关于使用数据库中没有的列对游标进行排序的想法,我也将不胜感激!
我知道有大量的 Android 应用程序使用此功能,但有人可以解释一下其中的魔力吗?
顺便说一句,我找到了这个替代方案:Query to getrecords based on Radius in SQLite?
建议为 cos 创建 4 个新列以及 lat 和 lng 的 sin 值,但是还有其他不那么多余的方法吗?
I have data with latitude and longitude stored in my SQLite database, and I want to get the nearest locations to the parameters I put in (ex. My current location - lat/lng, etc.).
I know that this is possible in MySQL, and I've done quite some research that SQLite needs a custom external function for the Haversine formula (calculating distance on a sphere), but I haven't found anything that is written in Java and works.
Also, if I want to add custom functions, I need the org.sqlite
.jar (for org.sqlite.Function
), and that adds unnecessary size to the app.
The other side of this is, I need the Order by function from SQL, because displaying the distance alone isn't that much of a problem - I already did it in my custom SimpleCursorAdapter, but I can't sort the data, because I don't have the distance column in my database. That would mean updating the database every time the location changes and that's a waste of battery and performance. So if someone has any idea on sorting the cursor with a column that's not in the database, I'd be grateful too!
I know there are tons of Android apps out there that use this function, but can someone please explain the magic.
By the way, I found this alternative: Query to get records based on Radius in SQLite?
It's suggesting to make 4 new columns for cos and sin values of lat and lng, but is there any other, not so redundant way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
1) 首先使用良好的近似值过滤 SQLite 数据,并减少需要在 Java 代码中计算的数据量。为此,请使用以下过程:
要获得确定的阈值和更准确的数据过滤器,最好计算
半径4个位置 code> 中心点的北、西、东、南米在 java 代码中,然后通过小于和大于 SQL 运算符(>、<)轻松检查< /strong> 确定数据库中的点是否在该矩形内。
calculateDerivedPosition(...)
方法会为您计算这些点(图中的 p1、p2、p3、p4)。现在创建您的查询:
COL_X
是存储纬度值的数据库,COL_Y
用于存储经度。因此,您有一些接近中心点的数据,并且具有良好的近似值。
2) 现在,您可以循环处理这些过滤后的数据,并使用以下方法确定它们是否真的接近您的点(在圆圈中):
享受吧!
我使用并定制了此参考并完成了它。
1) At first filter your SQLite data with a good approximation and decrease amount of data that you need to evaluate in your java code. Use the following procedure for this purpose:
To have a deterministic threshold and more accurate filter on data, It is better to calculate 4 locations that are in
radius
meter of the north, west, east and south of your central point in your java code and then check easily by less than and more than SQL operators (>, <) to determine if your points in database are in that rectangle or not.The method
calculateDerivedPosition(...)
calculates those points for you (p1, p2, p3, p4 in picture).And now create your query:
COL_X
is the name of the column in the database that stores latitude values andCOL_Y
is for longitude.So you have some data that are near your central point with a good approximation.
2) Now you can loop on these filtered data and determine if they are really near your point (in the circle) or not using the following methods:
Enjoy!
I used and customized this reference and completed it.
Chris 的答案确实很有用(谢谢!),但只有在您使用直线坐标(例如 UTM 或 OS 网格参考)时才有效。如果使用纬度/经度的度数(例如 WGS84),则上述仅适用于赤道。在其他纬度,您需要减少经度对排序顺序的影响。 (想象一下您靠近北极......纬度仍然与任何地方相同,但经度可能只有几英尺。这意味着排序顺序不正确)。
如果您不在赤道,请根据您当前的纬度预先计算模糊因子:
然后按以下顺序排序:
((- LAT_COLUMN) * (- LAT_COLUMN) +- LNG_COLUMN) * (- LNG_COLUMN) *)
(
这仍然只是一个近似值,但比第一个要好得多,因此排序顺序不准确的情况会少得多。
Chris's answer is really useful (thanks!), but will only work if you are using rectilinear coordinates (eg UTM or OS grid references). If using degrees for lat/lng (eg WGS84) then the above only works at the equator. At other latitudes, you need to decrease the impact of longitude on the sort order. (Imagine you're close to the north pole... a degree of latitude is still the same as it is anywhere, but a degree of longitude may only be a few feet. This will mean that the sort order is incorrect).
If you are not at the equator, pre-calculate the fudge-factor, based on your current latitude:
Then order by:
((<lat> - LAT_COLUMN) * (<lat> - LAT_COLUMN) +
(<lng> - LNG_COLUMN) * (<lng> - LNG_COLUMN) * <fudge>)
It's still only an approximation, but much better than the first one, so sort order inaccuracies will be much rarer.
我知道这已得到回答并接受,但我想我会添加我的经验和解决方案。
虽然我很高兴在设备上执行半正矢函数来计算用户当前位置与任何特定目标位置之间的准确距离,但需要按距离顺序对查询结果进行排序和限制。
不太令人满意的解决方案是返回批次并在事后进行排序和过滤,但这会导致第二个光标以及许多不必要的结果被返回和丢弃。
我的首选解决方案是传递经度和纬度的平方增量值的排序顺序:
不需要仅针对排序顺序执行完整的半正矢,也不需要对结果求平方根,因此 SQLite 可以处理计算。
编辑:
这个答案仍然受到喜爱。它在大多数情况下工作正常,但如果您需要更高的准确性,请查看下面 @Teasel 的答案,该答案添加了一个“模糊”因素,可以修复随着纬度接近 90 而增加的不准确性。
I know this has been answered and accepted but thought I'd add my experiences and solution.
Whilst I was happy to do a haversine function on the device to calculate the accurate distance between the user's current position and any particular target location there was a need to sort and limit the query results in order of distance.
The less than satisfactory solution is to return the lot and sort and filter after the fact but this would result in a second cursor and many unnecessary results being returned and discarded.
My preferred solution was to pass in a sort order of the squared delta values of the long and lats:
There's no need to do the full haversine just for a sort order and there's no need to square root the results therefore SQLite can handle the calculation.
EDIT:
This answer is still receiving love. It works fine in most cases but if you need a little more accuracy, please check out the answer by @Teasel below which adds a "fudge" factor that fixes inaccuracies that increase as the latitude approaches 90.
为了尽可能提高性能,我建议使用以下
ORDER BY
子句改进 @Chris Simpson 的想法:在这种情况下,您应该从代码中传递以下值:
并且您还应该存储
LAT_LON_SQ_SUM = LAT_COL^2 + LON_COL^2
作为数据库中的附加列。将您的实体插入数据库来填充它。这在提取大量数据的同时稍微提高了性能。In order to increase performance as much as possible I suggest improve @Chris Simpson's idea with the following
ORDER BY
clause:In this case you should pass the following values from code:
And you should also store
LAT_LON_SQ_SUM = LAT_COL^2 + LON_COL^2
as additional column in database. Populate it inserting your entities into database. This slightly improves performance while extracting large amount of data.尝试这样的事情:
在此之后, id 包含您想要从数据库中获取的项目,以便您可以获取它:
希望有帮助!
Try something like this:
After this, id contains the item you want from the database so you can fetch it:
Hope that helps!