gpt4 book ai didi

java - SQlite 获取最近的位置(经纬度)

转载 作者:IT老高 更新时间:2023-10-28 11:42:06 24 4
gpt4 key购买 nike

我的 SQLite 数据库中存储了经纬度数据,我想获取与我输入的参数最近的位置(例如,我当前的位置 - 纬度/经度等)。

我知道这在 MySQL 中是可能的,并且我已经进行了相当多的研究,认为 SQLite 需要一个自定义外部函数用于 Haversine 公式(计算球体上的距离),但我还没有找到任何写在Java 和作品。

另外,如果我想添加自定义函数,我需要 org.sqlite .jar(用于 org.sqlite.Function),这会增加不必要的大小应用程序。

另一方面,我需要 SQL 中的 Order by 函数,因为仅显示距离并不是什么大问题 - 我已经在自定义 SimpleCursorAdapter 中做到了,但我无法对数据进行排序,因为我的数据库中没有距离列。这意味着每次位置更改时都要更新数据库,这是对电池和性能的浪费。因此,如果有人对使用不在数据库中的列对光标进行排序有任何想法,我也将不胜感激!

我知道有大量的 Android 应用程序使用此功能,但谁能解释一下它的魔力。

顺便说一句,我找到了这个替代方案:Query to get records based on Radius in SQLite?

建议为 lat 和 lng 的 cos 和 sin 值创建 4 个新列,但是还有其他不那么多余的方法吗?

最佳答案

1) 首先,使用良好的近似值过滤您的 SQLite 数据,并减少您需要在 Java 代码中评估的数据量。为此,请使用以下过程:

要对数据有一个确定的阈值和更准确的过滤器,最好计算半径米内的4个位置 在您的 Java 代码中,然后通过小于和大于 SQL 运算符 (>、<) 轻松检查您的中心点的北、西、东和南,以确定您的数据库中的点是否在该矩形中。

calculateDerivedPosition(...) 方法会为您计算这些点(图片中的 p1、p2、p3、p4)。

enter image description here

/**
* Calculates the end-point from a given source at a given range (meters)
* and bearing (degrees). This methods uses simple geometry equations to
* calculate the end-point.
*
* @param point
* Point of origin
* @param range
* Range in meters
* @param bearing
* Bearing in degrees
* @return End-point from the source given the desired range and bearing.
*/
public static PointF calculateDerivedPosition(PointF point,
double range, double bearing)
{
double EarthRadius = 6371000; // m

double latA = Math.toRadians(point.x);
double lonA = Math.toRadians(point.y);
double angularDistance = range / EarthRadius;
double trueCourse = Math.toRadians(bearing);

double lat = Math.asin(
Math.sin(latA) * Math.cos(angularDistance) +
Math.cos(latA) * Math.sin(angularDistance)
* Math.cos(trueCourse));

double dlon = Math.atan2(
Math.sin(trueCourse) * Math.sin(angularDistance)
* Math.cos(latA),
Math.cos(angularDistance) - Math.sin(latA) * Math.sin(lat));

double lon = ((lonA + dlon + Math.PI) % (Math.PI * 2)) - Math.PI;

lat = Math.toDegrees(lat);
lon = Math.toDegrees(lon);

PointF newPoint = new PointF((float) lat, (float) lon);

return newPoint;

}

现在创建您的查询:

PointF center = new PointF(x, y);
final double mult = 1; // mult = 1.1; is more reliable
PointF p1 = calculateDerivedPosition(center, mult * radius, 0);
PointF p2 = calculateDerivedPosition(center, mult * radius, 90);
PointF p3 = calculateDerivedPosition(center, mult * radius, 180);
PointF p4 = calculateDerivedPosition(center, mult * radius, 270);

strWhere = " WHERE "
+ COL_X + " > " + String.valueOf(p3.x) + " AND "
+ COL_X + " < " + String.valueOf(p1.x) + " AND "
+ COL_Y + " < " + String.valueOf(p2.y) + " AND "
+ COL_Y + " > " + String.valueOf(p4.y);

COL_X 是数据库中存储纬度值的列名,COL_Y 是经度。

所以你有一些靠近你的中心点的数据,并且近似值很好。

2)现在您可以循环使用这些过滤后的数据,并使用以下方法确定它们是否真的靠近您的点(在圆圈中):

public static boolean pointIsInCircle(PointF pointForCheck, PointF center,
double radius) {
if (getDistanceBetweenTwoPoints(pointForCheck, center) <= radius)
return true;
else
return false;
}

public static double getDistanceBetweenTwoPoints(PointF p1, PointF p2) {
double R = 6371000; // m
double dLat = Math.toRadians(p2.x - p1.x);
double dLon = Math.toRadians(p2.y - p1.y);
double lat1 = Math.toRadians(p1.x);
double lat2 = Math.toRadians(p2.x);

double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2)
* Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = R * c;

return d;
}

享受吧!

我使用并定制了this reference并完成了。

关于java - SQlite 获取最近的位置(经纬度),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3695224/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com