轍 〜自転車的なる日記〜

またまた「何を今さら?」的な話題で恐縮ですが(^^;、また凄いものを発見してしまったので感動しております。いや、単なる無知なんですが・・

国土地理院のHPでダウンロードできる「数値地図25000(空間データ基盤)」なんですが、これまでわけのわからない数字の羅列でどうやって使うんだろう?と思ってましたが、付属のデコーダによりXML形式に変換することができるんですね。知らんかった・・(^^;

で、XMLに変換してみると(コピペしてもタグが化けてしまうので載せられませんが)、道路や鉄道、主な公共施設などがちゃんと座標として出力されているではありませんか! しかもメッシュ標高データもあります。国道番号や道路の幅員までわかるんですね。

GPSの地図をタダで作れるっていうのはこれのことだったんですね。UUDの市販地図もこれを使って作られているらしいです。商品化するにはCD-ROMを購入して国土地理院の許可を得る必要がありますが、とりあえず個人で遊ぶ分にはタダで楽しめます。(^^)

これができるってことは、こんなこともあんなこともできるんだよなぁ・・(^^; Googleも国土地理院も知らない間に勝手に進化しちゃって、もうついて行けません・・(爆)
最近Google Mapsのマッシュアップサイトが次々と登場してきてますが、いつの間にかこんなサイトができてたんですね。昨日ヒキタ氏のメルマガで紹介されていたので気づいたんですけど・・

以前これの東京版を見たことがあるんですが、ついに全国版ですか・・・。またやられちまったぜぃ・・って感じですが。(^_^;

そこそこユーザーもいるようで、インターフェースもなかなかお洒落。しかし地図を開いてみればわかりますが、めちゃくちゃ重い・・(-_-; スクロールなんかほとんどできない状態です。

重い理由は言うまでもなく、大量のアイコンを表示させているからですね。峠データベースなんかでも苦労させられましたが、これはもうGoogle Mapsの宿命なんで、トップページに一度にアイコンを表示させると絶対こうなっちゃうんですよね・・。自分だけで使うんならまだしも、多数のユーザーが使うサイトでこんなことをやればあっと言う間に激重になるってことは開発の時点で気づかなかったんでしょうか?

確かに地図を開いていろんな情報が一目でわかれば魅力的ではありますが、そうすると重くなりすぎて使い物にならない・・・これはGoogle Mapsのジレンマでもあります。実用的に軽くするためには表示する情報を絞り込むしかないんですよね・・。それがイヤならGoogle Earthを使うしかありません。

一方、ALPSLAB routeの方はこういうやり方をしてないですよね。もちろんルート情報でこんなことをやるととんでもないことになりますが、トップページでルートを選んでから個別に表示させるやり方なので、重くなることはありません。さすがにその辺はよく考えてるなと思いました。

この「自転車大好きマップ」に類するものは今後も出てくると思いますが、同じようなやり方をしていればすぐ激重になって使い物にならなくなります。そして重くなるとユーザーが離れるという悪循環ですね。かくしてユーザーはALPSLAB routeへと流れていき、ALPSLAB routeの一人勝ちは続く・・・(笑)

ところでこのマップ、インターフェースがちょっと独特だなと思ったらFLASHを使ってるんですね。Google MapsとFLASHの合わせ技なんてできたのか・・。しかし特別なプラグインなしに閲覧できるというのがGoogle Mapsの売りなのに、わざわざFLASHを使うというのは僕は好きじゃないですね。見栄えは多少地味になるけど、JavaScriptの力業でガリガリとやればできるはず。ちなみにこのサイトはXOOPSで作られてますよね。最近XOOPSで作ったサイトはすぐわかるようになってしまった。(^_^;
Google Mapsで使われているゼンリンの地図がリニューアルされて見やすくなってます。路線名も表示されるようになりました。
しかも地図+衛星画像の表示も可能になってます。これはGoogle Earthを意識したってことでしょうか。
ただ等高線がまったく表示されなくなったのはちょっと残念・・・
今回の宮古島ツアーで気づいたGPSの位置ずれ現象ですが、帰ってカシミールに取り込んでみると、やはり感じた通りであることがわかりました。ご覧のように山旅地図の上にトラックを表示させると、南東方向に80mほどずれます。これは現地で実感していた現象とまったく一致します。ウェイポイントを登録する際に山旅地図を使っていたので、このようにずれた状態になっていたわけです。


山旅地図では南東方向に80mほどずれる

ところが、国土地理院が提供している25000分の1地形図の上にトラックを表示させるとまったくずれることなくピタリと重なります。つまりこれが正しいということです。ということは山旅地図の座標データは宮古・八重山地方だけおかしいということになります。

watchizu.png
国土地理院「うぉっ地図」ではずれない

これで少なくともGPSの精度には問題がないことがわかりました。おそらくは山旅地図におけるデータの作り方の問題と思われます。これと同じく、Google Maps上にトラックを表示させても石垣島周辺でずれるという現象が見られます。Google Mapsで使われているゼンリンの地図もやはり宮古・八重山地方で座標がおかしくなっている可能性があります。
以前の記事でも説明したんですが、アクセス解析を見ていると、このブログはやたらと「緯度 経度 距離」というキーワードで検索されていることが多いんですよね。

JavaScriptなどを使って簡易的な方法として求めるにはそれで十分だったんですが、Google MapsがVersion 2になって、何と距離を求めるメソッド(関数とは言わない)が標準で装備されているではありませんか! これでめんどくさいことを考えずに簡単に距離が求められるようになったわけですね。めでたし、めでたし・・。以下、Googleのリファレンスより引用。

クラス:GLatLng
メソッド:distanceFrom(GLatLng other)
戻り値:距離(m)
説明:
Returns the distance, in meters, from this point to the given point. The earth is approximated as a sphere, hence the distance could be off by as much as 0.3%.

著者訳:
この点から与えられた点までの距離をメートル単位で返します。地球は球体として近似しているため、0.3パーセント程度の誤差が生じる場合があります。

使い方:
(緯度1,経度1)と(緯度2,経度2)の間の距離を求めるには次のようにします。

var point = new GLatLng(緯度1,経度1);
var distance = point.distanceFrom(new GLatLng(緯度2,経度2));

これで変数distanceに2点間の距離がメートル単位で求められます。オブジェクト指向の考え方がわかってない人には何でこんなことするのか理解できないと思いますが、まあ自分で勉強してください。(^_^;

説明にあるように、地球を完全な球体として近似しているために0.3%程度の誤差が生じますが、1kmにつき3mの誤差ですから、通常の使用では十分な精度と言えるでしょう。この方法は以前説明した簡易的な方法と同じです。厳密な方法でやるとものすごく重たくなるので、JavaScriptでやるのには向いていません。
Google Mapsのサテライト表示ではこれまで東京周辺しか詳細を見ることができませんでしたが、いつの間にか大阪をはじめ、各主要都市周辺で詳細が見られるようになっているではありませんか! 奈良市内もちゃんと見えます。でもうちは見えません。(^_^;

スケールを最大にすると家の一軒一軒、いや道を走る車まで識別できますね。これは凄いです。駐車場にある自分の車を探した方もいるんじゃないでしょうか?(^_^; 

世界中の主要都市は詳細まで見えるので、一瞬にして世界旅行してきたような気分ですね。北朝鮮とかすごい山奥なのにやたらと詳しい地域があったり・・。きっとアメリカの衛星が何か怪しいことやってないか監視してるんだろうなぁ・・(笑)
わぁぷさんからのトラックバックで知ったんですが、地図ソフトで有名なアルプス社が新しい実験サービス「ALPSLAB slide」をはじめたようです。

Google Mapsと同じようにマウスでスムーズにスクロールができ、縮尺の変更も自在にできます。これも今流行りのAjaxを使った技術なんでしょうね。Google Mapsみたいにマーカーを表示させたりはできませんが、標準でルート再生機能を持っていて、登録したルートに沿って自動的に地図がスクロールします。しかも何とGPSログからの変換ツールまで用意されているのです! これは業界では初の試みではないでしょうか?

使ってみて驚いたのは、設置が非常に簡単なこと。Google MapsみたいにAPIキーを取得する必要もなく、タグをコピペするだけで誰でも簡単に設置できてしまいます。JavaScriptの知識も一切要りません。めちゃくちゃお手軽です。しかもブログにも貼り付けられます!

Google Mapsと違ってお手軽な分、機能はかなり制限されるようですね。まず地図のサイズは固定で変えられません。マーカーも表示できないし、トラックを描画することもできません。できるのはある1点を表示させることと、ルートに沿ってアニメーションさせることだけです。いずれは機能強化されていくものと思いますが、今のところはGoogle Mapsの強力さには到底かなわないですね。Google Mapsは何と言ってもAPIが公開されているので、やろうと思えば何でもできてしまう自由度があります。もちろんルートに沿ったアニメーションも可能です。しかし今後地図サービス会社が同様のサービスに参入して過当競争の時代に入ることは間違いないだろうと思います。

こうなるとブログにも対応してくれという声が必ず出てくるでしょうね・・(^_^; まあこれは不可能ではないんですが、テンプレートを直接編集できることが必須なので、どんなブログでも利用できるというわけではありません。
ちょっと調べ物をするためネットを検索していたら、こんなサイトを見つけた。
http://www.ksgmap.jp/

GoogleMapsAPIを簡単に利用できるようにするための汎用JavaScript集みたいですね。GoogleMapsEditorもそうだけど、GoogleMapsAPIはプログラミング初心者には敷居が高いため、一般の人でも自分のサイトにGoogleMapsを組み込めるようにこうしたツール類はそれなりに需要があるのだろう。GoogleMapsはますます注目が高まっており、今後さらにいろいろな分野で応用されていくものと思われる。

現在開発中のツールも大方の機能は完成していて、一応当初の目的は達成できるようになった。あとはユーザーインターフェースをいかに作り込むかである。GoogleMapsEditorとの根本的な違いは、カシミールと連携して使うことを前提にしていることだ。したがってカシミールがなければまったく意味をなさないソフトである。GoogleMapsEditorは地図上のポイントを一つ一つ自分で入力していくのが基本的な使い方だ。一応CSV経由でデータを取り込むこともできるが、カシミールから変換するのは非常に面倒だ。したがってタウン情報などを登録するには向いているが、自転車の走行記録をプロットするような目的にはまったく向いていないのだ。

現在開発中のツールはこの点でGoogleMapsEditorとは方向性が異なるものである。入力はすべてカシミールが出力するファイルを通して行うため、データの入力機能というものは持たない。地点を説明するための補足情報を付加して、トラックログとともに表示させるのが主な目的だ。そのため汎用性は低いが、トラックログを表示するという目的だけに限れば他のソフトより圧倒的に簡単にできるはずである。

このツールを利用する主なターゲットはサイクリストであるが、非常にマイナーな分野であるため需要がどれだけあるかは未知数である。しかしトラックを表示したいという要望は他の分野でもあると思われる。たとえば登山でもGPSとカシミール利用者が多いと思われるが、サイクリングに比べれば圧倒的にメジャーな趣味であるから最大のターゲットになると思われる。

最初に紹介したツールもフリーソフトであるが、現在開発中のツールも当然フリーソフトにすべきだろう。インターネット上のものは何でもタダというのが当たり前になっているから、こういうものはシェアウェアにしたら誰も使わないことはわかりきっている。とにかく使ってもらわないことには話にならない。上記のサイトではツールは無料で使ってもらうが、コンサルティングやカスタマイズで利益を得るという考え方のようだ。まあネット上で利用するツールとしてはそういうビジネスモデルが妥当だろう。

完成度を高めていくといくらでも時間がかかるから、それではいつまで経っても公開できない。とにかく早く使いたい人が多いだろうから(自分もだけど)、ある程度基本的な機能ができた時点で公開するつもりである。あんまり未完成なものを出すもの気が引けるが、まあバグ取りに協力してもらうということで・・。(^_^; 同時に改善要望も聞きながら少しずつ完成度を高めていきたいと思っている。ソフト開発に終わりはないのだ。

あと一つ問題なのは、名称をどうするか?ということ。まだ決まってないんだよなぁ・・。
最近、「緯度 経度 距離」などのキーワードで検索されているケースが非常に多いので、地図上での簡単な距離の求め方を説明しておきましょう。ここで説明するのは地球を完全な球体と仮定した場合であり、厳密ではありませんが、通常の使用では十分な精度が得られるものです。単純な三角関数だけで計算できるので、CGIなどのプログラムに組み込むのも容易です。

【注意】ここで紹介する方法は経線の間隔が近似的に平行であると見なせる場合に限り有効です。たとえばGPSログのポイント間の距離など、ごく小さい範囲での移動に適用されます。東京〜ロサンゼルス間の距離と方位を求めるなど、大きな範囲の移動には適用できません。その場合は球面三角法を用いて計算する必要があります。



距離を求めたい2点の座標をそれぞれ(λ1,φ1), (λ2,φ2)とします。ここでλは経度、φは緯度を表します。また2点間の座標の変位を(Δλ, Δφ)とします。

まず、緯度方向の変位Δyについては地球を完全な球体と仮定すれば、緯度の変化に対する円弧の長さで簡単に計算できます。ここで地球の半径として赤道半径A=6378137mを使用すると、Δy = AΔφとなります。なお角度は度ではなくラジアンに変換しなければなりません。1度=π/180ラジアンです。

一方、経度方向の変化Δxについても同様に経度の変化に対する円弧の長さで計算できますが、この場合、緯度によって円の半径が変化することを考えなければなりません。緯線に沿って地球をスライスしたとすると、その切り口の半径は緯度の余弦に比例します。したがって、Δx = AΔλcosφ1で求められます。ここで代表点としてφ1を採用しましたが、φ2としても実用上は同じことです。

ΔxとΔyが求まれば、2点間の距離Lは三平方の定理により、それぞれの2乗の和の平方根で求められます。

また方位角θはΔy/Δxの逆正接で求めることができます。このとき方位角の基準は真東の方角を0度とします。

実際には地球は完全な球体ではないため、厳密に言うと誤差が生じますが、赤道半径と極半径の差は21km程度であるため、日本国内で使用する程度であればほとんど問題になりません。もう少し厳密にやりたいのなら、日本付近における地球の半径を回転楕円体モデルから計算すればできるはずです。また図では経線は平行であるとして長方形を描きましたが、実際は経線は極に向かって収束するため、台形になります。しかし、ごく短い距離で使うのであれば長方形と考えてもまったく問題はないわけです。厳密に計算した結果と比較してみると、1分あたりの距離で誤差はせいぜい5〜6m程度に過ぎませんでした。割合から言うと0.3パーセント程度ですから、十分実用になる精度と言えるでしょう。

座標変換とかえらいめんどくさいことをやりましたけど、ポイントを間引く程度の使い方であればこれで何の問題もないのでした。(^_^;
ヒマになったのでGoogleMapsAPIをちょっと研究してみた。Googleのサイトに英語だけど簡単なサンプルがあるし、一部和訳されたリファレンスも存在している。

それらのサイトを見てみると、GoogleMapsAPIはとても簡単に使えることがわかった。要するにGMapクラスで地図を生成し、GPolylineクラスで軌跡を定義して、addOverlay()メソッドで重ね書きするだけのことだ。やってみるととても簡単。GoogleMapsEditorの作者に使用許可をもらおうかと思っていたが、そんなことをするまでもなくオリジナルで作った方が早い。やっぱり著作権がらみの問題はない方がいいし・・。

マーカーをクリックすると説明が吹き出しで表示されるのは、GMarkerクラスのopenInfoWindowHtml()メソッドを使えば簡単にできる。引数にはHTMLで記述された文字列を渡せばいいだけ。

ただこういうのはオブジェクト指向の概念がわかってない人にはすごくわかりにくいと思う。マーカーをクリックすると説明が表示されるというのは具体的にはどういう仕組みで実現されているのかちょっと解説してみよう。以下はマーカーを一つ表示し、クリックするとメッセージが表示されるサンプルの主要部分だ。

var map = new GMap(document.getElementById("map"));

var marker = new GMarker(new GPoint(135.832987, 34.684464));
map.addOverlay(marker);

GEvent.addListener(marker, "click", function() {
  var msg = "ここに説明文を記述する";
  marker.openInfoWindowHtml(msg);
});

最初の行では地図を表すインスタンスを生成する。具体的にはdivタグのid="map"で指定された地図表示領域をgetElementById()メソッドで取得してGMapクラスのコンストラクタに渡している。クラスとインスタンスはちょうど設計図と製品の関係であって、具体的な「もの」を表すのがインスタンスなのだ。もっと平たく言えば、たこ焼きの「型」と「たこ焼き」と言うべきか? 一つのクラスからインスタンスはいくらでも作れるのであって、それを区別するために変数を使って一つ一つに名前を付ける。"var"は変数の宣言文である。ここでは"map"という変数が一つの地図を表すインスタンスである。なおクラスからインスタンスを作り出すものがnew演算子とコンストラクタである。コンストラクタには適当な引数を与えることにより、インスタンスの初期化を行う。

その次の行では座標をGPointクラスのインスタンスで与えて、マーカーを一つ生成している。引数は経度と緯度の順だ。これは何となくわかるだろう。ここでマーカーのインスタンスは"marker"という変数で表される。もちろん、マーカーがたくさんあるときは変数名で区別しなければならない。

次の行のmap.addOverlay(marker)でGMapクラスに用意されているaddOverlay()メソッドを呼び出し、先ほど生成したマーカーを地図上に重ね書き(オーバーレイ)する。ここでピリオドの後ろにaddOverlay()が来ることに戸惑う人が多いだろう。ここがCやBasicなどの手続き型言語に慣れている人には取っつきにくい部分だ。オブジェクト指向の考え方では、すべてのメソッド(つまり手続き)はオブジェクト自身に内包されているのであって、そのメソッドを呼び出すインスタンスを明示しなければならない。ピリオドはどのインスタンスに対してメソッドを呼び出すのかを表し、対象となるインスタンスが必ずピリオドの左側に来る。日本語ではピリオドを「〜に対して」と読み替えるとわかりやすいだろう。

そして一番わかりにくいのが最後のGEvent.addListener()メソッドである。まずこれはクラスそのものに属するメソッドであるため、対象となるインスタンスが存在しない。したがってクラス名そのものにピリオドを付けて呼び出すのである。そしてリスナーとは、何らかのイベント(つまりクリックなど)に対してどのような反応をするべきかを定義する部分である。この場合は、マーカーをクリックされたらメッセージを表示するという動作をしたいわけだ。引数として与えなければならないのは、対象となるインスタンス、イベントの種類、実行すべき関数の3つである。この場合、"marker"というインスタンスに対して"click"されたときに、function()で定義される関数が実行されるわけだ。本来3つめの引数にはあらかじめ定義された関数名を記述するのだが、ここでは無名の関数の定義を同時にやってしまっていると考えればよい。Javaで言うところの匿名クラスと非常によく似た考え方である。この無名関数の中で"marker"インスタンスに対してopenInfoWindowHtml()メソッドを呼び出すことにより、説明を吹き出し表示させるわけだ。メソッドの引数には変数msgに代入したHTML文を渡している。

とりあえず今日はGoogleMaps形式でトラックログを出力させ、軌跡を表示するところまでうまく行った。あとはウェイポイントの情報を読み込んでマーカーを表示させ、必要な情報を付加する部分を作ればよい。操作性としてはGoogleMapsEditorと似たようなものになるだろう。