4

我有一组来自需要在地图上显示的网络服务的点。

我有一个当前的解决方案,在大多数情况下都能很好地工作,使用众所周知的LatLngBounds.Builder,CameraUpdateFactory.newLatLngBoundsmap.animateCamera.

我有一些情况会出现问题:当点太远时,地图以这些点的重心为中心以最大缩放级别为中心。例如:我在法国有10分,在夏威夷有2分。地图以最小缩放级别或多或少地集中在加勒比地区。因此在屏幕上我什么都没有显示,用户必须滚动才能真正看到那里有东西。

所以我的问题是:

有没有办法让地图缩小到足够远以便我可以看到所有点(那会是首选)

或者:这将是过滤掉那些只有几个点与大多数点相距甚远的情况并选择一组点进行放大的最佳方法(在我的示例中,我会选择放大法国的 10 个点)忘记夏威夷的那些)。

4

4 回答 4

5

将标记的所有LatLng放入列表中并将它们传递给此方法,并在newLatLngBounds(bounds, 50)) 50 的最后一行表示地图边缘与每侧最外侧标记之间的填充

public void centerIncidentRouteOnMap(List<LatLng> copiedPoints) {
        double minLat = Integer.MAX_VALUE;
        double maxLat = Integer.MIN_VALUE;
        double minLon = Integer.MAX_VALUE;
        double maxLon = Integer.MIN_VALUE;
        for (LatLng point : copiedPoints) {
            maxLat = Math.max(point.latitude, maxLat);
            minLat = Math.min(point.latitude, minLat);
            maxLon = Math.max(point.longitude, maxLon);
            minLon = Math.min(point.longitude, minLon);
        }
        final LatLngBounds bounds = new LatLngBounds.Builder().include(new LatLng(maxLat, maxLon)).include(new LatLng(minLat, minLon)).build();
        mapFragment.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 50));
    }
于 2013-09-30T23:14:17.363 回答
4

在我之前的代码中发现了一个错误,并决定坐下来重写它。

我之前做过类似的事情,我有大约 4500 个标记,并想选择在特定位置一定距离内的那些。采用该代码并将其概括为与任何类型的标记一起使用。

所有标记使用 getSurroundingMarkers 选择的标记

我将在下面发布的代码包含两种您可以使用的方法:

选择低距离标记

测量每个标记之间的距离,并仅选择与任何其他标记距离不远的那些。由于每个标记和之后的检查之间的比较,这需要 O(n+n^2) 运行时间。

获取周围标记

如果您已经知道要放大的位置,则此方法与上述相同。这种方法对 CPU 的负担要小得多,因为它只需要 O(n) 遍历所有标记并将它们与给定位置进行比较。

private List<Marker> selectLowDistanceMarkers(List<Marker> markers,
        int maxDistanceMeters) {

    List<Marker> acceptedMarkers = new ArrayList<Marker>();

    if (markers == null) return acceptedMarkers;

    Map<Marker, Float> longestDist = new HashMap<Marker, Float>();

    for (Marker marker1 : markers) {

        // in this for loop we remember the max distance for each marker
        // think of a map with a flight company's routes from an airport
        // these lines is drawn for each airport
        // marker1 being the airport and marker2 destinations

        for (Marker marker2 : markers) {
            if (!marker1.equals(marker2)) {
                float distance = distBetween(marker1.getPosition(),
                        marker2.getPosition());
                if (longestDist.containsKey(marker1)) {
                    // possible we have a longer distance
                    if (distance > longestDist.get(marker1))
                        longestDist.put(marker1, distance);
                } else {
                    // first distance
                    longestDist.put(marker1, distance);
                }
            }
        }
    }


    // examine the distances collected
    for (Marker marker: longestDist.keySet()) {
        if (longestDist.get(marker) <= maxDistanceMeters) acceptedMarkers.add(marker);
    }

    return acceptedMarkers;
}

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 < getHydrantsLoadradius()) {
                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);
}

同样,使用众所周知的 LatLngBounds 来确定在使用上述过滤算法之一后需要缩放多少。

于 2013-09-30T21:25:13.400 回答
0

根据 cYrixmorten 的一些想法,我简化了问题,因为我知道地图可以容纳至少 4000 公里的表面。所以这里是构建被忽略的网络摄像头列表的函数(然后我只是忽略该网络摄像头进行摄像头边界计算,但仍然添加标记,以便在用户移动时它在地图上)。

private List<Webcam> buildIgnoredWebcamsList(List<Webcam> webcams) {
    if (webcams == null || webcams.size() < 2) return Lists.newArrayList();

    int webcamCount = webcams.size();

    // Number of conflicts (distance > 4000 km) for the camera at index #
    float averageConflictCount = 0;
    int[] conflictCount = new int[webcamCount];
    Arrays.fill(conflictCount, 0);

    // Find number of conflicts between camera pairs
    float[] distance = new float[1];

    for (int i = 0; i < webcamCount - 1; ++i) {
        Webcam a = webcams.get(i);

                    // We don't have to start from 0, compare a and b only once
        for (int j = i + 1; j < webcamCount; ++j) {
            Webcam b = webcams.get(j);
            Location.distanceBetween(a.getLatitude(), a.getLongitude(), b.getLatitude(), b.getLongitude(), distance);

            // We have a conflict between a and b if they are more than 4000km away
            if (distance[0] > 4000 * 1000) {
                conflictCount[i] += 1;
                conflictCount[j] += 1;
                averageConflictCount += 2;
            }
        }
    }
    averageConflictCount /= webcamCount;

    // Exclude all webcams with a number of conflicts greater than the average
    List<Webcam> ignoredCamerasForBounds = Lists.newArrayList();

    for (int i = 0; i < webcamCount; ++i) {
        if (conflictCount[i] > averageConflictCount) {
            ignoredCamerasForBounds.add(webcams.get(i));
        }
    }

    return ignoredCamerasForBounds;
}
于 2013-10-01T19:56:41.110 回答
0
Display display = getWindowManager().getDefaultDisplay(); 
        Point size = new Point();
        display.getSize(size);
        int ancho = size.x;
        int alto =size.y;
List<LatLng> copiedPoints = new ArrayList<LatLng>();
        copiedPoints.add(origin);
        copiedPoints.add(dest);

centerIncidentRouteOnMap(copiedPoints, ancho, alto);

……

public void centerIncidentRouteOnMap(List<LatLng> copiedPoints, int ancho, int alto) {
    double minLat = Integer.MAX_VALUE;
    double maxLat = Integer.MIN_VALUE;
    double minLon = Integer.MAX_VALUE;
    double maxLon = Integer.MIN_VALUE;
    for (LatLng point : copiedPoints) {
        maxLat = Math.max(point.latitude, maxLat);
        minLat = Math.min(point.latitude, minLat);
        maxLon = Math.max(point.longitude, maxLon);
        minLon = Math.min(point.longitude, minLon);
    }
    final LatLngBounds bounds = new LatLngBounds.Builder().include(new LatLng(maxLat, maxLon)).include(new LatLng(minLat, minLon)).build();
    map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds,ancho, alto, 50));
}
于 2015-04-28T14:56:37.370 回答