sos の 作業メモ

プログラミングや英会話学習、マイルや旅行、日常生活など。最近はWebFormなASP.NETのお守りがお仕事です。

日々の生活にhappyをプラスする|ハピタス Gポイント

その7: Tile Layers (Google Maps SDK for iOS)

前回の続き

Tile Layers

Tile Layerは指定されたズームレベルで、地図の最上面に画像を配置する機能である。様々なズームレベルに対応する十分なタイルを用意すれば、グーグルマップの補助用の地図データとして利用できる。

Introduction

TileLayers(Tile Overlayとも呼ばれる)は、基本の地図の上に重ね合わせての表示が可能。 これは、興味のある地点や交通情報等のデータを、ローカルのイメージとして追加する方法として優れた方法である。

kGMSTypeNoneと組み合わせると、Googleの提供する基本地図を置き換えたようにもみせられる。

通常のマップに対し、広範囲をカバーするイメージデータ群を追加したい場合はTile Layerを使えばよい。それに対し、ある地点に一枚のイメージを追加したい場合はGround Overlayがよい。

Tile Coordinates

Maps API はズームレベルに応じた正方形の順序付されたマップタイルに画像を分割し、スクロールやズーム等で新しいマップタイルが必要と判断されると、その場所のための新しいタイルを取得する。。

Googleのメルカトル図法においては、北西の角が0,0で、x軸は西から東、y軸は北から南を正として番号が振られる。例えばズームレベルが2の場合、世界は16分割され、x,yのそれぞれの番号で参照される。

各タイルは一辺が256ピクセルの正方形で、ズームレベル0で世界が一枚のタイルとなる。 ズームレベルをNとしたとき、世界は 2N x 2N のタイルに分割される。つまり、ズームレベル1なら 2x2=4分割、 ズームレベル2 なら 4x4=16分割。

Tile Layer用に画像を作成する場合は、ズームレベルに応じた256x256ピクセルの画像にする必要がある。

Add a Tile Layer

  1. GMSURLTileLayerオブジェクト、もしくは GMSTileLayerやGMSSyncTileLayerクラスを継承したクラスのインスタンスを生成
  2. 他のTileLayersとの調整が必要なら、zindexプロパティを設定する
  3. GMSTileLayerオブジェクトのmapプロパティに GMSMavViewオブジェクトを設定する

SDKではTile Layerのために、3つのクラスを用意している。それぞれのクラスでは、x,y,zoomに応じた適切なマップタイルの取得の仕方をで意義する必要がある。

設定可能なオプションは以下

The available options are:

  • GMSSyncTileLayerのサブクラスでは、requestTileForX:y:zoom:に対してUIImageのインスタンスを返す
  • GMSTileLayerのサブクラスでは,非同期にコールバックでタイルイメージを返す
  • GMSURLTileLayerを使えば、GMSTileURLConstructorで指定したURLから自動的にタイルを取得する。GMSURLTileLayerはfinalクラス(拡張できない)クラスである。

GMSSyncTileLayerやGMSTileLayerにおいて、nilの結果を返すことは、現在はその場所のタイルが無効であるが、将来的に利用可能になるかもしれないことを示す。一方で、kGMSTileLayerNoTileを返した場合、その場所にタイルが存在しないことを示す。

GMSURLTileLayerにおいて、GMSTileURLConstructorがnilを返すことは、その場所にタイルが存在しないことを示す。

Use GMSURLTileLayer to fetch tiles from URLs

GMSURLTileLayerの拡張は不要だが、GMSTileURLConstructorの実装は行わなければならない。 以下は高層ビルのフロアマップのコード例。

NSInteger floor = 1;

// x,yとズームレベルと階から目的のマップタイルを取得するためのブロック(結局はURLの対応が必要ですが)
GMSTileURLConstructor urls = ^(NSUInteger x, NSUInteger y, NSUInteger zoom) {
  NSString *url = [NSString stringWithFormat:@"http://www.example.com/floorplans/L%d_%d_%d_%d.png", floor, zoom, x, y];
  return [NSURL URLWithString:url];
}

// Create the GMSTileLayer
GMSURLTileLayer *layer = [GMSURLTileLayer tileLayerWithURLConstructor:urls];

// Display on the map at a specific zIndex
layer.zIndex = 100;
layer.map = mapView_;

Subclass GMSSyncTileLayer to serve tiles as a UIImage

GMSSyncTileLayer と GMSTileLayer は継承を前提と下仮想クラスである。 これらのクラスはUIImageを供給する為のものである。

以下は、GMSSyncTileLayerのサブクラスで、どのようにマップに独自のイメージを描画するかのサンプル。(xが偶数の列は"australia"のUIImageを表示する)

@interface TestTileLayer : GMSSyncTileLayer
@end

@implementation TestTileLayer
- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom {
  // On every odd tile, render an image.
  if (x % 2) {
    return [UIImage imageNamed:@"australia"];
  } else {
    return kGMSTileLayerNoTile;
  }
}
@end

オブジェクトを生成して、地図に表示するコードは以下

GMSTileLayer *layer = [[TestTileLayer alloc] init];
layer.map = mapView_;

High DPI Tiles for Retina devices

GMSSyncTileLayerやGMSURLTileLayerのtileSizeプロパティを512にセットすることで、高解像度イメージを使用することができる。

tileSizeプロパティは、イメージのピクセル数を示す。最前の結果を得る為に、tileSizeとdisplayのDPIは対応させること。 Retinaでバイスでは、tileSizeを512にして高解像度画像を表示、ノーマルデーバイスでは、tileSizeを256にしてデフォルト画像を表示するとよい。

Clear stale tiles

Tile Layerによって供給されたタイルが古くなった時は、clearTileCacheを呼び出す必要がある。 このメソッドが呼ばれたら、layer上の全てのタイルがリロードされることになる。

[layer clearTileCache];

というわけでTile Layersまで終わり。次からいよいよStreet Viewです。

次回へ続く