Android でカスタム レイヤを作成する方法

ArcGIS Runtime SDK for Android では各種レイヤのクラスを拡張してカスタム レイヤを作成できます。ここでは TiledServiceLayer クラスを使って独自のタイル サービス レイヤを作成する方法をご紹介します。この方法を使うと ArcGIS 以外のマップ タイルにアクセスして ArcGIS のレイヤと簡単に重ね合わせることができます。

Tiledservicelayer1


上のクラス関係を示す図からもわかるように TiledServiceLayer は抽象クラス(abstract class)で、これを継承したクラスとして ArcGISTiledMapServiceLayer や BingMapsLayer、OpenStreetMapLayer があります。この TiledServiceLayer を継承する独自のタイル サービス レイヤを作成すると、例えば「http://some.domain.com/{level}/{col}/{row}.png」のような形式のマップ タイルを ArcGIS for Server や ArcGIS Online のレイヤと同じように Android のネイティブ アプリで使えるようになります。

TiledServiceLayer を拡張する場合のポイントは、各タイル画像を取得する getTile メソッドの実装と、表示範囲や投影法、各縮尺レベルの解像度や縮尺などをコンストラクタに適切に設定することにあります。

■getTile メソッドの実装
まず TiledServiceLayer クラスの getTile メソッドをオーバーライドします。
このメソッドは、縮尺レベル(level)とXY座標(col および row)に対応する byte 配列を返します。

以下のコードは各タイル画像を URL で取得する場合の実装例になります。 

——————————————————————————————–
public class SampleCustomLayer extends TiledServiceLayer {
  @Override
  protected byte[] getTile(int level, int col, int row) throws Exception {
    byte[] tile = null;
    URL url = null;
    InputStream is;

    try{
      url = new URL(“http://some.domain.com/” + level + “/” + col + “/” + row + “.png”);
      is = url.openStream();
      Bitmap bm = BitmapFactory.decodeStream(is);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
      tile = baos.toByteArray();
    }catch(FileNotFoundException fnfe){
    }catch(Exception e){
      e.printStackTrace();
    }
    return tile;
  }
}

——————————————————————————————–

■コンストラクタ
タイルを読み込む前にタイル レイヤの仕様をコンストラクタで設定しておきます。必要となる主な情報は以下の通りです。
・投影法
・タイルの原点
・縮尺レベルの数
・縮尺レベルごとの縮尺と解像度
・レイヤの範囲(Extent) これらを実装すると以下のようになります。 

——————————————————————————————–
  public SampleCustomLayer(boolean initLayer) {
    super(initLayer);

    //表示範囲(緯度経度から Web メルカトルに変換)
    Envelope envWGS = new Envelope(100.0, 0.0, 180.0, 60.0);
    Envelope envWeb = (Envelope) GeometryEngine.project(envWGS, SpatialReference.create(4326), SpatialReference.create(102100));

    int mLevels = 18;

    //縮尺レベルごとの解像度と縮尺
    double[] resolution = new double[mLevels];
    double[] scale = new double[mLevels];
    for (int i = 0; i < mLevels; i++) {
      resolution[i] = 156543.03392800014 / Math.pow(2, i);
      scale[i] = 591657527.591555 / Math.pow(2, i);
    }

    //タイル定義(原点の指定)
    TileInfo ti = new TileInfo(new Point(-20037508.342787, 20037508.342787), scale, resolution, mLevels, 96, 256, 256);
   
    this.setTileInfo(ti);
    this.setFullExtent(envWeb);
    this.setDefaultSpatialReference(SpatialReference.create(102100));
    this.setInitialExtent(envWeb);

    this.initLayer();
  }
——————————————————————————————–

■マップへの追加
カスタム レイヤが作成できれば、あとは MapView インスタンスに addLayer メソッドを使用してレイヤを追加するだけです。 

——————————————————————————————-
TiledServiceLayer layer = new SampleCustomLayer(true);
mapView.addLayer(layer);
——————————————————————————————–

実際に作成してみると比較的簡単にカスタム レイヤを実装可能なことがおわかりいただけると思います。 この方法を使って例えば、地理院地図を背景図としたアプリを開発できます。 

Tiledservicelayer2

[注意事項]
今回ご紹介したコードはカスタム レイヤを実装する際の参考となるように、拡張クラスの実装例をご紹介しているものでありサポート対象外となります。従って、本記事に記載している実装方法に関するご質問はお受けできません。
また、本記事のコードを使用して生じたいかなる障害についても、弊社では責任を負いかねますことを予めご了承願います。

■関連リンク
ESRIジャパン Web サイト
・ArcGIS Runtime SDK for Android: http://www.esrij.com/products/arcgis/developer/arcgis-runtime-sdks/arcgis-runtime-sdk-for-android/
Esri 社(米国)Web サイト
・ArcGIS for Developers:https://developers.arcgis.com/android/