web-dev-qa-db-fra.com

Définir un niveau de zoom maximal sur le générateur LatLngBounds

Je n'ai pas trouvé de réponse dans ma recherche, il y a quelques réponses sur SO mais elles ne m'ont pas fonctionné.

J'ai 2 marqueurs sur la carte et j'utilise le constructeur LatLngBounds afin de laisser la caméra zoomer sur le niveau de zoom droit pour les inclure tous les deux. Tout fonctionne comme prévu, à part une chose, quand les 2 balises sont très proches l'une de l'autre, la carte est très très zoomée et bon, cela n'a aucun sens d'avoir ce niveau de zoom.

LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(firstMarker.getPosition());
builder.include(secondMarker.getPosition());
LatLngBounds bounds = builder.build();

CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, markerPadding);

Y at-il un moyen de forcer un certain niveau de zoom, après quoi la caméra ne zoomera pas? Cela éviterait que la carte soit trop agrandie/dézoomée. Fondamentalement, j'utilise 15.0f comme niveau de zoom. Si les points sont trop éloignés, je veux que le zoom s'adapte à la fois. Si les points se rapprochent, je ne veux pas que le niveau de zoom dépasse 15.0f.

23
Alin

J'ai un cas similaire, où je veux au moins une carte diagonale de 2 kilomètres . Par conséquent, je viens d'ajouter deux points supplémentaires au constructeur: le premier 1 km au nord-ouest du centre des limites d'origine et le second km au sud-est du centre. Si ceux-ci sont à l'intérieur des limites, ils ne changent rien. S'ils sont en dehors des limites d'origine, ils augmentent les limites pour atteindre une taille significative. 

Voici un exemple de code complet:

public LatLngBounds createBoundsWithMinDiagonal(MarkerOptions firstMarker, MarkerOptions secondMarker) {
    LatLngBounds.Builder builder = new LatLngBounds.Builder();
    builder.include(firstMarker.getPosition());
    builder.include(secondMarker.getPosition());

    LatLngBounds tmpBounds = builder.build();
    /** Add 2 points 1000m northEast and southWest of the center.
     * They increase the bounds only, if they are not already larger
     * than this. 
     * 1000m on the diagonal translates into about 709m to each direction. */
    LatLng center = tmpBounds.getCenter();
    LatLng northEast = move(center, 709, 709);
    LatLng southWest = move(center, -709, -709);
    builder.include(southWest);
    builder.include(northEast);
    return builder.build();     
}

private static final double EARTHRADIUS = 6366198;
/**
 * Create a new LatLng which lies toNorth meters north and toEast meters
 * east of startLL
 */
private static LatLng move(LatLng startLL, double toNorth, double toEast) {
    double lonDiff = meterToLongitude(toEast, startLL.latitude);
    double latDiff = meterToLatitude(toNorth);
    return new LatLng(startLL.latitude + latDiff, startLL.longitude
            + lonDiff);
}

private static double meterToLongitude(double meterToEast, double latitude) {
    double latArc = Math.toRadians(latitude);
    double radius = Math.cos(latArc) * EARTHRADIUS;
    double rad = meterToEast / radius;
    return Math.toDegrees(rad);
}


private static double meterToLatitude(double meterToNorth) {
    double rad = meterToNorth / EARTHRADIUS;
    return Math.toDegrees(rad);
}
43
user2808624

J'ai implémenté cette solution en fonction de la réponse de user2808624, mais en utilisant le SphericalUtil à partir de la bibliothèque Android Maps Utility pour effectuer les calculs.

final double HEADING_NORTH_EAST = 45;
final double HEADING_SOUTH_WEST = 215;
LatLng center = tmpBounds.getCenter();
LatLng norhtEast = SphericalUtil.computeOffset(center, 709,HEADING_NORTH_EAST);
LatLng southWest = SphericalUtil.computeOffset(center, 709,HEADING_SOUTH_WEST );
8
dvdrlee

Arriver en retard mais peut-être que quelqu'un a le même problème que moi: j'ai reçu des bornes d'un lieu et non d'un LatLngBounds.Builder:

J'ai utilisé Location.distanceBetween (...) pour déterminer si les limites étaient trop petites, puis utiliser un niveau de zoom minimal avec le centre des limites:

if (areBoundsTooSmall(bounds, 300)) {
    mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(bounds.getCenter(), 17));
} else {
    mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 20));
}

La méthode de vérification est:

private boolean areBoundsTooSmall(LatLngBounds bounds, int minDistanceInMeter) {
    float[] result = new float[1];
    Location.distanceBetween(bounds.southwest.latitude, bounds.southwest.longitude, bounds.northeast.latitude, bounds.northeast.longitude, result);
    return result[0] < minDistanceInMeter;
}

