如何在Android中根据当前位置距离对地理点进行排序

9

我有一个“Place”对象,每个对象都有一个经纬度坐标:

import com.google.android.gms.maps.model.LatLng;

public class Place{
    public String name;
    public LatLng latlng;

    public Restaurant(String name, LatLng latlng) {
        this.name = name;
        this.latlng = latlng;
    }
}

我有一个这样的地点(ArrayList)列表,就像这样:

    ArrayList<Place> places = new ArrayList<Place>();
    places.add("Place 1", LatLng(90.0,90.0));
    places.add("Place 2", LatLng(93.0,93.0));
    places.add("Place 3", LatLng(83.0,92.0));
    places.add("Place 4", LatLng(93.0,91.0));

我有一个“我的”经纬度:

    LatLng myLocation = new LatLng(10.0,10.0);

我该如何按照距离我最近的顺序对这些对象进行排序?感谢您的帮助。


你熟悉Comparable接口吗? - MarsAtomic
我已经使用它来比较整数等简单的东西,但是我不确定如何比较像距离这样需要先计算的东西。 - user1282637
1
这个链接可能会很有用:https://dev59.com/b1XTa4cB1Zd3GeqP2HkE - shieldstroy
4个回答

17

使用@shieldstroy发布的问题中此答案所述算法,该算法使用Great Circle Distance,我已将其示例成功运行。

以下是Comparator

public class SortPlaces implements Comparator<Place> {
    LatLng currentLoc;

    public SortPlaces(LatLng current){
        currentLoc = current;
    }
    @Override
    public int compare(final Place place1, final Place place2) {
        double lat1 = place1.latlng.latitude;
        double lon1 = place1.latlng.longitude;
        double lat2 = place2.latlng.latitude;
        double lon2 = place2.latlng.longitude;

        double distanceToPlace1 = distance(currentLoc.latitude, currentLoc.longitude, lat1, lon1);
        double distanceToPlace2 = distance(currentLoc.latitude, currentLoc.longitude, lat2, lon2);
        return (int) (distanceToPlace1 - distanceToPlace2);
    }

    public double distance(double fromLat, double fromLon, double toLat, double toLon) {
        double radius = 6378137;   // approximate Earth radius, *in meters*
        double deltaLat = toLat - fromLat;
        double deltaLon = toLon - fromLon;
        double angle = 2 * Math.asin( Math.sqrt(
                Math.pow(Math.sin(deltaLat/2), 2) +
                        Math.cos(fromLat) * Math.cos(toLat) *
                                Math.pow(Math.sin(deltaLon/2), 2) ) );
        return radius * angle;
    }
}

这里是高层次的代码,我只是把它放在 onCreate() 中:

        //My location, San Francisco
        double lat = 37.77657;
        double lng = -122.417506;
        LatLng latLng = new LatLng(lat, lng);

        //set up list
        ArrayList<Place> places = new ArrayList<Place>();

        places.add(new Place("New York", new LatLng(40.571256,73.98369)));
        places.add(new Place("Colorado", new LatLng(39.260658,-105.101615)));
        places.add(new Place("Los Angeles", new LatLng(33.986816,118.473819)));

        for (Place p: places){
            Log.i("Places before sorting", "Place: " + p.name);
        }

        //sort the list, give the Comparator the current location
        Collections.sort(places, new SortPlaces(latLng));

        for (Place p: places){
            Log.i("Places after sorting", "Place: " + p.name);
        }

这是日志输出:

04-17 23:04:16.074  12963-12963/com.maptest.daniel.maptest I/Places before sorting﹕ Place: New York
04-17 23:04:16.074  12963-12963/com.maptest.daniel.maptest I/Places before sorting﹕ Place: Colorado
04-17 23:04:16.074  12963-12963/com.maptest.daniel.maptest I/Places before sorting﹕ Place: Los Angeles
04-17 23:04:16.074  12963-12963/com.maptest.daniel.maptest I/Places after sorting﹕ Place: Los Angeles
04-17 23:04:16.074  12963-12963/com.maptest.daniel.maptest I/Places after sorting﹕ Place: Colorado
04-17 23:04:16.074  12963-12963/com.maptest.daniel.maptest I/Places after sorting﹕ Place: New York

1
谢谢你的帮助,最终我做成了这个。 - user1282637
如果你需要计算并按距离排序大约10k个位置,该怎么办? - Beemo
@Beemo 使用Google Play服务和distanceBetween或distanceTo函数作为比较器以获得最佳效率。 - Abandoned Cart

3

计算距离有不同的方法可用。其中一个相当简单的方法是Haversine公式 (http://rosettacode.org/wiki/Haversine_formula#Java)。更精确的计算方法是Vincenty公式。如果两个位置不远,Haversine解决方案就足够了。

计算完距离后,您只需使用比较器对数组进行排序,例如:

Collections.sort(places, new Comparator<Place>() {
    public int compare(Place p1, Place p2) {
        return Double.compare(p1.getDistance(), p2.getDistance());
    }
});

1
如果你需要计算并按距离排序大约10k个位置,该怎么办? - Beemo
@Beemo 使用Google Play服务和distanceBetween或distanceTo函数作为比较器以获得最佳效率。 - Abandoned Cart

1

一旦获取了您的当前位置,您可以按照以下方式通过计算驾车距离(这在像餐厅之类的场所最为合适)进行排序:

  1. Calculate the distance to each object

    http://maps.googleapis.com/maps/api/directions/json?origin="+yourLat+","+yourLong+"&destination="+toLat+","+toLong+"&sensor=false&mode=DRIVING
    
  2. Once you calculate each distance , apply some simple sorting algorithm for those distances.


1
你知道谷歌地图API是通过公路路线还是直线距离获取距离的吗? - user1282637
我认为它提供的是道路路径而不是直线路径。 - Heshan Sandeepa
我会去查看一下,如果是路线指示的话,那肯定比直线更有用,再次感谢。 - user1282637
欢迎,肯定你需要道路路线作为直线距离,只需提供两个地理点之间的差异即可,但在现实世界中无法使用。 - Heshan Sandeepa

0

你可以使用

distanceInMeters = (loc1.distanceTo(loc2));

从谷歌地图API获取结果,然后将其添加到TreeMap中的Key中


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接