初めに
従来のYahoo!地図アプリは、社内ではラスタ形式地図アプリと呼んでおり、サーバ上で生成された地図タイル画像(ラスタデータ)を端末側で貼り合わせることで、地図を表示していました。
しかし、画像でやり取りを行うために、次のようなデメリットもありました。それは、通信の帯域を多く占有したり、地図の回転をする場合に地名などの文字も回転してしまい、読みづらくなったりする点です。
そこで、今回フルリニューアルしたAndroid版Yahoo!地図アプリでは、サーバからベクトルデータを受信して、端末側で地図を描画するベクトル形式地図アプリに移行しました。
ベクトル形式地図アプリに移行したAndroid版Yahoo!地図アプリは、従来版と比べ、以下のような点がメリットとして挙げられます。
- 通信の軽量化
- 回転拡大縮小のスムーズ化
- 3Dなど新しい地図表現の追加
ベクトル形式地図アプリ
ラスタ形式のデータはビットマップデータと呼ばれていて、ドットごとに色のついたデータで構成されています。従来のラスタ形式のYahoo!地図アプリでは、PNG形式で地図データを扱っていました。ベクトル形式となった最新版Yahoo!地図アプリでは、写真データにはJPEG形式が使われています。
今回のベクトル形式は、点・線・面の座標データで構成されています。そのため従来のラスタ形式よりもデータ容量が1/3ほどとなるのはもちろん、端末側でベクトルデータを元に地図を描画するため、拡大・縮小しても画質が損なわれることがなくなるなどのメリットがあります。特に高解像度端末では、ラスタデータの場合、端末の解像度に合わせた高解像度の画像をサーバで生成して配信しなくてはなりません。よって、データ容量が何倍にもなってしまい、受信するまでに時間がかかるといったデメリットがありました。ベクトル形式であれば、前述のとおり地図の拡大・縮小が自在であるため、容量を変えずに端末の解像度に合わせた表示を実現できます。
では、ベクトルデータをどのようにして端末で描画しているかというと、Yahoo!地図アプリでは、OpenGLを使ったハードウェアレンダリングを採用しています。Canvasでのソフトウェアレンダリングの可能性も検討しましたが、Yahoo!地図アプリの求めるパフォーマンスを実現することが困難であると判断したため、端末のパフォーマンスを最大限活用できるOpenGLでの描画を採用しました。
OpenGL
OpenGLは、グラフィックス用のAPIでさまざまなハードウェアやOSで取り扱われています。
Androidでは、OpenGL ES(OpenGL for Embedded Systems)と呼ばれる、携帯端末などの組み込み用に最適化されたAPIを使うことが可能で、ゲームアプリなどでよく利用されています。
最新のAndroid 4.3(Jelly Bean)では、OpenGL ES 3.0までサポートされていますが、Yahoo!地図アプリは、広く端末をカバーするためOpenGL ES 2.0を採用しています。
では、実際にOpenGLを使った地図表示の流れを追っていきましょう。
OpenGLを使った地図の描画
地図といっても点、線、面と文字で構成されるベクトルの絵であるため、他のアプリと大きな違いはありません。そのためユーザの動作に合わせてシームレスにデータを取得する点や地図独特の座標の考え方以外は、基本的なAndroidアプリケーションと同じです。
上記の図2の流れが、基本構造です。
- 地図アプリ全体を構成するためのMainActivity
- 地図操作を管理するためのMapView
- OpenGLで描画を行うためのGLSurfaceView
- 描画処理本体のRenderer
MainActivityはアプリ本体を構成するもので、お店検索やルート検索など地図を補助する機能を包括的に管理しています。なお、これらの処理については、別の機会に改めて紹介させていただきます。
MapView以下が地図処理についての本体です。旧アプリを構成したYahoo! AndroidマップSDKと同様に、SDKとして別ライブラリで管理されています。一般公開は行っていませんが、将来的には公開を行いたいと思います。
では、処理をもう少し詳しく説明します。
MapView
地図を描画するための初期化処理やユーザのタッチイベントの処理、アプリからの操作インターフェースを提供しています。下記のGLSurfaceViewの初期化をここで行います。
GLSurfaceView
OpenGLでレンダリングを行うためのビューです。地図を構成するためには、上記のベクトルデータに合わせて色を示すためのスタイルが必要になってきます。それらの情報を初期化時にロードなどを行っています。実際のレンダリング処理は、Rendererが受け持つことになります。
Renderer
OpenGL側が作成したGLThreadから描画処理(onDrawFrame)が呼ばれます。以下のような流れで必要な場所のベクトルデータのロードから表示処理までの動作を行います。
- 位置座標の計算
- ベクトルデータをネットワーク経由でロード
- ベクトルデータとスタイルデータをもとに描画用データを生成
- ベクトルデータをグラフィックメモリに転送
- FBO(Frame Buffer Object)にレンダリング
- FBOで作成したテクスチャーを使って画面に地図を表示
以上の流れが、地図描画に関する概要です。
実際にコードをもとに説明したいと思いますが、地図アプリは何万行となるコードで形成されているためとても説明しきれません。
そこで本連載では、簡易的な地図アプリを何回かに分けて構築していきたいと思います。その際に開発で工夫した点などもいっしょに紹介させていただきます。第一回目は、基本となる骨組みの部分の作成を行います。