GPSの位置情報から2地点間の距離を求める
2019年8月25日
GPSの位置情報から2地点間の距離を求める!
TCX形式のファイルには、距離情報が含まれているのでGPSの位置情報から計算する必要はありません。しかし、GPX形式のファイルの場合は距離情報が含まれていないのでGPSの位置情報から距離情報を計算する必要があります。今日はその話です。
いろいろなサンプルコードや計算のやり方自体はインターネットで検索すると
沢山でてきます。
検索キーワードは「GPXの距離計算方法」とか「ヒュベニの式」とかで検索すれば出てきます。
基本的な考え方は、地球を回転楕円体と仮定して、緯度と経度から計算するという物です
その際に必要になる、地球の長半径、扁平率などが必要になりますがそれらは幾つか異なる定義があって、それによって計算結果も変わってきます。さらに精度を高くするために実際に使われている計算式にいろいろ補正が加えられていたりします。
主な数値を定義している物として
- Bessel Ellipsoid
- Geodetic Reference system 1980
- World Geodetic System 1984
などが広く使われています。
今回のサービスの実装では?
今回のサービスの実装には距離の制度は余り重要ではなく、
あくまで移動速度を求めるために必要になるだけです。
同じ距離の算定によって導き出された速度情報を元に比較などをおこなって
実際の歩くペースの評価を行うため、
誤差が数パーセントであれば大きな問題にはなりません
従って、今回は「World Geodetic System 1984」の数値を使って算出しています。
- 長半径が6378137.0[m]
- 扁平率が1 / 298.257223563
という数値を比較しています。
実際に、この式によって求められた距離とTCXの距離情報と比較を幾つかの例で行いましたが、ござは数パーセント以内に収まっている事を確認しています。
計算自体は公式を当てはめるだけ
詳細は、サンプルのコードがいろいろなプログラミング言語で提供されているので
それを見れば簡単に実装できます。
入力情報は、2地点の緯度と経度、長半径、扁平率そして円周率です。
距離を計算する関数(メソッド)を作ってしまえば後は機械的に計算できます。
GPXの読み込みも距離計算ができれば簡単
TCXのデータが読み込めれば、GPXの読み込みも殆ど同じ要領でできます。
違うのは、XMLのタグの名前です。
あとは、位置情報を入手した後、一つ前の位置情報を使って距離情報を計算する事です。
これでほぼ同じ情報をTCXとGPXのファイルから読み込むことができます。
実際の読み込み方は?
GPXファイルの読み込みの例です。必要な情報が含まれているタグを調べて、そのタグの属性もしくは値を読み込めば良いだけです。TCXの場合属性に含まれるデータはありませんが、GPXの場合は、緯度と経度は「trkpt」の属性情報として含まれています。
それ以外は基本的に同じです。
// XMLのテキスト情報を取り込む
var xml = e.target.result;
// テキスト情報からXMLのタグの構造に従った情報にする
var xmlDoc = $.parseXML(xml);
var $xml = $(xmlDoc);
// 各時間のデータは、「trkpt」というタグの下にあるのでその情報を抽出
var $trackpoint = $xml.find("trkpt");
// 各レコードのデータを順番に抽出する
$trackpoint.each(function() {
var record = {};
// 時間情報
record['time'] = $(this).find('time').text();
// 時間情報をUNIX時間に変換(関数の呼び出し)
record['timestamp'] = current.get_timestamp(record['time']);
// 緯度情報
record['latitude'] = parseFloat($(this).attr('lat'));
// 経度情報
record['longitude'] = parseFloat($(this).attr('lon'));
// 標高
record['altitude'] = parseFloat($(this).find('ele').text());
// 心拍数(拡張のためのネームスペースを使っています)
record['hr'] = parseInt($(this).find(current.ext_ns + '\\:hr').text());
// 距離の計算
if (records.length === 0 ) {
// 最初のレコードは「0」
record['distance'] = 0;
record['deltaT'] = 0;
} else {
// 2つ目以降のレコードは前の位置情報を利用して計算(関数利用)
var cur = records.length;
var pre = records[cur - 1];
var loc = new Location();
loc.setLocation(record['latitude'],record['longitude']);
// Delta Distance
record['deltaD'] = loc.getDistance(pre['latitude'],pre['longitude'])
record['distance'] = pre['distance'] + record['deltaD'];
}
records.push(record);
});
var xml = e.target.result;
// テキスト情報からXMLのタグの構造に従った情報にする
var xmlDoc = $.parseXML(xml);
var $xml = $(xmlDoc);
// 各時間のデータは、「trkpt」というタグの下にあるのでその情報を抽出
var $trackpoint = $xml.find("trkpt");
// 各レコードのデータを順番に抽出する
$trackpoint.each(function() {
var record = {};
// 時間情報
record['time'] = $(this).find('time').text();
// 時間情報をUNIX時間に変換(関数の呼び出し)
record['timestamp'] = current.get_timestamp(record['time']);
// 緯度情報
record['latitude'] = parseFloat($(this).attr('lat'));
// 経度情報
record['longitude'] = parseFloat($(this).attr('lon'));
// 標高
record['altitude'] = parseFloat($(this).find('ele').text());
// 心拍数(拡張のためのネームスペースを使っています)
record['hr'] = parseInt($(this).find(current.ext_ns + '\\:hr').text());
// 距離の計算
if (records.length === 0 ) {
// 最初のレコードは「0」
record['distance'] = 0;
record['deltaT'] = 0;
} else {
// 2つ目以降のレコードは前の位置情報を利用して計算(関数利用)
var cur = records.length;
var pre = records[cur - 1];
var loc = new Location();
loc.setLocation(record['latitude'],record['longitude']);
// Delta Distance
record['deltaD'] = loc.getDistance(pre['latitude'],pre['longitude'])
record['distance'] = pre['distance'] + record['deltaD'];
}
records.push(record);
});
データの読み込み自体はこれで完了です。
既に、これを表示する例は紹介していますので、次回はWebサービスを作成する上で考える事について書く予定です!
既に、これを表示する例は紹介していますので、次回はWebサービスを作成する上で考える事について書く予定です!
コメント
コメントを投稿