トップ地図システム基礎技術 > GPX入門
GPX入門

はじめに

自作地図システムでは、GPS(Global Positioning System)から得た情報は下に示すようなCSV(Comma Separated Value)ファイル形式としている(数値は架空の値)。 データは順に、時刻、経度、緯度、海抜である。日付別ファイルのため、日付はなく時刻のみ記録している。

GPSデータをOSMデータ編集ソフトJOSMなどに読み込んで、編集に使うには、 GPSデータファイルを GPX(GPS eXchange format: GPSデータ交換用ファイル形式、拡張子 .gpx)ファイルに変換する 必要がある。

10:07:56,138.504389,36.545304,65.4
10:07:57,138.504468,36.545318,47.4
……

GPXは XMLファイルであり、レコード 10:07:56,138.504389,36.545304,65.4 は 次のように表す。

      <trkpt lat="36.545304" lon="138.504389">
        <ele>65.4</ele>
        <time>2016-12-06T10:07:56Z</time>
      </trkpt>

取り敢えずは、CSVファイルをJOSMに取り込める必要最小限の GPXファイルに変換してみよう。 おそらく次の形でいいだろう。 metadataはなくてもいいのかも知れないし、さらにいくつかの項目が必要かもしれない。

<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1">
  <metadata>
    <bounds minlat="..." minlon="..." maxlat="..." maxlon="..."/>
  </metadata>
  <trk>
    <trkseg>
      <trkpt lat="36.545304" lon="138.504389">
        <ele>65.4</ele>
        <time>2016-12-06T10:07:56Z</time>
      </trkpt>
     [中略]
    </trkseg>
  </trk>
</gpx>

OSMデータ編集では metadata はなくてもよいことが分かった。

変換プログラム csv2gpx.cs の作成

まずは、引数で日付を指定するコマンドラインプログラムを作る。

GPS軌跡を道路等の描画に使う場合、必要なのは、緯度・経度のみであり、eleタグ、timeタグは要らないので、 なくても動作すると思うが、デフォルトでは、緯度・経度のみとして、-ele, -time オプション指定で、 海抜(標高)、日時を含められるようにしておこう。

XML用のクラスライブラリを使う案もあるが、シンプルな形式のため、何も使わず、直に書いてみよう。

試行錯誤の結果、次のプログラムに落ち着いた。

// csv2gpx.cs

using System;
using System.IO;
using System.Text;

public class CSV2GPX {

    static void Main(string[] args) {
        bool optEle = false;
        bool optTime = false;
        string date = null;
        int  hourFrom = 10;
        int  hourTo   = 15;

        for (int n = 0; n < args.Length; n++) {
            if (args[n] == "-ele") optEle = true;
            else if (args[n] == "-time") optTime = true;
            else { 
                date = args[n];
                if (n + 1 < args.Length) {  // ex. 10-13  
                    string[] hours = args[++n].Split('-');
                    hourFrom = int.Parse(hours[0]);
                    hourTo = int.Parse(hours[1]);
                }
            }
        }
        string pathCSV = "c:/gis/tablet/log/p" + date + ".csv";
        string pathGPX = "c:/gis/tablet/gpx/" + date + ".gpx";
        if (!File.Exists(pathCSV)) {
            Console.WriteLine(pathCSV + " は存在しません");
            return;
        }

        StreamWriter writer = new StreamWriter(pathGPX, false, Encoding.GetEncoding("utf-8"));
        writer.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

        writer.WriteLine("<gpx version=\"1.1\">");
        writer.WriteLine("  <trk>");
        writer.WriteLine("    <trkseg>");
        string[] positions = File.ReadAllText(pathCSV).Trim().Split('\n');
        for (int n = 0; n < positions.Length; n++) {
            string[] items = positions[n].Trim().Split(',');
            DateTime time = DateTime.ParseExact(date + " " + items[0],  // 20161207 12:34:56
                 "yyyyMMdd H:m:s", System.Globalization.CultureInfo.InvariantCulture);
            if (time.Hour < hourFrom || time.Hour >= hourTo) continue;
            writer.WriteLine("      <trkpt lat=\"" + items[2] + "\" lon=\"" + items[1] + "\">");
            if (optEle) writer.WriteLine("        <ele>" + items[3] + "</ele>");
            if (optTime) writer.WriteLine("        <time>" + time.ToString("u") + "</time>");
            writer.WriteLine("      </trkpt>");
        }
        writer.WriteLine("    </trkseg>");
        writer.WriteLine("  </trk>");
        writer.WriteLine("</gpx>");
        writer.Close();
    }

}

次のようにすれば、2016年12月3日の 12時から14時までのGPS軌跡を GPXファイルに出力できる。 これを OSM編集画面にドラッグ&ドロップすると、めでたく画面上にGPS軌跡が描画され、 これをなぞって、歩いた道を登録できた。

c:\gis>csv2gpx -time 20161203 12-14

結果的には、GPSデータの利用は想像以上に簡単であった。

最初にメタデータとして、緯度・経度の最小値・最大値を出力する必要がある場合、直接、ファイルに書きこまず、 まずは、StringBuilder に trk セクションデータを蓄えた方がいいだろう。

リファレンス

[1] GPX ファイルの例