マップ上に2つ以上のポイントを表示するために最適なズームレベルを計算する方法


11

静的マップ上にいくつかのマーカーを表示し、Googleマップのように最適なズームレベルを計算したいと考えています。バウンディング四角形とマップの中心点はすでに計算されていますが、バウンディング四角形全体を表示するための正しいズームレベルを計算するのに苦労しています。誰かが私たちを正しい方向に向けることができますか?


それほど洗練されていませんが、MBRに120%を掛けて拡大してみませんか?それ以外は、「最適」の定義に依存しますね。
ThomM、2012

ThomMのアイデアに+1。これはまさにArcGISが行うことです。
Ragi Yaser Burhum

1
申し訳ありませんが、このMBRは何ですか?
ロドリゴ

回答:


4

ズームレベルを取得するには、マップのピクセル寸法を知っている必要があります。また、球形のメルカトル座標で計算を行う必要があります。

  1. 緯度、経度を球形メルカトルx、yに変換します。
  2. 球形メルカトルの2点間の距離を取得します。
  3. 赤道の長さは約40mメートルで、タイルの幅は256ピクセルです。そのため、特定のズームレベルでのそのマップのピクセル長は、約256 *距離/ 40000000 * 2 ^ zoomです。マップのピクセル寸法に対して距離が長すぎるまで、zoom = 0、zoom = 1、zoom = 2を試してください。

1
私があなたが実際に求めていることをリモートで理解できたといいのですが。= \
Michal Migurski

この回答を探しているときにこの質問を見つけました、ありがとう。
BenjaminGolder

@MichalMigurski、球形メルカトルの2点間の距離を計算する方法を説明できますか?特にx座標...感謝しています。
otmezger 2013

4

これは、Maperitiveで使用するC#コードです

    public void ZoomToArea (Bounds2 mapArea, float paddingFactor)
    {
        double ry1 = Math.Log((Math.Sin(GeometryUtils.Deg2Rad(mapArea.MinY)) + 1) 
            / Math.Cos(GeometryUtils.Deg2Rad(mapArea.MinY)));
        double ry2 = Math.Log((Math.Sin(GeometryUtils.Deg2Rad(mapArea.MaxY)) + 1) 
            / Math.Cos(GeometryUtils.Deg2Rad(mapArea.MaxY)));
        double ryc = (ry1 + ry2) / 2;
        double centerY = GeometryUtils.Rad2Deg(Math.Atan(Math.Sinh(ryc)));

        double resolutionHorizontal = mapArea.DeltaX / Viewport.Width;

        double vy0 = Math.Log(Math.Tan(Math.PI*(0.25 + centerY/360)));
        double vy1 = Math.Log(Math.Tan(Math.PI*(0.25 + mapArea.MaxY/360)));
        double viewHeightHalf = Viewport.Height/2.0f;
        double zoomFactorPowered = viewHeightHalf
            / (40.7436654315252*(vy1 - vy0));
        double resolutionVertical = 360.0 / (zoomFactorPowered * 256);

        double resolution = Math.Max(resolutionHorizontal, resolutionVertical) 
            * paddingFactor;
        double zoom = Math.Log(360 / (resolution * 256), 2);
        double lon = mapArea.Center.X;
        double lat = centerY;

        CenterMapOnPoint(new PointD2(lon, lat), zoom);
    }
  • mapArea:long / lat座標の境界ボックス(x = long、y = lat)
  • paddingFactor:これは、ThomMが参照する「120%」の効果を得るために使用できます。値が1.2の場合、120%になります。

私の場合zoom、実数になる可能性があることに注意してください。Webマップの場合、整数のズーム値が必要なので、(int)Math.Floor(zoom)取得するようなものを使用する必要があります。

もちろん、このコードはWebメルカトル図法にのみ適用されます。


1
これをありがとう。CenterMapOnPointのコードは利用できますか?
mcintyre321 2014年

パーフェクト!これを使用して、OsmDroid SDKでBoundingBoxのズームを計算しました。これは機能します:)
Billda

これらのライブラリはどこにありますか?GeometryUtilsまたはBounds2アセンブリが見つかりません。maperitiveから何かをダウンロードする必要がありますか?そこにはアプリしか表示されません。
Dowlers

@Dowlers GeometryUtilsは、ここでは度をラジアンに変換するために使用されています。これは単純な数式です。Bounds2基本的には単なる長方形の構造です。このコードは、直接コピーして貼り付けることができるものではなく、疑似コードとして提供されました。
Igor Brejc

ああ、わかった。質問した後、Maperitiveアプリを調べて、必要な.dllを見つけたことを認めなければなりません。しかし、ライセンスの制限に気付いたので、別のルートに進みました。代わりにこの記事のコードを使用しました:rbrundritt.wordpress.com/2009/07/21/…– Dowlers
07/12

1

OpenLayersを使用している場合はMap.getZoomForExtent、マップの範囲全体に収まる最大ズームレベルを計算します。extentマップの投影にする必要があります。また、a fill_factorを使用して、マップの端にポイントが表示されないようにしmax_zoom、可能なズームを制限することもできます。

extent = extent.scale(1/fill_ratio);
var zoom = Math.min(map.getZoomForExtent(map_extent), max_zoom);
map.setCenter(extent.getCenterLonLat(), zoom);

これで問題は解決しませんでしたが、LeafletのfitBoundsメソッドを見つけることになりました。
SamuelDev
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.