sos の 作業メモ

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

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

その9: Changing the View (Google Maps SDK for iOS)

前回の続き

Changing the View

Introduction

Google Maps SDK for iOSに追加されたマップは、理にかなった簡単なジェスチャーで、Tiltや回転を行わせることができる。

様々なズームレベルで地図をパン(スクロール)させたり、短時間での視点の変更も可能。

マップの方向やTilt(傾き)、座標、そしてズームレベルは、GMSCameraPositionオプジェクトを使ってプログラムから操作が可能。

新しい視界にあわせて、追加したマーカーやpolyline,その他のoverlayの値をより適したものに変化させたいと考えるかもしれないが、カメラへの変更がそういったものを変えることはない。

このトピックの残りの部分では、ズームレベルやビューポート、視点を変更するためのカメラの使い方を説明する。

The map's view

Web版のGoogle Mapsと同じく、Google Maps SDK for iOSも、端末のスクリーン上にメルカトル図法で地球の表面を投影する。

東西方向には、マップは継ぎ目なく無限に繰り返され、南北方向には、およそ北緯85度と南緯85度に制限されている。

メルカトル図法は、経度を幅、緯度を高さにもつ手法(高緯度地域で幅の拡大が多くなる)

世界地図から緯度を南北85度にカットし、地図を正方形にしたのは、タイルの選択ロジックを簡単にするためである。

Camera position

カメラポジションは、緯度経度、ズームレベル、方位、視角(俯角)で決定される。 初期のカメラポジションは、GMSMapViewオブジェクトを生成する際に設定される。

GMSCameraPosition* camera = [GMSCameraPosition cameraWithLatitude:-33.8683 longitude:151.2086 zoom:16];
mapView = [GMSMapView mapWithFrame:self.view.bounds camera:camera];

地図は地表を見下ろす形で作成される。GMSMapViewを生成する際に、デフォルトのUIViewも作成される。以下のケースでは、カメラポジションはデフォルトで生成されるが、その後で明示的に変更することができる。

mapView = [[GMSMapView alloc] initWithFrame:self.view.bounds];

Moving the camera

作成されたGMSMapViewオブジェクトは、設定したものかデフォルトのカメラを持つが、これはいくつかの方法で変更が可能である。

カメラを変更する際に、移動をアニメーションさせるオプションもある。アニメーションは、現在の値と新しい値を補間して行われる。また、core animationを使ったアニメーションに要する時間の制御も可能である.

GMSCameraPositionオブジェクトを変更し、それをGMSMapViewに設定した場合、アニメーションなしで新しい場所にカメラが移動する。 GMSCameraPositionオブジェクトは、緯度、経度、ズーム及び、方角と視角(俯角)のプロパティで構成されている。

GMSCameraPosition *sydney = [GMSCameraPosition cameraWithLatitude:-33.8683 longitude:151.2086 zoom:6];
[mapView setCamera:sydney];

また、GMSCameraPositionには、明示的に方角と俯角を設定することもできる。

GMSCameraPosition* fancy = [GMSCameraPosition cameraWithLatitude:-33.8683 longitude:151.2086 zoom:6 bearing:30 viewingAngle:45];
[mapView setCamera:fancy];

移動をアニメーションしたい場合は、いくつかのメソッドのうちの何れかが使える。また、アニメーションに要する時間は、CoreAnimationで制御が可能。

[mapView animateToViewingAngle:45];

GMSCameraUpdateオブジェクトを使えば、カメラの新しいビューの指定が、アニメーションするかしないかも含めて指定できる。

Viewを更新するなら、GMSMapViewの moveCameraメソッドでGMSCameraUpdateオブジェクトを渡すとよい。これは、あらかじめ定義しておいた領域にカメラを移動させる場合に便利。

GMSCameraUpdate* update = [GMSCameraUpdate fitBounds:bounds withPadding:50.0f];
[mapView moveCamera:update]; // アニメーション無し
[mapView animateWithCameraUpdate::update]; // アニメーション有り

以下のセクションでは、カメラプロパティをどのように変更するかを説明する。

Location

Locationは、マップの中心の座標で緯度と経度によって指定される。プログラムでは、CLLocationCoordiante2DMakeによって作られるCLLocationCoordinate2Dオブジェクトで表現する。

緯度は -85度から85度の範囲で、それを越えるとそこでカットされる。例えば、100をセットしようとすると、セットされた値は85になる。
経度は-180度から180度で、値はその範囲におさまるようにラップされる。例えば、480,840,1200は、全て120になる。

ユーザーは、地図をパン(スクロール)することでlocationを変更できる。プログラムからは、GMSMapViewの animateToLocationメソッドを使う。

[mapView animateToLocation:CLLocationCoordinate2DMake(-33.868, 151.208)];

アニメーションを行わず直接locationをセットするなら以下

CLLocationCoordinate2D target = CLLocationCoordinate2DMake(-33.868, 151.208);
mapView.camera = [GMSCameraPosition cameraWithTarget:target zoom:6];

Zoom

地図の縮尺を決めるのがカメラのズームレベル。

ズームレベルが大きいと、より詳細な地図がスクリーン上で見られ、ズームレベルが小さいと、世界全体が見られる。

ズームレベルが0の場合、世界全体が256ポイントの大きさとなる。ズームレベルが1大きくなる毎に、スクリーン上の世界の幅が倍になる。

ズームレベルをNとすると、世界の幅は 256 * 2N。例えば、ズームレベルが2の場合、世界は 256 * 22 = 256 * 4 = 1024ポイントとなる。

なお、ズームレベルは整数である必要はなく、また、設定可能なズームレベルの範囲は、スクリーンサイズやマップ種別や場所によって様々である。

