UP | HOME

高度なトピック

ここでは、maprayJSライブラリを利用した開発の高度なトピックについて説明します。

1. データプロバイダの作成

Maprayエンジンはレンダリング時にデータプロバイダから地表の形状(DEM)や地図画像データを取得します。

ライブラリでは StandardDemProviderStandardImageProvider を用意していますが、これらのクラスの機能だけでは対応できないとき、コンテンツ開発者が独自のデータプロバイダを実装できます。

1つのデータプロバイダは固定サイズのタイルを単位にデータを提供します。たとえば典型的な地図画像プロバイダは256×256サイズの画像タイルを提供します。

提供される個々のタイルは Z/X/Y 座標で区別されます。Maprayエンジンはデータプロバイダにタイルを要求するときに Z/X/Y 座標を指定します。

1.1. タイルの座標

Z/X/Y 座標の Z はズームレベルを表し、 Z > 0 となる整数です。 X はそのズームレベル上のタイルの水平方向の位置、 Y は垂直方向の位置を表し、 0 <= X, Y <= pow(2,Z) - 1 となる整数です。

北緯および南緯約85.0511度以上を除外した、正方形のメルカトル世界地図上に Z/X/Y 座標が定義されます。

Z 座標が z のタイルは、この正方形地図を縦横均等に pow(2,z) 分割された領域に対応します。

X 座標は一番左側のタイルが 0 で、一番右側のタイルが pow(2,z) - 1 になり、 Y 座標は一番上側のタイルの 0 で、一番下側のタイルが pow(2,z) - 1 になります。

数式で表すと、経度 λ, 緯度 φZ/X/Y 座標の関係は次のようになります。ここで gd はグーデルマン関数を、 c1, c2 は任意の整数を表します。

tile.png

1.2. DEMデータプロバイダの実装

独自のDEMデータプロバイダを定義するためには DemProvider のサブクラスを実装します。

このときサブクラスでは次のメソッドをオーバライドします。

  • requestTile(z, x, y, callback)
  • cancelRequest(id)
  • getResolutionPower()

requestTile() はMaprayエンジンがタイルをリクエストするときに呼び出すメソッドです。このメソッドの z , x , y パラメータはタイルの座標です。 callback パラメータは、データを取得したとき、データの取得に失敗したときに、プロバイダが呼び出す必要がある関数です。 callback は即時に呼び出さずに非同期に呼び出さなければなりません。

cancelRequest() はMaprayエンジンがタイルのリクエストを取り消すときに呼び出します。このメソッドの id パラメータは requestTile() が返したオブジェクトで、プロバイダはそれに対応するリクエストを取り消す必要があります。ただし取り消す手段がない場合は、何もする必要はありません。

getResolutionPower() が返す整数を ρ とすると、DEMデータの解像度が pow(2, ρ) であることを示します。 デフォルトの実装では8を返すので、DEMデータの解像度が256のときはこのメソッドをオーバライドする必要はありません。

以下は単純なDEMデータプロバイダ MyDemProvider の実装例です。

class MyDemProvider extends mapray.DemProvider {
    constructor()
    {
        super();
        // 初期化
        ...
    }

    requestTile( z, x, y, callback )  // override
    {
        var req = new XMLHttpRequest();
        req.open( 'GET', this._makeURL( z, x, y ), true );
        req.responseType = 'arraybuffer';
        req.onloadend = function ( event ) {
            var status = req.status;
            if ( req.response && (status >= 200 && status < 300 || status == 304) ) {
                callback( req.response );  // データ取得に成功 (ArrayBuffer インスタンスを返す)
            }
            else {
                callback( null );  // データ取得に失敗、または取り消し
            }
        };
        req.send();
        return req;  // 要求 ID
    }

    cancelRequest( id )  // override
    {
        id.abort();  // XMLHttpRequest#abort() でリクエスト取り消し
    }

    _makeURL( z, x, y )  // タイル z/x/y の DEM データの URL を返す
    {
        return 'http://localhost/dem/' + z + '/' + x + '/' + y + '.bin';
    }
}

1.3. 地図画像プロバイダの実装

独自の地図画像プロバイダを定義するためには ImageProvider のサブクラスを実装します。

このときサブクラスでは次のメソッドをオーバライドします。

  • requestTile(z, x, y, callback)
  • cancelRequest(id)
  • getImageSize()
  • getZoomLevelRange()

