在LatLngBounds构建器上设置最大缩放级别

时间:2013-12-13 16:59:10

标签: android android-maps-v2 zooming

我的搜索中没有找到答案,有几个答案,但它们对我不起作用。

我在地图上有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。

10 个答案:

答案 0 :(得分:44)

我有一个类似的情况,我想要至少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);
}

答案 1 :(得分:10)

我根据user2808624的答案实施了此解决方案,但使用SphericalUtil中的Android Maps 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 );

答案 2 :(得分:3)

迟到但也许某人有同样的问题:我收到了一个地方的界限,而不是来自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米。您可以根据需要调整数字。

答案 3 :(得分:2)

Google添加了一个用于限制最大/最小缩放级别的API。

GoogleMap.setMaxZoomPreference()
GoogleMap.setMinZoomPreference()

答案 4 :(得分:2)

这是一个基于user2808624answer的更短的版本。

        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行额外代码。

答案 5 :(得分:1)

您是否考虑制作隐藏的地图片段,并使用它来确定缩放/界限?它显然不是最好的计算,但它可能是最简单/最准确的解决方案。例如,制作一个在极点和0度经度附近工作的数学解决方案很复杂(如果你愿意的话)。如果您使用地图,那就已经内置了。您显然也可以在现有地图上使用此解决方案,但用户会看到反弹。

以下是你的表现:

  1. 转到上面定义的界限
  2. 使用map.getCameraPosition()进行缩放。缩放。
  3. 如果缩放&gt; 15使用CameraUpdateFactory.zoomTo(15)
  4. 缩小到15

答案 6 :(得分:1)

快速修复:

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


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

请注意,在完全重新加载地图之前,它可以暂停缩放。但作为一个快速修复它的工作原理。

答案 7 :(得分:1)

这很简单:

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

答案 8 :(得分:1)

根据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)) 

答案 9 :(得分:0)

自4.0.30起无法限制缩放级别,但您可以跟踪this issue

简单的方法是像这个视频一样强制缩放级别:http://www.youtube.com/watch?v=-nCZ37HdheY
基本上,当达到某个缩放级别时,他们会调用animateCamera

这看起来有点奇怪,因为你有2个不是由用户启动的动画。

艰难的方法就是自己做数学。尝试使用CameraUpdateFactory.newLatLngZoom LatLng作为这些点之间的中心,并在检测到点彼此接近时进行最大缩放。