web-dev-qa-db-ja.com

LatLngBounds Builderで最大ズームレベルを設定します

私の検索で答えが見つかりませんでした。SOにいくつかの答えがありますが、それらは私にはうまくいきませんでした。

マップ上に2つのマーカーがあり、カメラを適切なズームレベルにズームして両方を含めるためにLatLngBounds Builderを使用しています。 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を超えないようにします。

25
Alin

同様のケースがあり、少なくとも2キロメートルの対角線マップが必要です。したがって、ビルダーに2つの追加ポイントを追加するだけです。最初の境界の中心から北西に最初の1 km、中心から南東に2番目の地点です。これらが境界内にある場合、何も変更されません。元の境界の外側にある場合は、境界を意味のあるサイズに増やします。

完全なコード例を次に示します。

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

User2808624の回答に従ってこのソリューションを実装しましたが、計算を行うために Android Maps Utility LibrarySphericalUtil を使用しました。

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

ser2808624answer に基づいたはるかに短いバージョンを次に示します。

        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行だけ追加されることです。

4
Marc

遅くなりますが、誰かが私と同じ問題を抱えている可能性があります:LatLngBounds.Builderではなく、Placeから境界を受け取りました:

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
Björn Kechel

Googleは、最大/最小ズームレベルを制限するためのAPIを追加しました。

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

簡単です:

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

非表示のマップフラグメントを作成し、それを使用してズーム/境界を決定することを検討しましたか?これは明らかに計算上では最良ではありませんが、おそらく最も簡単で最も正確なソリューションです。たとえば、極の近くで経度0度で動作する数学的なソリューションを作成するのは複雑です(気になる場合)。マップを使用する場合、それはすでにすべて組み込まれています。既存のマップでこのソリューションを使用することもできますが、ユーザーにはバウンスが表示されます。

方法は次のとおりです。

  1. 上記で定義したように境界に移動します
  2. Map.getCameraPosition()。zoomを使用してズームを取得します。
  3. Zoom> 15の場合、CameraUpdateFactory.zoomTo(15)を使用して15にズームアウトします。
1
GLee

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)) 
1
Supriya

クイックフィックスは:

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


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

マップが完全にリロードされるまでズームを停止できることに注意してください。しかし、簡単な修正として機能します。

1

4.0.30の時点でズームレベルを制限する方法はありませんが、 この問題 を追跡できます。

簡単な方法は、このビデオのようにズームレベルを強制することです。 http://www.youtube.com/watch?v=-nCZ37HdheY
基本的に、特定のズームレベルに到達すると、animateCameraを呼び出します。

ユーザーが開始していない2つのアニメーションがあるため、これは少し奇妙に見えます。

難しい方法は、自分で計算することです。 CameraUpdateFactory.newLatLngZoomは、これらのポイント間の中心としてLatLngを使用し、ポイントが互いに近接していることを検出した場合の最大ズーム。

0
MaciejGórski