查找平均位置并删除其他位置:

时间:2013-10-29 19:12:19

标签: java android location average

假设我每20分钟收集一次用户位置数据。在一天结束时,我有ArrayList个包含latlong字段及其他数据的对象。

我遇到两个问题并试图找出问题:

  1. 部分地点是从建筑物内部拍摄的,所以它们不是很准确,可能会散布在当时用户所在的实际位置。

  2. 有些位置是在不同时间拍摄的,但是来自同一位置,因为用户没有移动。

  3. 我想要达到的目的是找到彼此靠近的所有位置:比如说70米,找到所有这些位置的平均位置,只用这个平均位置替换它们。

    所以我要回答两个重要的问题:

    1. 找到所有近处位置的最佳方法是什么? 70米距离(请记住,阵列包含有效的位置变化。所以我必须找到附近的组并保持其他组完好无损。)

    2. 是否有方法或方法可以找到许多近处的平均位置?

3 个答案:

答案 0 :(得分:2)

关于近位置,我之前在这里回答了类似的问题:Android Maps v2 - animate camera to include most markers

具体来说,我认为你可以使用这段代码:

private List<Marker> getSurroundingMarkers(List<Marker> markers,
        LatLng origin, int maxDistanceMeters) {
    List<Marker> surroundingMarkers = surroundingMarkers = new ArrayList<Marker>();
    if (markers == null) return surroundingMarkers ;


        for (Marker marker : markers) {

            double dist = distBetween(origin, marker.getPosition());

            if (dist < maxDistanceMeters) {
                surroundingMarkers.add(marker);
            }
        }


    return surroundingMarkers;
}

private float distBetween(LatLng pos1, LatLng pos2) {
    return distBetween(pos1.latitude, pos1.longitude, pos2.latitude,
            pos2.longitude);
}

/** distance in meters **/
private float distBetween(double lat1, double lng1, double lat2, double lng2) {
    double earthRadius = 3958.75;
    double dLat = Math.toRadians(lat2 - lat1);
    double dLng = Math.toRadians(lng2 - lng1);
    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(Math.toRadians(lat1))
            * Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2)
            * Math.sin(dLng / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double dist = earthRadius * c;

    int meterConversion = 1609;

    return (float) (dist * meterConversion);
}

可能会重写标记部分以改为使用LatLng。

关于平均,它应该是一个简单的问题(比如你有n LatLng):

lat_avg = (lat1+lat2+...+latn)/n 
lng_avg = (lng1+lng2+...+lngn)/n 

latlng_avg = new LatLng(lat_avg, lat_lng)

答案 1 :(得分:1)

我不确定您是如何获取用户的位置的 - 无论您使用传统的LocationManager还是播放服务。我总是模仿我在Android开发人员博客上记录this approach的位置。如果您可以灵活地在位置收集方法之间切换,那么这个人是在内部还是外部都不应该那么重要。您应该在任何给定时间获得最佳位置。

假设您在足够的时间表上获得位置(我不知道您何时检查更新,但由于您希望所有内容都在半径70米范围内,我假设其按时间表而不是距离更改)找到平均点的基本方法是:

(1)将每个纬度/长度对转换为单位长度的3D矢量。 (2)对每个向量求和 (3)归一化得到的矢量 (4)转换回球坐标

这种方法documented here以及earlier SO post计算一组角度的平均值

示例代码非常容易理解 - 只需插入从您的位置获取的lat long值,您就可以了。

答案 2 :(得分:0)

对于来自同一位置的标记,我创建了以下方法:

public ArrayList<MyLocation> removeSameLocationMarkers(List<ParseObject> objects, int maxDistanceMeters) 
{
    boolean isLocationExist;
    ArrayList<MyLocation> acceptedLocations = new ArrayList<MyLocation>();

    if (objects == null) return acceptedLocations;

    for (ParseObject location1 : objects) 
    {
        isLocationExist = false;
        for (MyLocation location2 : acceptedLocations) 
        {
            if (!location1.equals(location2)) 
            {
                float distance = distBetween(location1.getDouble("latitude"), location1.getDouble("longitude"), location2.getLatitude(), location2.getLongitude());
                if (distance < maxDistanceMeters) 
                {
                    location2.addTimeToLocation(location1.getString("time"));
                    isLocationExist = true;
                }
            }
        }
        if (!isLocationExist)
        {
            Location newLocation = new Location("");
            newLocation.setLatitude(location1.getDouble("latitude"));
            newLocation.setLongitude(location1.getDouble("longitude"));
            String provider = location1.getString("provider");
            if (provider != null)
            {
                newLocation.setProvider(provider);
            }
            MyLocation newMyLocation = new MyLocation(newLocation);
            newMyLocation.addTimeToLocation(location1.getString("time"));
            acceptedLocations.add(newMyLocation);
        }
    }

    return acceptedLocations;
}