Android Maps v2 - animate camera to include most markers

你离开我真会死。 提交于 2019-11-28 12:35:37

Put all the LatLng of the markers in the list and pass them to this method and at the last line in the newLatLngBounds(bounds, 50)) the 50 represent the padding between the map edge and the most outer marker in each side

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

Spotted an error in my previous code and decided to sit down and rewrite it.

I have done something similar before where I had ~4500 markers and wanted to select those within a certain distance of a specific location. Took that code and generalized it to be used with any kind of Markers.

The code that I will post below contains two methods that you can use:

selectLowDistanceMarkers

Measures distance between each and every marker and selects only those that does not have a long distance to any of the other markers. This requires a O(n+n^2) runtime due to the comparison between every marker and an examination afterwards.

getSurroundingMarkers

If you already know a postition that you would like to zoom in to, then this method does the same as above. This method is way less CPU heavy as it only has to do a O(n) run through all the markers and compare them to the given position.

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

Again, use the well known LatLngBounds to determine how much you need to zoom after using one of the filtering algorithms above.

Based on some ideas from cYrixmorten, I have simplified the problem because I know the map can accomodate at least 4000km of surface. So here is the function to build the list of ignored webcams (then I simply ignore that webcam for the camera bounds computation but still add the marker so that it is on the map if the user moves).

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;
}
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));
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!