GPSで遊ぶ (1)デビュー (2006.10.06/10.14加筆/10.23加筆)
ギャラリーのトップへもどる
GARMIN製GPSmap 60CSxを使い始めました(10/1)。試したことや 新しくわかったことを順次紹介していきます。

会社から近くの多摩川を渡って一週してきた時のログをシェープファイルに 変換し、ArcGISで表示しました。記録は10秒間隔で取っています。
西側の橋から川の南岸の途中まででは 経路がずいぶん蛇行しています。このときは、付属品のベルトクリップを 使って腰の高さに留めていたので、自分の体で天空を遮蔽してしまって いたのでしょう。でも経路の後半(京王線の鉄橋をくぐるあたりから)は 結構まっすぐに見えますので、遮蔽ばかりでなく衛星の配置も悪かった のでしょう。
測位の精度はまだきちんと評価していないのですが、室内に放置したとき のトラックポイントのばらつき具合からすると、5〜10m程度のようです。 SA解除の効果は絶大ですね。
GPS受信機をリュックの天蓋に入れて自転車で走ったときのログ (緑色の丸)との比較です。上図で赤枠で囲った範囲を拡大しています。 こちらは受信状態が良いせいか、ほぼ堤防上の 遊歩道に沿ってポイントが取れています(往復とも)。徒歩の記録(茶色)は 堤防下の道路に降りてしまっているように見えますが、実際には堤防の 上を歩いていました。
ところで、GPSに付属してくるマッピングソフト(MapSource)を使うと、 トラックポイントを強制的に道路中心線に合わせてしまうようです。堤防の 上下の道路に飛ぶので経路がかえってギザギザになってしまうという結果に なりました。
背景の地図には国土地理院の数値地図25000(地図画像) 「東京」の一部を使用しました。


今はまだUSB経由でログファイルを読み出しているので、「GARMIN形式」の フォーマットしか扱えません。この「GARMIN形式」とは、 トラックやウェイポイントのデータを交換する際の標準として利用するために 提案されている「GPX」のようです。詳しい解説が http://www.topografix.com/gpx.asp にあります。
GARMINではトラックポイントだけをGPXに書き出しているようです。ウェイポイントを 取得するには、シリアル接続でNMEA形式か「テキスト形式」を選択して読み出す プログラムを作成するなどが必要なのかもしれません。カシミールで読んで ファイルに落とせるのかも調べたいところです。

というわけで、現時点ではUSBで読み出したGPX形式のファイルをAvenueで シェープファイルに変換しています。以下にソースコードを掲載しますので、 ArcView3をお持ちの方はご自由にお使いください。ただし動作テストは GARMIN製GPSmap 60CSxのGPXファイルでしかやっていません。GPX汎用 ではなく、私が取得したログに出てくるタグだけを考慮したものなので、 他のメーカーのGPX形式のログや、GARMINの従来機で 作成したGPXファイル(そんなものがあるとして)では保証の限りでは ありませんのでご承知の上お使いください。
また、*.prjファイルも作っていません。(後からArcCatalogで付けています^^;) ArcGIS版を作るときには*.prjも出力しないと手間ですね。

以下、Avenueのコードです。

'trk2shape
'GPX形式のGPSログをシェープファイルに変換する(とりあえず版)
'
'2006/10/3 (C)雨宮 有/GIS Institute, Inc.
'2006/10/14
' カシミールからgpx形式で出力したトラックログに対応


inFN = FileDialog.Show("*.gpx","GPSログファイル(*.gpx)","ログファイルを選択")
logDate = inFN.GetBaseName.Left(inFN.GetBaseName.count - 4)
logPath = inFN.ReturnDir.AsString
p_name = logPath + "\" + logDate + "_p.dbf"
l_name = logPath + "\" + logDate + "_l.dbf"

