Подтвердить что ты не робот

Установите максимальный уровень масштабирования в построителе LatLngBounds

Я не нашел ответа в своем поиске, есть несколько ответов на SO, но они не сработали для меня.

У меня есть 2 маркера на карте, и я использую построитель LatLngBounds, чтобы позволить камере приближаться к правильному уровню масштабирования, чтобы включить их обоих. Все работает так, как ожидалось, в стороне от одной вещи, когда 2 маркера действительно близки друг к другу, карта очень сильно масштабируется и хорошо, нет никакого смысла, чтобы этот уровень масштабирования.

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

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

Есть ли способ заставить определенный уровень масштабирования, после чего камера не будет масштабироваться? Это позволит избежать слишком большого увеличения карты. В основном я использую 15.0f как уровень масштабирования. Если точки слишком далеко, я хочу, чтобы зум соответствовал им. Если точки приближаются, я не хочу, чтобы уровень масштабирования превышал 15.0f.

4b9b3361

Ответ 1

У меня есть аналогичный случай, где я хочу, по крайней мере, диагональ карты в 2 километра. Поэтому я просто добавляю к строителю два дополнительных пункта: первый 1 км к северо-западу от центра исходных границ и второй 1 км к юго-востоку от центра. Если они находятся внутри границ, они ничего не меняют. Если они находятся за пределами исходных границ, они увеличивают границы до значимого размера.

Вот пример полного кода:

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

Ответ 2

Я реализовал это решение в соответствии с ответом user2808624, но используя SphericalUtil из Android Utility Library для выполнения вычислений.

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

Ответ 3

Поздно, но, возможно, у кого-то есть такая же проблема: я получил ограничения от Place, а не из LatLngBounds.Builder:

Я использовал Location.distanceBetween(...), чтобы узнать, были ли границы слишком маленькими, а затем используйте минимальный уровень масштабирования с центром границ:

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

Метод проверки:

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

Я использовал минимальный уровень масштабирования 17 и дополнение 20 для слишком малых границ, слишком мал, здесь здесь останавливается минимальное расстояние в метре 300. Вы можете отрегулировать числа по мере необходимости.

Ответ 4

Google добавил api для ограничения уровней масштабирования max/min.

GoogleMap.setMaxZoomPreference()
GoogleMap.setMinZoomPreference()

Ответ 5

Вот более короткая версия, основанная на user2808624 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();

Его немного неряшливо, но вы можете использовать 0.001 для увеличения не менее городского блока, 0,01 за не менее, чем город. Единственным преимуществом является только 4 дополнительных строки кода.

Ответ 6

Считаете ли вы, что фрагмент карты скрыт, и используя это для определения ваших зум/границ? Это, очевидно, не самое лучшее вычислительное, но это, вероятно, самое простое/наиболее точное решение. Например, сложно сделать математическое решение, которое работает вблизи полюсов и через 0 градусов долготы (если вам интересно). Если вы используете карту, то все уже встроено. Вы также можете использовать это решение на своей существующей карте, но пользователь увидит отскок.

Вот как вы это сделаете:

  • Перейдите к границам, определенным выше.
  • Получить масштаб с помощью map.getCameraPosition(). zoom.
  • Если масштаб > 15 уменьшит масштаб до 15, используя CameraUpdateFactory.zoomTo(15)

Ответ 7

Невозможно ограничить уровни масштабирования с 4.0.30, но вы можете отслеживать эту проблему.

Простым способом было бы повысить уровень масштабирования, как на этом видео: http://www.youtube.com/watch?v=-nCZ37HdheY
В основном они вызывают animateCamera, когда достигается определенный уровень масштабирования.

Это выглядело бы немного странно, потому что у вас тогда есть 2 анимации, которые не запускаются пользователем.

Трудный путь будет делать сама математика. Попытайтесь работать с CameraUpdateFactory.newLatLngZoom с LatLng как центром между этими точками и максимальным увеличением при обнаружении точек близко друг к другу.

Ответ 8

Быстрое исправление:

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


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

Остерегайтесь того, что он может остановить масштабирование, пока карта не будет полностью перезагружена. Но в качестве быстрого решения это работает.

Ответ 9

Это просто:

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

Ответ 10

Следуя ответам user2808624 и dvdrlee, я написал расширение в 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()
}

Обычно это будет в вашем файле Utils или Extensions, а затем вы можете использовать его из любого места, просто так:

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