【Android】GoogleMap の回転 従コンパス移動と従画面移動

EngineeringAndroid, 備忘録

【Android】GoogleMap の回転 従コンパス移動と従画面移動

軌跡なき轍

GoogleMap を回転させた際に、コンパスに沿って十字移動する場合と、画面に沿って十字移動する場合があると思ったので、移動モードを Switch で切り替える、ということを考えた。

とりあえず「従コンパス移動」と「従画面移動」とした。

回転角0°(N-Sは画面鉛直方向に平行)からアプリはスタートする。

 

 

これが答えだ

private void incLatLon() {
lat += moduMoveArg() * abs(Math.sin(Math.toRadians(angR)));
lon += moduMoveArg() * abs(Math.cos(Math.toRadians(angR)));
if (lat > 70.6502477) lat = 70.6502477; // GoogleMap の臨海値
if (lon > 180) lon -= 360;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat,lon), altitude));
}
private void decLatincLon() {
lat -= moduMoveArg() * abs(Math.sin(Math.toRadians(angR)));
lon += moduMoveArg() * abs(Math.cos(Math.toRadians(angR)));
if (lat > 70.6502477) lat = 70.6502477;
if (lon > 180) lon -= 360;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat,lon), altitude));
}private void incLatdecLon() {
lat += moduMoveArg() * abs(Math.sin(Math.toRadians(angR)));
lon -= moduMoveArg() * abs(Math.cos(Math.toRadians(angR)));
if (lat > 70.6502477) lat = 70.6502477;
if (lon > 180) lon -= 360;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat,lon), altitude));
}
private void decLatLon() {
lat -= moduMoveArg() * abs(Math.sin(Math.toRadians(angR)));
lon -= moduMoveArg() * abs(Math.cos(Math.toRadians(angR)));
if (lat > 70.6502477) lat = 70.6502477;
if (lon > 180) lon -= 360;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat,lon), altitude));
}

ジャーン(ちなみに、iMac のスタート音は擬声語としてなんと表現すればよいのか、なかなかの難題である。ジョーン、ジューン、ゾーンという3者の平均中間値(勝手に言葉を作っている)とでもいおうか。 こういう表現ができないような音源を意図して製作しているとすれば、・・・・占星術でもあるまいし、だからなんだというわけでもないが、少なくとも単純なひとびとがつくったものではないということだけはわかる)。

以下のサイトが大いに参考になった。回転、俯角等について、実にわかりやすい解説にかろうじて巡り合えた。
【Android】Google Map API v2で、地図を拡大/指定位置の表示/傾ける/回転などを行う

 

 

経過

十字移動のメソッドを4つ定義。

private void incrementLat() {  //★move to North
lat += moduMoveArg();
if (lat > 70.6502477) lat = 70.6502477;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat,lon), altitude));
}
private void incrementLon() { //★move to East
lon += moduMoveArg();
if (lon > 180) lon -= 360;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat,lon), altitude));
}
private void decrementLat() { //★move to South
lat -= moduMoveArg() * Math.cos(Math.toRadians((angR + 360) % 360));
if (lat < -70.6502477) lat = -70.6502477;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat,lon), altitude));
}
private void decrementLon() { //★move to West
lon -= moduMoveArg() * Math.cos(Math.toRadians((angR + 360) % 360));
if (lon < -180) lon += 360;
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat,lon), altitude));
}

緯度やら経度やらのパラメーターは final static 宣言しておく。

回転角0°、→右回りで+90°、+180°。 →左回りで-90°、-180° というように回転するのだが、1°以上89°以下の場合、91°以上179°以下の場合、-179°以上-91°以下の場合、-89°以上-1°以下の場合(1°単位でしか GoogleMap は回転指定できない)の4つの場合について、それぞれ十字移動メソッド2つずつの組み合わせで移動ボタンの動作を設定できるはずである。

だから、

btn3_4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
incrementLon();
if (sw_propo) {
incrementLon();
} else {
int t = angR;
if (t < -270) {
decrementLat();
incrementLon();
} else if (t == -270) {
decrementLat();
} else if (t < -180) {
decrementLon();
decrementLat();
} else if (t == -180) {
decrementLon();
} else if (t < -90) {
incrementLat();
decrementLon();
} else if (t == -90) {
incrementLat();
} else if (t < 0) {
incrementLat();
incrementLon();
incLatLon();
} else if (t == 0) {
incrementLon();
} else if (t < 90) {
incrementLat();
decrementLon();
} else if (t == 90) {
decrementLat();
} else if (t < 180) {
decrementLon();
decrementLat();
} else if (t == 180) {
decrementLon();
} else if (t < 270) {
incrementLat();
decrementLon();
} else if (t == 270) {
incrementLat();
} else if (t < 360) {
incrementLon();
incrementLat();
}
}
//System.out.println("☆ - btn3_4 : 東へ移動");
}
});

というように場合分けして試行するのだが、当初、角度によって移動する向きがバラバラになった。もちろん場合分けして調整するのだが、政界になかなかヒットしないまま、時間が経過した。

北へ移動が incrementLat() で、東へ移動が incrementLon() であるなら、北東とか北北東といった中間の座標への移動は incrementLat(); と incrementLon(); の2行の記述で実行されるだろう。

mMap.moveCamera 描画処理を incrementLat(); と incrementLon(); の2回に割り当てるより1回にまとめるため、メソッドにする。

private void incLatLon() {
lat += moduMoveArg() * Math.sin(Math.toRadians((angR + 360) % 360));
lon += moduMoveArg() * Math.cos(Math.toRadians((angR + 360) % 360));
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat,lon), altitude));
}

高校数学を思い出して紙に図を書きながら考える。

角度に変化があった場合、sinθ に反映される緯度の増減ベクトルと、cosθ に反映される経度の増減ベクトルの合成ベクトルが企図する移動ベクトルであるから、上のようになると思ったが、今だ角度によって移動が意図しない方向へ向かっている。

・・・・・ついに気づいた。上において、緯度経度の増加を見越してせっかくメソッド名を incLatLon() としているのに、これでは値が減る場合がある!

すなわちっ、

abs() を被せることによって絶対値を得、これを増減の算出に用いるのであった。
(経度の増減に btn3_1 とか btn3_2 を用意し、上の incLatLon() メソッドを使ったとする。
 緯度の増減の場合、試行錯誤盤根錯節の結果、sin と cos が逆になるようである、ということが判明した。
たとえば btn_4_1 とか btn_4_2 を用意したとき、これらのボタンのための incLatLon_btn_4() メソッドは、incLatLon() メソッドの中身をコピーしたのち、sin と cos を入れ替えてつくる)。

 

このような、解けた瞬間はとてもうれしいものである。開発という仕事のやりがいでもあるのだろう。もっとも、実際の求職活動の中では、ゴリゴリのプログラミングより、採算や納期も管理できるマネジメント能力・経験がないとなると、ダメだね、ホント。 プログラマが不足している + 教えたくない職人気質という存在矛盾をたくさん見せつけられるきょうこのごろ♡。


 

EngineeringAndroid, 備忘録

Posted by Qawai