J'ai utilisé le niveau de zoom minimum 17 et le rembourrage 20 pour les limites trop petites. Trop petit est défini ici par une distance minimale en mètres 300. Vous pouvez ajuster les chiffres à votre guise.

3
Björn Kechel

Voici une version beaucoup plus courte basée sur user2808624 's answer

        LatLngBounds bounds = builder.build();
        LatLng center = bounds.getCenter();
        builder.include(new LatLng(center.latitude-0.001f,center.longitude-0.001f));
        builder.include(new LatLng(center.latitude+0.001f,center.longitude+0.001f));
        bounds = builder.build();

C'est un peu bâclé, mais vous pouvez utiliser 0,001 pour zoomer autant qu'un bloc de la ville, 0,01 pour pas moins qu'une vue de la ville. Le seul avantage est ses 4 lignes de code supplémentaires.

2
Marc

Google a ajouté un api pour limiter les niveaux de zoom max/min.

GoogleMap.setMaxZoomPreference()
GoogleMap.setMinZoomPreference()
2
malinjir

Avez-vous envisagé de créer un fragment de carte masqué et de l'utiliser pour déterminer votre zoom/limites? Ce n'est évidemment pas le meilleur calcul, mais c'est probablement la solution la plus simple et la plus précise. Par exemple, il est complexe de créer une solution mathématique qui fonctionne près des pôles et sur une longitude de 0 degré (si vous vous en souciez). Si vous utilisez une carte, tout est déjà intégré. Vous pouvez aussi évidemment utiliser cette solution sur votre carte existante, mais l’utilisateur verra un rebond. 

Voici comment vous le feriez:

  1. Allez aux limites que vous avez définies ci-dessus
  2. Obtenez le zoom en utilisant map.getCameraPosition (). Zoom. 
  3. Si zoom> 15, effectuez un zoom arrière sur 15 avec CameraUpdateFactory.zoomTo (15) 
1
GLee

C'est simple:

LatLngBounds.Builder latlngBuilder = new LatLngBounds.Builder();

LatLng sydney1 = new LatLng(57.149651, -2.099075);

LatLng sydney2 = new LatLng(51.621441, -3.943646);

latlngBuilder.include(sydney1);
latlngBuilder.include(sydney2);

googlemap.animateCamera(CameraUpdateFactory.newLatLngBounds(latlngBuilder.build(), 100));
1
user2150941

La solution rapide est: 

gMap.setOnMapLoadedCallback(this);
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
gMap.setMaxZoomPreference(10);
gMap.animateCamera(cu);


@Override
public void onMapLoaded() {
    gMap.resetMinMaxZoomPreference();
}

Attention, le zoom peut être interrompu jusqu'à ce que la carte soit complètement rechargée. Mais comme solution rapide cela fonctionne. 

1
Paul Brewczynski

Suite aux réponses de user2808624 et de dvdrlee, j’ai écrit une extension en kotlin:

fun LatLngBounds.Builder.createBoundsWithZoomMaintained(bounds: LatLngBounds) : LatLngBounds  {
    val HEADING_NORTH_EAST = 45.0   //NorthEast angle
    val HEADING_SOUTH_WEST = 215.0  //SouthWest angle
    val center = bounds.center
    val northEast = SphericalUtil.computeOffset(center, 709.0, HEADING_NORTH_EAST)  //1000 metres on the diagonal translates to 709 metres on either side.
    val southWest = SphericalUtil.computeOffset(center, 709.0, HEADING_SOUTH_WEST)
    this.include(northEast).include(southWest)
    return this.build()
}

Cela se trouve généralement dans votre fichier Utils ou Extensions, et vous pouvez ensuite l'utiliser de n'importe où simplement comme ceci:

var bounds = builder.build()  //To include all your existing points.
bounds = builder.createBoundsWithZoomMaintained(bounds)  //Updated bounds.
mMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 10)) 
0
Supriya

Il n’existe aucun moyen de limiter les niveaux de zoom à partir de la version 4.0.30, mais vous pouvez suivre ce problème .

Le moyen le plus simple serait de forcer le niveau de zoom comme sur cette vidéo: http://www.youtube.com/watch?v=-nCZ37HdheY
En gros, ils appellent animateCamera lorsque certains niveaux de zoom sont atteints.

Cela aurait l'air un peu bizarre, car vous avez alors 2 animations qui ne sont pas lancées par l'utilisateur.

La difficulté serait de faire le calcul vous-même. Essayez de travailler avec CameraUpdateFactory.newLatLngZoom avec LatLng comme centre entre ces points et votre zoom maximal lorsque vous détectez des points proches les uns des autres.

0
MaciejGórski