'入力
inFile = LineFile.Make( inFN, #FILE_PERM_READ )

'出力1:ポイント
pointFTab = FTab.MakeNew( p_name.AsFileName, point )
pShape = pointFTab.FindField("Shape")
pID    = Field.Make("Point_ID",  #FIELD_LONG,    8, 0)
pTrkID = Field.Make("Track_ID",  #FIELD_CHAR,   20, 0 )
pLAT   = Field.Make("Latitude",  #FIELD_DOUBLE, 12, 6 )
pLON   = Field.Make("Longitude", #FIELD_DOUBLE, 12, 6 )
pELV   = Field.Make("Elevation", #FIELD_DOUBLE, 12, 3 )
pDT    = Field.Make("DateTime",  #FIELD_CHAR,   20, 0 )
pointFTab.AddFields({pID,pTrkID,pLAT,pLON,pELV,pDT})

'出力2:ライン
lineFTab  = FTab.MakeNew( l_name.AsFileName, polyline )
lShape = lineFTab.FindField("Shape")
lTrkID = Field.Make("Track_ID", #FIELD_CHAR, 20, 0 )
lineFTab.AddFields({lTrkID})

'ラインを構成するポイントのリスト
pList = {}
'二重引用符文字
quote = 34.AsChar
'ダミーの変数宣言
trackname = ""
tracknumber = 0
IsKashmir = FALSE

'ログの読み込みと変換
aLine = inFile.ReadElt '<?xml>
aLine = inFile.ReadElt '<gpx>
aLine = inFile.ReadElt.Trim '最初の<trk>

while (inFile.IsAtEnd.Not)
  if (aLine.Contains("Kashmir") AND IsKashmir.Not) then
  'カシミールから出力したgpxの場合はNumberフィールドを追加
    IsKashmir = true
    pNumber = Field.Make("Number", #FIELD_LONG, 10, 0)
    pointFTab.AddFields({pNumber})
    lNumber = Field.Make("Number", #FIELD_LONG, 10, 0)
    lineFTab.AddFields({lNumber})
  end
  
  if (aLine = "</gpx>") then 'ファイルをクローズして終了
    inFile.CLose
    pointFTab.SetEditable( false )
    lineFTab.SetEditable( false )
    exit
  end
  
  if (aLine.Contains("</trk>")) then 'ラインを書き出す
    lineRec = lineFTab.AddRecord
    if (pList.Count > 1) then
      lineFTab.SetValue( lShape, lineRec, polyline.Make({pList}) )
      lineFTab.SetValue( lTrkID, lineRec, trackname )
      if (IsKashmir) then
        lineFTab.SetValue( lNumber, lineRec, tracknumber )
      end
    end
    pList.Empty
  end

  if (aLine.Contains("<trk>")) then '新しいトラックの開始
    '</trkseg>が出るまで、ポイントの取得と出力を繰り返す
    aLine = inFile.ReadElt.Trim
    while (aLine.Contains("</trkseg>").Not)
      if (aLine.Contains("name")) then trackName = av.Run("extractValue",{aLine}) end
      if (aLine.Contains("number")) then trackNumber = av.Run("extractValue",{aLine}) end
      if (aLine.Contains("<trkpt")) then
        '座標値を読み取りポイントを作成
        pointRec = pointFTab.AddRecord
        pointFTab.SetValue( pTrkID, pointRec, trackname )
        pointFTab.SetValue( pID   , pointRec, pointRec )
        strArray = aLine.AsTokens(quote)
        vLat = strArray.Get(1).AsNumber
        vLon = strArray.Get(3).AsNumber
        pointFTab.SetValue( pLAT,   pointRec, vLat )
        pointFTab.SetValue( pLON,   pointRec, vLon )
        pointFTab.SetValue( pShape, pointRec, Point.Make(vLon,vLat) )
        pointFTab.SetValue( pTrkID, pointRec, trackname )
        if (IsKashmir) then
          pointFTab.SetValue( pNumber, pointRec, tracknumber )
        end
        'ラインを構成するポイントリストに追加
        pList.Add( vLon@vLat )
      end
      if (aLine.Contains("<ele>")) then
        elevation = av.Run("extractValue",{aLine})
        pointFTab.SetValue( pELV, pointRec, elevation)
      end
      if (aLine.Contains("<time>")) then
        datetime = av.Run("extractValue",{aLine})
        pointFTab.SetValue( pDT, pointRec, datetime)
      end
      aLine = inFile.ReadElt.Trim
    end '/while()
    '</trkseg>が出たらループを抜ける。次に読む行は</trk>になるはず。
  end

  aLine = inFile.ReadElt.Trim
end '/while(inFIle.IsAtEnd.Not)
こちらは上のメイン(gpx2shape)が呼んでいるサブルーチンです。
'extractValue
'gpx2shapeのサブルーチン
'2006/10/3
'<TAG_START>value<TAG_END>の構造をもつstringからvalueの部分を取り出して返す
'2006/10/14変更
'<TAG_START><![CDATA[value]]><TAG_END>の構造に対応(カシミールのgpx)

inStr = SELF.Get(0)

if (inStr.Contains("[")) then
  '"["記号の個数を数える
  nChar = 0
  for each n in 0..(inStr.Count-1)
    if(inStr.Middle(n,1) = "[") then nChar = nChar + 1 end
  end

  '最も内側の"["から左を削除
  for each n in 1..nChar
     inStr = inStr.Right( inStr.Count - (inStr.IndexOf("[")) -1 )
  end

  '最も内側の"]"から右を削除
  inStr = inStr.Left( inStr.IndexOf("]") )
  
else
  '<TAG_START>を除去
  inStr = inStr.Right( inStr.Count - (inStr.IndexOf(">")) -1 )
  '<TAG_END>を除去
  inStr = inStr.Left( inStr.IndexOf("<") )
end

return inStr
10/14加筆
GPS受信機から一旦カシミールでデータを読み取りgpx形式で保存した トラックデータにも対応しました。ソースコードは差し換えてあります。

10/23加筆
トラックセグメント中のトラックポイントが2点以上ないときは ラインにならないので(具体的には このような ログが取れた場合です)、トラックのラインを出力しないという 制御をかけています。 ですがラインシェープのレコードエントリーだけは作ってしまっているために、 結果としてNull Shapeのレコードができてしまい、ArcGISで表示しようと するとエラーすることがわかりました。近いうちに直します。
ギャラリーのトップへもどる

©2003-2006, 有限会社GISインスティテュート. All rights reserved.
〒183-0035 東京都府中市四谷3-49-18
電話・FAX:042-405-3901
gis-i@nifty.com