获取两个地理位置之间的距离


108

我想制作一个可以检查用户最近的地方的应用程序。我可以轻松获取用户的位置,并且已经有了一个经度和纬度的位置列表。

相对于当前用户位置,了解列表最近位置的最佳方法是什么。

我在Google API中找不到任何内容。

Answers:


164
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);

参考:http : //developer.android.com/reference/android/location/Location.html#distanceTo(android.location.Location)


2
可能比使用Location.DistanceBetween()慢,因为它使用的是Location对象,但对我而言效果很好。
ZoltanF'2

我必须为位置信息导入哪个类import android.location.Location;或哪个
Pranav MS

@PranavMS是android.location.Location;
AndrewS

我认为distanceTo返回第一个点和最后一个点之间的距离,但在一条直线上,因此,如果您从a点到b点采取任何其他方向,由于路径不同,它将永远不会被精确化,也就是说,当distanceBetween加入时,您可以保存创建的点之间的每个距离,然后使用最终参数result []获得正确的距离。
加斯顿·塞伦(GastónSaillén)

122

http://developer.android.com/reference/android/location/Location.html

查看distanceTo或distanceBetween。您可以根据经纬度创建位置对象:

Location location = new Location("");
location.setLatitude(lat);
location.setLongitude(lon);

37
distanceBetween是一个静态方法,需要2套经纬度长点,因此您甚至无需实例化Location对象=)
Stan Kurdziel 2012年

4
我敢肯定他的意思是distanceTo方法。
laph

这很棒,而且很有帮助,但是构造函数中的String提供程序是什么?
miss.serena 2013年

33

一种近似的解决方案(基于等矩形投影),速度更快(仅需要1个trig和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;

您可以通过以下任一方法进一步优化

  1. 如果仅将距离与另一个距离进行比较(在这种情况下,请比较两个平方距离),则删除平方根
  2. 如果您计算一个主点到许多其他点的距离,则将余弦分解(在这种情况下,您将以该主点为中心进行等角投影,因此您可以为所有比较计算一次余弦)。

有关更多信息,请参见:http : //www.movable-type.co.uk/scripts/latlong.html

Haversine公式有多种语言的不错参考实现,网址为:http : //www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe


伟人thanx。但是,如果我需要在周边的一个位置周围获取一组位置,是否应该使用while循环来对照搜索到的位置检查每个位置,并仅保留周边的位置?
themhz 2012年

您可以,但这是中的蛮力方法O(n)。对于O(1)解决方案,在计算精确的解决方案之前,请使用2D空间索引来修剪潜在的匹配项。我们将离开这个问题的范围:)
洛朗·格雷戈里(LaurentGrégoire)2012年

这是一个很好的可能优化的很好的总结。Excactly什么,我一直在寻找
萨姆Vloeberghs

我只是想知道,如果这个公式适用于大的距离
Sandipan MAJHI

参见答案,但总之:,它不适用于长距离。与精确的Haversine公式相比,两点之间的距离越大,误差越大。
LaurentGrégoire19年

11

您可以使用两种方法,但是要确定哪种方法最好,我们首先需要知道您是否知道用户的海拔高度以及其他点的海拔高度吗?

根据您追求的准确性水平,您可以研究Haversine或Vincenty公式...

这些页面详细介绍了公式,并且在数学上不太偏爱的地方也提供了如何在脚本中实现公式的说明!

Haversine公式:http//www.movable-type.co.uk/scripts/latlong.html

文森特公式:http : //www.movable-type.co.uk/scripts/latlong-vincenty.html

如果您对公式中的任何含义有任何疑问,请发表评论,我会尽力回答这些问题:)


4

有两种方法可以获取LatLng之间的距离。

public static void distanceBetween (double startLatitude, double startLongitude, double endLatitude, double endLongitude, float[] results)

看到这个

第二

public float distanceTo (Location dest) 普拉文回答。


3
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];
    }

1

只需使用以下方法,将其传递给纬度和经度,就可以得到以米为单位的距离:

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

2
latlong1和latlong2没有定义
男孩

1
latlong1和latlong2是什么?
Nisal Malinda Livera

0

你可以使用谷歌地图API获取时间和距离 谷歌地图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);


}

0

a =sin²(Δφ/ 2)+ cosφ1⋅cosφ2⋅sin²(Δλ/ 2)

c = 2⋅atan2(√a,√(1-a))

距离= R⋅c

其中φ为纬度,λ为经度,R为地球半径(平均半径= 6,371km);

请注意,角度必须以弧度为单位才能传递给Trig函数!

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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.