Androidで与えられた中心とスケールで境界ボックスを計算していますか?


8

これらの条件を考えると:

  • のようなスケール 1:50000
  • ビューポートの中心は 100°E, 20°N
  • ビューポートのサイズは 400x600

ビューポートの境界ボックスを計算するにはどうすればよいですか?


マップの地理座標系はEPSG:4490です。

それらをメルカトルや緯度 _ 経度 _投影などの別の投影法で表示したいと思います(おそらくこれはいわゆる非投影です)。

ビューポートのサイズはピクセル単位です。


マップはどの投影法ですか?Webメルカトル?または、投影されていない地図を緯度/経度で表示しますか?そして、ビューポートのサイズは、ピクセル単位ですか?スケールはピールですか?この機能を持つ可能性のあるマッピングフレームワーク/ライブラリを使用していますか?
atlefren 2013年

これを試すために使用しているGISソフトウェアとバージョンは何ですか?
PolyGeo

@atlefren:投稿を更新します。
giser 2013年

@PolyGeo:なし。Androidで地図データを表示しようとしました。また、ライブラリは見つかりませんでした。
giser 2013年

1
Android、Google Maps APIを使用していますか、それとも単純に画像を表示していますか?また、マップが大きく歪んで見えるため、投影されていない座標系を使用してマップを表示しないことをお勧めします。
atlefren 2013年

回答:


9

さて、いくつかの初期の問題が解決されたので、タスクは比較的簡単です。

縮尺は、f.ex 1:50000として表され、マップ上の1つの単位が実世界の50.000単位に対応することを意味します。

1:50000の縮尺で印刷された紙の地図の場合、これは、地図上の1メートルが現実世界の50.000メートルに対応すること、または簡単にするために、地図上の1 cmが現実世界の50メートルに対応することを意味します。ここまでは順調ですね。

コンピューター(または電話スクリーン)がショーに入るとき、それははるかに困難です。スクリーン上の測定単位はピクセルであり、センチメートルに直接マッピングされません。OpenLayersは(または少なくともその場所で)「1インチあたりのドット数」を使用しており、1インチは72ピクセルに相当すると想定されています(これは72 dpi画面では理にかなっていますが、Retinaディスプレイでは間違っています。しかし、今のところ、 72 dpi(これはほとんどのマッピングライブラリが行うことです(私は、修正を歓迎します))。

OpenLayersにはOpenLayers.Util.getResolutionFromScale関数があります(ソースを参照)。

OpenLayers.Util.getResolutionFromScale = function (scale, units) {
    var resolution;
    if (scale) {
        if (units == null) {
            units = "degrees";
        }
        var normScale = OpenLayers.Util.normalizeScale(scale);
        resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
                                        * OpenLayers.DOTS_PER_INCH);
    }
    return resolution;
};
  • units = "degrees"(EPSG:4490は、私が収集したものです)を使用すると、inch_per unit = 4374754(OpenLayers.INCHES_PER_UNIT ["degrees"])が得られます。

  • 1:50000のスケール(これは1/50000 = 0.00002に対応します)(これはpenLayers.Util.normalizeScaleが計算するものです)は、normScale = 0.00002を与えます

  • OpenLayers.DOTS_PER_INCH = 72

次に、次のように解像度を計算できます

1 / (0.00002 * 4374754 * 72) = 0.00015873908440210453

中心点(lon = 100、lat = 30)、ビューポートのピクセルサイズ(w = 400、h = 600)、およびOpenLayers.MapのcalculateBounds関数を使用できる解像度(sourceを参照)がわかっている場合:

calculateBounds: function(center, resolution) {

        var extent = null;

        if (center == null) {
            center = this.getCachedCenter();
        }
        if (resolution == null) {
            resolution = this.getResolution();
        }

        if ((center != null) && (resolution != null)) {
            var halfWDeg = (this.size.w * resolution) / 2;
            var halfHDeg = (this.size.h * resolution) / 2;

            extent = new OpenLayers.Bounds(center.lon - halfWDeg,
                                           center.lat - halfHDeg,
                                           center.lon + halfWDeg,
                                           center.lat + halfHDeg);
        }

        return extent;
    },

これを次のように削減できます。

function calculateBounds(center, resolution, size) {       
    var halfWDeg = (size.w * resolution) / 2;
    var halfHDeg = (size.h * resolution) / 2;
    return {
        "left": center.lon - halfWDeg,
        "bottom": center.lat - halfHDeg,
        "right": center.lon + halfWDeg,
        "top": center.lat + halfHDeg
    };
}

これを私たちの値で呼び出すと、次のようになります。

calculateBounds({"lon": 100, "lat": 30}, 0.00015873908440210453, {"w": 400, "h":600});
{ 
    left: 99.96825218311957, 
    bottom: 29.95237827467937,
    right: 100.03174781688043,
    top: 30.04762172532063
}

次に、これらすべてを、与えられたスケール分母を使用して、度数に対して機能する関数に組み合わせることができます。

function calculateBounds(center, scaleDenominator, size) {       
    var resolution = 1 / ((1 / scaleDenominator) * 4374754 * 72)
    var halfWDeg = (size.w * resolution) / 2;
    var halfHDeg = (size.h * resolution) / 2;
    return {
        "left": center.lon - halfWDeg,
        "bottom": center.lat - halfHDeg,
        "right": center.lon + halfWDeg,
        "top": center.lat + halfHDeg
    };
}

素晴らしい答え。実際、ここで重要なのはdpi価値です。だよね?
giser 2013年

ああ、投影はどうですか?上記のコードは、学位を直接計算するために使用されているようです。
2013年

はい、そうです。ユーザーが紙の地図と同じ方法でマップを使用することを期待していない限り(つまり、地図上で測定)、任意の値を使用できます(ほとんどのマッピングライブラリは72または96を使用していると思います)
atlefren

投影について知っておく必要があるのはその単位だけです。OpenLayersはUtils.jsのOpenLayers.INCHES_PER_UNIT [units]配列を使用します。計算解像度に39.37の代わり4374754を意味ユニット、などのWebメルカトルを使用メートル
atlefren

@atlerfren:こんにちは、あなたはopenlayersの専門家のようです。これに関連するいくつかの問題に遭遇しました。この投稿をチェックする時間を割いてください。gis.stackexchange.com/q/61256/12681
giser
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.