概要
GASでGoogleマップを表示する際、地図上にピンを立てたり線を引くメソッドがある。
でも円を描写するメソッドがない・・・。
任意の中心点と半径でGoogleマップに円を描写したいなぁと思い、やってみた。
関連記事
GoogleAppsScriptで地図を扱うTips
GoogleAppsScriptで2点間のルートと道中の標高を表示
線を描く
まずは線の描写から。
公式リファレンスを見ると、Maps.encodePolyline([緯度,経度,緯度,経度,緯度,経度,...])
って感じに点を決めて、Maps.addPath()
してやると線が引けるとのこと。
点を用意
皇居のお堀外周に線を引いてみる。
Googleマイマップを使い、次のようにお堀をなぞる線を繋ぐ点をゲットした。
・お堀外周のポリゴン作成
・KMLファイルに書き出す
・拡張子をtxt変更
・ポリゴンの各点の経緯度が並んでる
Googleマップ上で経緯度を拾うことも可能だけど、完成形をイメージしやすかったのでマイマップを使用してみた。
※この方法だと "経度,緯度" の順で並んでるので注意。GASに入力するときは "緯度,経度" の順番で記述する。
コード
function koukyo() {
var point = [35.6889765,139.745822,
35.6887848,139.7456289,
35.6866238,139.7454143,
35.6835737,139.7445775,
35.6828069,139.7447921,
35.6799484,139.7462512,
35.6794604,139.7476245,
35.6785889,139.748354,
35.6775431,139.749384,
35.6774036,139.7509719,
35.6779614,139.753461,
35.6754514,139.7596837,
35.6840269,139.762559,
35.6844452,139.7604132,
35.687408,139.7613145,
35.6891508,139.7607136,
35.6891508,139.7600699,
35.6899176,139.7600699,
35.6907542,139.7563363,
35.6926363,139.7551347,
35.6932637,139.7535468,
35.6936471,139.7513581,
35.6950063,139.750371,
35.6943441,139.7477961,
35.6923575,139.7479249,
35.6916952,139.7470666,
35.6897434,139.7482682,
35.6889765,139.745822];
var polyline = Maps.encodePolyline(point);
var map = Maps.newStaticMap()
.setLanguage('ja')
.setSize(300,300)
.setZoom(14)
.setCenter('皇居')
.addPath(polyline);
SpreadsheetApp.getActiveSheet().insertImage(map,1,1);
}
点を決めてencodePolyline
して、地図の各パラメータと一緒にaddPath
して、シートに表示。中心点はランドマークでも行けるのでシンプルに皇居
と指定。
こんな感じ
円を描く
円を描くメソッドがなくたって、線が引けるんだから直接描けばいい。中心点を決めて等距離にある点を繋いだら円になるよなと、試してみた。
失敗例
x=rcosθ
y=rsinθ
で円の座標が求められる。と思って計算して描写したところ、楕円になってしまった。
どうやら緯度によって経度当たりの長さが変わるので補正が必要っぽい。
補正付き数式
よく分からなくてググったところ、OKWAVEでいい感じに意見交換されてたので、書き込みを参考にして数式を作成。
\begin{align}
&y=緯度+\frac{円の半径×\sin\theta}{地球の半径}\\
&x=経度+\frac{円の半径×\cos\theta}{地球の半径}×\frac{1}{cosy}
\end{align}
x=rcosθ
y=rsinθ
の考え方はそのままに、x
にはcosy
の逆数をかければ良いっぽい。で、角度と長さから分かった座標分、元の経緯度からずらしてやる。
地球の半径は6371008mなので、あとは元の経緯度と円の半径が決まれば円が描けるはず!
Qiita記事:【GoogleMap】地球を半径6371008mの球体として距離計算していた
OKWAVE:距離から緯度経度を求める方法
コード
というわけで、皇居を中心に半径1kmの円を描いてみる。
function en() {
var lat = 35.68523; //皇居の緯度
var lng = 139.75279; //皇居の経度
var len = 1000; //円の半径m
var I = Math.PI/180; //ラジアン変換
var R = 6371008 * I; //地球の半径m(×ラジアン変換)
var point = [];
//基準点から全方位へlenだけ離れた位置を計算して並べていく
for(var A=0; A<=360; A++){
var y = lat + len * Math.sin(A*I) / R ;
var x = lng + len * Math.cos(A*I) / R / Math.cos(y*I);
point.push(y,x);
}
var polyline = Maps.encodePolyline(point);
var map = Maps.newStaticMap()
.setLanguage('ja')
.setSize(300,300)
.setZoom(14)
.setCenter(lat,lng)
.addPath(polyline);
SpreadsheetApp.getActiveSheet().insertImage(map,1,1);
}
事前に、分母に来る地球の半径にラジアン変換をかけておき、度数に戻す式を省略。for文中の数式を見やすくしたつもりだけど・・・好みの問題?
こんな感じ
おまけ
Maps.setPathStyle(線の太さ, 線の色, 塗りつぶし)
で描写スタイルを指定できる。コードの地図設定部分を次のようにすると・・・
Maps.newStaticMap()
.setLanguage('ja')
.setSize(300,300)
.setZoom(14)
.setCenter(lat,lng)
.setPathStyle(5,'red','blue')
.addPath(polyline);
こんな感じになる。
塗りつぶし部分をnull
にすれば塗りつぶしなし。