ユーザーは二本指のピンチ操作によってズームレベルを変更可能(ダブルタップで指を離さずに上下にスワイプでも可)である。プログラムからは、GMSMapViewのanimateToZoom:メソッドを使う。

[mapView animateToZoom:12];

Bearing (orientation)

地図上の点の縦線の向き。真北から時計回りに度で測られる。

車を運転する人は、進行方向に向かってしばしば地図を回転させる。地図とコンパスを使うハイカーも、通常は地図の縦線を北に合わせる。

Google Maps SDK for iOSは、地図の配置や方角の変更が可能で、例えば、bearingを90度にすると、上方向が真東を指すようになる。

ユーザーは、二本指の回転操作でbearing(方位)を変更できる。プログラムからは、GMSMapViewのanimateToBearing:メソッドで変更が可能。

[mapView animateToBearing:0];

Viewing Angle

カメラの位置は、マップの中心の直上(天頂)から地表面まで間の円弧を動く。なお、天頂から直下の方向を0として度で表される。

視角(俯角)を変えると、3D表示の効果として、注視点より手前のものはより大きく、奥のものはより小さく表示されることになる。

視角(俯角)の範囲は、0度(真下方向)から30度もしくは45度であり、ズームレベルによって上限は変わる。

ユーザーは二本指の縦方向のスワイプ動作で視角の変更が可能。プログラムからは、GMSMapViewのanimateToViewingAngle:メソッドを使う。

[mapView animateToViewingAngle:45];

Create a new view with GMSCameraUpdate

直接カメラを変更するGMSMapViewの多様なメソッドの代わりに、GMSCameraUpdateと呼ばれる事前にマップの操作を定義し、それをGMSMapVIewのmoveCamera:メソッドに指定することができる。また、アニメーションさせるならanimateWithCameraUpdate:が使える。

GMSCameraUpdateオブジェクトは、以下のfactoryメソッドによってのみ作られる。

zoomIn: and zoomOut:

現在のズームレベルから1.0だけ変化させる。他の全てのプロパティはそのまま。

zoomTo:

設定された値にズームレベルをセットする。他の全てのプロパティはそのまま。

zoomBy:

現在のズームレベルに、指定された値を足す(値がマイナスなら引く)

zoomBy:atPoint:

指定された座標を中心として、ズームレベルに指定された値を足す(値がマイナスなら引く)

setTarget:

他の全てのプロパティはそのままで、カメラの緯度と経度を変更する

setTarget:zoom:

カメラの緯度と経度、ズームレベルを変更する。他の全てのプロパティはそのまま

setCamera:

GMSCameraPosittionオブジェクトを設定する。(このオブジェクトはtarget,zoom,bearing,view anbleを一度に指定可能)

scrollByX:Y:

カメラの緯度と経度を、スクリーン上のポイント数で変化させる。Xに正の値を与えるとカメラは右に動き、その結果マップは左へ移動する。Yに正の値を与えるとカメラは下に動き、その結果マップは上へ移動する。上下左右はカメラの向きに関係し、bearingが90度の時は東が上となる。

fitBounds:

指定された領域が画面の中央におさまるように、中心座標とズームレベルが調整される。デフォルトで64ポイントパディングされる。

fitBounds:withPadding:

指定された領域が画面の中央におさまるように、中心座標とズームレベルが調整される。指定されたポイントだけパディングされる。

Updating the Camera View

GMSCameraUpdateオブジェクトで カメラを更新する

  1. GMSMapViewオブジェクトを生成
  2. GMSCameraUpdateオブジェクトをファクトリメソッドのどれかで生成
  3. GMSMapViewのmoveCamera: か animateWithCameraUpdate: メソッドでカメラを更新

以下、GMSCameraUpdateを使ったカメラ移動のコード例

// 1レベルズームイン(拡大)
GMSCameraUpdate* zoomCamera = [GMSCameraUpdate zoomIn];
[mapView animateWithCameraUpdate:zoomCamera];
// カナダのバンクーバーを中心に表示
CLLocationCoordinate2D vancouver = CLLocationCoordinate2DMake(49.26,-123.11);
GMSCameraUpdate* vancouverCam = [GMSCameraUpdate setTarget:vancouver];
[mapView animateWithCameraUpdate:vancouverCam];
// 下に100ポイント、右に200ポイントカメラを移動
GMSCameraUpdate *downwards = [GMSCameraUpdate scrollByX:100 Y:200];
[mapView animateWithCameraUpdate:downwards];

Zoom to a geographic bounds

興味のある範囲全体が、可能な限りの最大サイズで表示されるようにカメラが移動すると便利なことがある。 例えば、ユーザーの現在位置から5マイルの範囲内の全てのガソリンスタンドを画面に表示したい時に、できるだけ大きく表示するようカメラを移動したいと考えるだろう。 この場合、まずGMSCoordinateBoundsオブジェクトに表示する領域を設定し、 これをGMSCameraUpdateのfitBounds:メソッドに渡せば、希望に適したGMSCameraUpdateオブジェクトが得られる。(tiltとbearingは共に0となる)

また、別バージョンの fitBounds:withPadding:メソッドを使えば、領域を囲む余白も設定可能となる。

以下は、バンクーバーカルガリーの都市の両方が表示されるようにカメラを移動するコード例

CLLocationCoordinate2D vancouver = CLLocationCoordinate2DMake(49.26,-123.11);
CLLocationCoordinate2D calgary = CLLocationCoordinate2DMake(51.05,-114.05);
GMSCoordinateBounds* bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:vancouver coordinate:calgary];
GMSCameraUpdate* update = [GMSCameraUpdate fitBounds:bounds withPadding:50.0f];
[mapView animateWithCameraUpdate:update];

次回へ続く