requestTile()cancelRequest()DemProvider の同名メソッドと同じ働きをします。 ただし callback パラメータの関数に与える引数はArrayBufferインスタンスではなくImageインスタンスになります。

getImageSize() はプロバイダが提供する地図タイル画像の水平方向または垂直方向の画素数を返します。地図タイル画像は正方形でなければなりません。

getZoomLevelRange() はプロバイダが提供する地図タイル画像のズームレベルの範囲を返します。

以下は単純な地図画像プロバイダ MyImageProvider の実装例です。

class MyImageProvider extends mapray.ImageProvider {
    constructor()
    {
        super();
        // 初期化
        ...
    }

    requestTile( z, x, y, callback )  // override
    {
        var image = new Image();
        image.onload  = function() { callback( image ); };
        image.onerror = function() { callback( null ); };
        image.src = this._makeURL( z, x, y );
        return image;  // 要求 ID
    }

    cancelRequest( id )  // override
    {
        // 取り消し方法はないので何もしない
    }

    getImageSize()  // override
    {
        return 256;  // 画像サイズは 256×256
    }

    getZoomLevelRange()  // override
    {
        return new mapray.ImageProvider.Range( 0, 10 );  // ズームレベルは 0 から 10
    }

    _makeURL( z, x, y )  // タイル z/x/y の地図画像データの URL を返す
    {
        return 'http://localhost/map/' + z + '/' + x + '/' + y + '.png';
    }
}

2. 地形の問い合わせ

コンテンツでマウスなどのインタラクティブ操作を実現する場合、地形に合わせてカメラを動かしたいことがあります。

たとえばカメラが地表の下に移動しないようにするため、カメラ真下の地表の標高を知ることにより、その場所よりも高い場所にカメラ位置を調整できます。

また、マウスのドラッグにより地表を掴んで動かすイメージの操作を実現するとき、ドラッグ開始時のマウスカーソル位置に表示されている地表の位置を知ると、それによりカメラの位置を計算できます。

maprayJS APIでは、DEMデータから地形の情報を得るメソッドとして次のメソッドを用意しています。

  • Viewer#getElevation(lat, lon)
  • Viewer#getRayIntersection(ray)

    Viewer#getElevation() は引数に緯度と経度を与えてその場所の標高を得ます。

    Viewer#getRayIntersection() は引数にレイ(始点と方向)を与えて、そのレイと地表が交差するもっとも近い点の座標 (GOCS) を得ます。

Maprayのシーンが表示されているキャンバス上のある点に対応するレイを次のメソッドにより取得できます。

  • Camera#getCanvasRay(cpos, oray)

2.1. 精度に関する注意点

Viewer#getElevation()Viewer#getRayIntersection() により得られる値は、その時の状況により精度が変化します。 これは現在メモリ内に存在するもっとも精度が高いDEMデータを使い、即時に値を計算しているからです。

Viewer#getElevation() は、さらに詳細なDEMデータが DemProvider により取得することができれば、そのデータをリクエストします。そのため、時間を置いてこのメソッドを呼び出すと、さらに正確な値を取得できることがあります。

これに対し Viewer#getRayIntersection() は新たにDEMデータをリクエストしません。このメソッドは基本的に現在画面に表示されてる場所が対象になり、一般的に、近くに表示されている部分は精度が高く、遠くに表示されている部分は精度が低くなります。

3. エンティティの表示

Maprayエンジンは地表と同時にポリゴンモデルや文字などのオブジェクトも表示できます。

fuji-motosuko.png

maprayJS APIではこのオブジェクトのことをエンティティと呼び、 Scene インスタンスに Entity インスタンスを追加することによってエンティティを表示できます。 Scene インスタンスは Viewer#scene プロパティによりアクセスできます。

maprayJSライブラリは現在、以下に示す Entity のサブクラスを用意しています。

クラス 表示内容
GenericEntity ポリゴンモデル
TextEntity 複数のテキスト
MarkerLineEntity 連続ライン

次のコードは TextEntity を使い、シーンに2つのテキストを表示する例です。

var entity = new mapray.TextEntity( viewer.scene );

entity.addText( "富士山",
                [-3911845.4, 3433281.3, 3693469.5],
                { color: [1, 1, 0], font_size: 30 } );

entity.addText( "本栖湖",
                [-3896100.8, 3437552.8, 3700948.3],
                { color: [0, 1, 1], font_size: 25 } );

viewer.scene.addEntity( entity );

各エンティティにはさまざまなプロパティがあります。詳細はリファレンスマニュアルを参照してください。