15

私は、AndroidにiOSアプリを移植し、アプリケーションがマップ上にヒートマップオーバーレイを描画する必要がGoogle Maps Android API v2.を使用しています。TileProvider方法getTile - LATするxとyを翻訳する必要性/長い

これまでのところ、TileOverlayを使用し、カスタムTileProviderを実装するのが最善の方法です。メソッドgetTileでは、私のメソッドにx、y、およびzoomが与えられ、Tileの形式でビットマップを返す必要があります。ここまでは順調ですね。

は私が緯度/経度でそれぞれ、ビットマップ上に放射状のグラデーションを描画するために使用するヒートマップアイテムの配列を持っています。

  1. x、y、およびzoomで表されるタイルにヒートマップアイテムの緯度/経度が含まれているかどうかを確認するにはどうすればよいですか?
  2. ヒートマップアイテムの緯度/経度をビットマップのx/y座標に変換するにはどうすればよいですか?

はあなたの助けをありがとう!以下MaciejGórskiの答え、およびマルチンの実装に

UPDATE

おかげで私は私の質問答えの前半を得ることができたが、私はまだ第二の部分との助けを必要としています。明確にするために、指定された緯度/経度のタイルのx/y座標を返す関数が必要です。私はMaciejGrskiとmarcinの答えの計算を逆行させようとしました。

public static Point fromLatLng(LatLng latlng, int zoom){ 
    int noTiles = (1 << zoom); 
    double longitudeSpan = 360.0/noTiles; 
    double mercator = fromLatitude(latlng.latitude); 
    int y = ((int)(mercator/360 * noTiles)) + 180; 
    int x = (int)(latlng.longitude/longitudeSpan) + 180; 
    return new Point(x, y); 
} 

ご協力いただきましてありがとうございます。ズームレベル0で

+0

LatLng ZをXYに変換する方法を見つけましたか?私は部分的に動作する関数を見つけましたが、それは私に間違ったyを与えます。 –

答えて

8

、唯一つのタイル(X = 0、Y = 0)があります。次のズームレベルで、タイル数が4倍になります(xとyの2倍になります)。

これは、ズームレベルWの意味で、xは範囲<の値、1 < <Wの値である可能性があります。

ドキュメントから:タイルの

座標は左上(北西)マップの隅から測定されています。ズームレベルNでは、タイル座標のx値は0〜2N - 1の範囲にあり、西から東へ増加し、y値の範囲は0〜2N - 1であり、北から南へと増加します。

あなたは、単純な計算を使用してこれを達成することができます。経度について

これは簡単である:ここ

double longitudeMin = (((double) x)/(1 << zoom)) * 360 - 180; 
double longitudeMax = (((double) x + 1)/(1 << zoom)) * 360 - 180; 
longitudeMax = Double.longBitsToDouble(Double.doubleToLongBits(longitudeMax) - 1); // adjust 

xが最初< -180180に次いで、)< 0,1にスケーリングされます)。

最大値は調整されているため、次の領域と重複しません。これをスキップすることができます。緯度について

Googleマップは、メルカトル図法を使用するので、これは少し難しくなります。

最初に、範囲が< -180,180であったのと同様に、yをスケールします。値を逆にする必要があることに注意してください。

public static double toLatitude(double mercator) { 
    double radians = Math.atan(Math.exp(Math.toRadians(mercator))); 
    return Math.toDegrees(2 * radians) - 90; 
} 

latitudeMax = SphericalMercator.toLatitude(mercatorMax); 
latitudeMin = SphericalMercator.toLatitude(mercatorMin); 
latitudeMin = Double.longBitsToDouble(Double.doubleToLongBits(latitudeMin) + 1); 

これは、メモリから入力されたされ、そこにエラーがあるので、もし、どのような方法でテストされていなかった。

double mercatorMax = 180 - (((double) y)/(1 << zoom)) * 360; 
double mercatorMin = 180 - (((double) y + 1)/(1 << zoom)) * 360; 

は今、あなたは( SphericalMercator.javaから)メルカトル図法を行う魔法の機能を使用しますコメントしてください。私はそれを修正します。

+1

ホントイ!私はまったく気付いていない組み込み関数を期待していました。このコードが多ければTileOverlayはマップ上に描画する正しい方法ではないかもしれません。 Google Maps Javascript v3にはこれが組み込まれており、iOS MKOverlayViewも組み込まれています。 – azcoastal

+0

あなたの答えを見直す際に、私はあなたが「x」から経度と緯度を計算していることに気付きました。それはタイプミスですか?私はあなたが意味することを推測しています:double mercatorMax = 180 - (((ダブル)y)/(1 <<ズーム))* 360;また、緯度/経度をx/yに変換する同様の方法はありますか? – azcoastal

+0

@azcoastalはい。コピーペーストエラーです。私はそれを修正しました。緯度/経度の逆順の場合は、答えに入れたリンクの下にある「SphericalMercator.fromLatitude」から逆順にすべてを呼び出すだけです。実際にそれほど多くのコードはありません。 –

7

MaciejGórskiあなたは(あなたがしなければ、私はこの記事を削除します)メソッドを使用する準備に私はあなたのコードをコンパイルし気にしない場合:

private LatLngBounds boundsOfTile(int x, int y, int zoom) { 
    int noTiles = (1 << zoom); 
    double longitudeSpan = 360.0/noTiles; 
    double longitudeMin = -180.0 + x * longitudeSpan; 

    double mercatorMax = 180 - (((double) y)/noTiles) * 360; 
    double mercatorMin = 180 - (((double) y + 1)/noTiles) * 360; 
    double latitudeMax = toLatitude(mercatorMax); 
    double latitudeMin = toLatitude(mercatorMin); 

    LatLngBounds bounds = new LatLngBounds(new LatLng(latitudeMin, longitudeMin), new LatLng(latitudeMax, longitudeMin + longitudeSpan)); 
    return bounds; 
} 
+1

これは問題ありません。コードは正しい値を返しますか?私はまだそれをテストする機会がありません。 –

+0

私が知る限り:はいそれはあります:) – marcin

+0

@marcin、私はこれを後ろに持っているかもしれませんので、私が間違っていれば私を修正してください... LatLngBoundsのコンストラクタは最初のパラメータとして南西の角を探しているので、 1番目のパラメータとして 'new LatLng(latitudeMax、longitudeMin)'、2番目のパラメータに 'new LatLng(latitudeMin、longitudeMin + longitudeSpan)'を設定しますか?私はxとyがタイルのNWコーナーを表していると思っていました。 – azcoastal

9

これは私の仕事:

double n = Math.pow(2, zoom); 
double longitudeMin = x/n * 360 -180; 
double lat_rad = Math.atan(Math.sinh(Math.PI * (1 - 2 * y/n))); 
double latitudeMin = lat_rad * 180/Math.PI; 

double longitudeMax = (x + 1)/n * 360 -180; 
lat_rad = Math.atan(Math.sinh(Math.PI * (1 - 2 * (y + 1)/n))); 
double latitudeMax = lat_rad * 180/Math.PI; 

参考: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames

+1

リンクをご利用いただきありがとうございます。このリンクでは、ほとんどの一般的な言語で両方の操作を行うためのコードスニペットが提供されています。 –

+0

'^ 1'ありがとう、最後の2日から検索していました:) –

関連する問題