【发布时间】:2011-02-14 01:06:03
【问题描述】:
我想制作一个应用程序来检查用户最近的位置。我可以轻松获取用户的位置,并且我已经有了一个经纬度的地点列表。
根据当前用户位置了解列表中最近位置的最佳方法是什么。
我在谷歌 API 中找不到任何东西。
【问题讨论】:
标签: android geolocation maps
我想制作一个应用程序来检查用户最近的位置。我可以轻松获取用户的位置,并且我已经有了一个经纬度的地点列表。
根据当前用户位置了解列表中最近位置的最佳方法是什么。
我在谷歌 API 中找不到任何东西。
【问题讨论】:
标签: android geolocation maps
Location loc1 = new Location("");
loc1.setLatitude(lat1);
loc1.setLongitude(lon1);
Location loc2 = new Location("");
loc2.setLatitude(lat2);
loc2.setLongitude(lon2);
float distanceInMeters = loc1.distanceTo(loc2);
【讨论】:
import android.location.Location; 导入哪个类或哪个类
http://developer.android.com/reference/android/location/Location.html
查看 distanceTo 或 distanceBetween。您可以根据纬度和经度创建 Location 对象:
Location location = new Location("");
location.setLatitude(lat);
location.setLongitude(lon);
【讨论】:
distanceTo 方法。
一个近似解(基于 equirectangular 投影),更快(它只需要 1 个三角函数和 1 个平方根)。
如果您的点相距不太远,则此近似值是相关的。与真实的半正弦距离相比,它总是会高估。例如,如果两点之间的纬度或经度增量不超过 4 个十进制度,它将不超过 0.05382 % 到实际距离。
标准公式(Haversine)是精确的公式(也就是说,它适用于地球上的任何经度/纬度),但根据需要慢得多 7 个三角函数和 2 个平方根。如果您的两个点相距不太远,并且绝对精度不是最重要的,您可以使用这个近似版本(Equirectangular),因为它只使用一个三角函数和一个平方根,所以速度更快。
// Approximate Equirectangular -- works if (lat1,lon1) ~ (lat2,lon2)
int R = 6371; // km
double x = (lon2 - lon1) * Math.cos((lat1 + lat2) / 2);
double y = (lat2 - lat1);
double distance = Math.sqrt(x * x + y * y) * R;
您可以通过以下任一方式进一步优化:
欲了解更多信息,请参阅:http://www.movable-type.co.uk/scripts/latlong.html
Haversine 公式有多种语言的一个很好的参考实现:http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe
【讨论】:
O(n) 中的蛮力方法。对于O(1) 解决方案,请在计算精确解决方案之前使用二维空间索引来修剪潜在匹配项。我们将离开这个问题的范围:)
您可以使用几种方法,但要确定哪种方法最好,我们首先需要知道您是否知道用户的高度以及其他点的高度?
根据您所追求的准确度,您可以研究 Haversine 或 Vincenty 公式...
这些页面详细介绍了公式,并且,对于不太喜欢数学的人,还提供了如何在脚本中实现它们的说明!
Haversine 公式:http://www.movable-type.co.uk/scripts/latlong.html
文森提公式:http://www.movable-type.co.uk/scripts/latlong-vincenty.html
如果您对公式中的任何含义有任何疑问,请发表评论,我会尽力回答:)
【讨论】:
有两种方法可以获取 LatLng 之间的距离。
public static void distanceBetween (double startLatitude, double startLongitude, double endLatitude, double endLongitude, float[] results)
第二个
public float distanceTo (Location dest) 由 praveen 回答。
【讨论】:
private float getDistance(double lat1, double lon1, double lat2, double lon2) {
float[] distance = new float[2];
Location.distanceBetween(lat1, lon1, lat2, lon2, distance);
return distance[0];
}
【讨论】:
只需使用以下方法,将其经纬度传递并以米为单位获得距离:
private static double distance_in_meter(final double lat1, final double lon1, final double lat2, final double lon2) {
double R = 6371000f; // Radius of the earth in m
double dLat = (lat1 - lat2) * Math.PI / 180f;
double dLon = (lon1 - lon2) * Math.PI / 180f;
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(latlong1.latitude * Math.PI / 180f) * Math.cos(latlong2.latitude * Math.PI / 180f) *
Math.sin(dLon/2) * Math.sin(dLon/2);
double c = 2f * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double d = R * c;
return d;
}
【讨论】:
a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
c = 2 ⋅ atan2( √a, √(1−a) )
距离 = R ⋅ c
其中 φ 是纬度,λ 是经度,R 是地球半径(平均半径 = 6,371km);
请注意,角度需要以弧度为单位才能传递给三角函数!
fun distanceInMeter(firstLocation: Location, secondLocation: Location): Double {
val earthRadius = 6371000.0
val deltaLatitudeDegree = (firstLocation.latitude - secondLocation.latitude) * Math.PI / 180f
val deltaLongitudeDegree = (firstLocation.longitude - secondLocation.longitude) * Math.PI / 180f
val a = sin(deltaLatitudeDegree / 2).pow(2) +
cos(firstLocation.latitude * Math.PI / 180f) * cos(secondLocation.latitude * Math.PI / 180f) *
sin(deltaLongitudeDegree / 2).pow(2)
val c = 2f * atan2(sqrt(a), sqrt(1 - a))
return earthRadius * c
}
data class Location(val latitude: Double, val longitude: Double)
【讨论】:
您可以使用 google Map API 获取距离和时间 Google Map API
只需将下载的 JSON 传递给此方法,您将获得两个 latlong 之间的实时距离和时间
void parseJSONForDurationAndKMS(String json) throws JSONException {
Log.d(TAG, "called parseJSONForDurationAndKMS");
JSONObject jsonObject = new JSONObject(json);
String distance;
String duration;
distance = jsonObject.getJSONArray("routes").getJSONObject(0).getJSONArray("legs").getJSONObject(0).getJSONObject("distance").getString("text");
duration = jsonObject.getJSONArray("routes").getJSONObject(0).getJSONArray("legs").getJSONObject(0).getJSONObject("duration").getString("text");
Log.d(TAG, "distance : " + distance);
Log.d(TAG, "duration : " + duration);
distanceBWLats.setText("Distance : " + distance + "\n" + "Duration : " + duration);
}
【讨论】: