かみやんの技術者ブログ

主にプログラムの話です

GPSログをGoogle Mapsに貼る(KML出力)

昨日のエントリで、GPSのアンタレス48を買って、NMEAのGPGGAをパースして、可視化したところまで作った訳だが、Google Mapsへ出力が間に合わなかったので、今日、さくっと作成。
Google Mapsのマイマップのインポートで、KMLファイルをアップロードすればGoogle Mapsの地図上に自分のGPSログの軌跡が表示できるらしい。KMLのフォーマットは、
http://bubble.atnifty.com/modules/bwiki/index.php?KML
を参考にした。で、KMLを出力して、昨日のエントリで、AibiUI上で「長方形に表示されるはずが、ひし形に表示された」と書いたが、緯度経度をパースするときに単位が度なのに100で割るのを忘れて、100倍の度になっていた。修正したところ、下記のような感じで長方形になった。

で、Google MapsKMLをアップロードしたところ、

なぜか、中央区ではなく、湘南に表示されました。うーむ。アンタレス48の出力は、WGS84にしたはずなんだが。。
もうちょっと設定を見直して再度GPSログを取る必要がありそうです。

2009/6/22 2:00追記:バグの原因がわかった

NMEAのGPGGAのフォーマットを読んで原因がわかりました。GPGGAでは、緯度経度がddmm.ssssという形で、ddが度、mm.ssssが分。分なので、60分で1度ですね。全然仕様を注意深く読んでいなくて、度だけだと思っていました。というわけで、
下記が、Google Mapsに重ね合わせたもの。ついでに自分が歩行した真の値も青い線で手動で書き入れました。

大通り側(北東側)が特に誤差が多いですね。こっち側は街路樹が多かったからかな。南西側で大きくずれているのは、ログ開始直後でまだGPSが安定していなかったためなので大した問題ではない。
ちなみに北東側は、片側2車線。両側4車線の道路。GPSでロボットをナビゲートしたら思いっきり車にひかれているところですね。

C#で、KMLファイルの出力ソース(Licence:BSD)

        //KML(Google Maps, Google Earthフォーマット)へ出力
        public void WriteAsKML(string placeMarkName,StreamWriter sw)
        {
            //ヘッダ部、線の色、線の太さを指定
            sw.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
                "<kml xmlns=\"http://earth.google.com/kml/2.0\">\r\n" +
                "<Document>\r\n" +
                "<Style id=\"Line\">\r\n" +
                "<LineStyle>\r\n" +
                "<color>ff0000ff</color>\r\n" +
                "<width>4</width>\r\n" +
                "</LineStyle>\r\n" +
                "</Style>\r\n" +
                "<Folder>\r\n" +
                "<Placemark>");
            //プレースマーク名の指定
            sw.WriteLine("<name>" + placeMarkName + "</name>");
            //線分のヘッダ
            sw.WriteLine("<styleUrl>#Line</styleUrl>\r\n" +
                "<LineString>\r\n" +
                "<extrude>1</extrude>\r\n" +
                "<tessellate>1</tessellate>\r\n" +
                "<altitudeMode>relativeToGround</altitudeMode>\r\n" +
                "<coordinates>");
            //線分のデータ
            foreach (GpsGGA gga in List) {
                sw.WriteLine(gga.Longitude + "," + gga.Latitude + "," + gga.Altitude + " ");
            }
            //フッタ
            sw.WriteLine("</coordinates>\r\n" +
                "</LineString>\r\n" +
                "</Placemark>\r\n" +
                "</Folder>\r\n" +
                "</Document>\r\n" +
                "</kml>\r\n");
        }