Sort list of lon\\lat points, start with nearest

2019-01-22 16:26发布

问题:

I have location from GPS (lon_base, lat_base). I have a list of locations (lon1, lat1|lon2, lat2|lon3, lat3...) This list is very long and is around the world.

My questions are: 1. How do I get from that list only the lon\lat that are 1 mile from my lon_base\lat_base? 2. How do I sort them from closest to farthest?

Thanks in advance!

回答1:

You want to define your own Comparator that, in general, looks something like this:

LonLat myHouse = /* whatever */ ;
Comparable comp = new Comparable () {
    LonLat a;
    int compareTo (Object b) {
        int aDist = calcDistance(a, myHouse) ;
        int bDist = calcDistance(b, myHouse) ;
        return aDist - bDist;
    }
};
myLonLatList.sort(lonLatList, comp);

where calcDistance() simply calculates the distance between the two points. If you're on Android, I think Google Maps has a function somewhere in their API that will do this for you.

EDIT : You'll want your calcDistance() function to look like ChrisJ's distance function.

-tjw



回答2:

public static List<Location> sortLocations(List<Location> locations, final double myLatitude,final double myLongitude) {
    Comparator comp = new Comparator<Location>() {
        @Override
        public int compare(Location o, Location o2) {
            float[] result1 = new float[3];
            android.location.Location.distanceBetween(myLatitude, myLongitude, o.Lat, o.Long, result1);
            Float distance1 = result1[0];

            float[] result2 = new float[3];
            android.location.Location.distanceBetween(myLatitude, myLongitude, o2.Lat, o2.Long, result2);
            Float distance2 = result2[0];

            return distance1.compareTo(distance2);
        }
    };


    Collections.sort(locations, comp);
    return locations;
}

Where the List of Locations is a list containing your own Location class, not the android.location.Location.



回答3:

You may use the great circle distance to calculate the distance between two points whose you know the latitude-longitude coordinates. The formulae are quite easy to code:

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


回答4:

You can use followig approximation (since 1 mile is much smaller than the radius of the earth) to calculate the distances from your base:

dx = cos(phi_base) * (theta - theta_base)
dy = phi - phi_base

dist = sqrt(dx*dx+dy*dy) 

with: phi = latitude and theta = longitude

The result is in units of 60 nautical miles if theta and phi are given in degrees. The results will be quite wrong for points that have a latitude that is much different from your base latitude, but this doesn't matter if you just want to know wich points are about 1 mile from your base.

For most programming languages you have to convert phi_base to radians (multiply by pi/180) in order to use it for cos().

(Attention: You have to take special care if your base longitude is very close to 180° or -180°, but probably that is not the case :-)

Use the calculated distances as sorting key to sort your points.

If you have to be more exact (e.g. if you want to know all points that are about 2000 miles from your home), than you must use the formula for Great Circle Distance to calculate the exact distance of two points on a sphere.



回答5:

According to this link i made working method. The answer above was wrong, because it doesn't convert lat/lng degrees to radians.

    private double getDistance(double fromLat, double fromLon, double toLat, double toLon){
        double radius = 6371;   // Earth radius in km
        double deltaLat = Math.toRadians(toLat - fromLat);
        double deltaLon = Math.toRadians(toLon - fromLon);
        double lat1 = Math.toRadians(fromLat);
        double lat2 = Math.toRadians(toLat);
        double aVal = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) +
            Math.sin(deltaLon/2) * Math.sin(deltaLon/2) * Math.cos(lat1) * Math.cos(lat2);
        double cVal = 2*Math.atan2(Math.sqrt(aVal), Math.sqrt(1-aVal));  

        double distance = radius*cVal;
        Log.d("distance","radius * angle = " +distance);
        return distance;
    }