GPS軌跡データからウォーキングの歩行距離を求めたい。GPS軌跡データから点をつなぎ合わせた折れ線の長さが歩行距離となるが、 スマホやタブレットのGPS軌跡は揺れ動いており、地図では、どの道を歩いたことはわかるが、 折れ線の長さは実際の歩行距離よりかなり大きな値となる。
このように誤差が大きいGPS軌跡を地図上の道路に沿った位置に置き換えるのが Map Matching である。
途中で公園によって休憩することもある。通常、道路から公園への入り口は何か所かあり、 地図データにはこの入口データがないこともある。また、接近して入口が複数あった場合、どの入口を通ったまで特定するのは難しい。
公園内を歩いた場合、公園内の歩道が地図データになければ Map Matching はできない。
地図データでは交差点などは特定できるが、直線道路で折り返したり、入口データのない公園を横切って別の道路に出たりした場合、 Map Matching も簡単ではない。
Map Matching技術自体、そう簡単なものではないし、精度高く GPS軌跡データを補正するのは容易ではない。 直ちに Map Matching に取り組むのでなく、当面は、ネット記事リストを作っておく程度にする。
ウォーキングやハイキングの計画をたてたとき、予定ルートデータを予め、スマホに設定して置き、ナビゲーションに使いたい。 始点から終点への最短経路というわけではないので、地図上の交差点などをクリック(タップ)することにより、予定ルートを設定したい。
ルート設定で手作業で Map Matching を行うのには時間はかかるが、プログラム的には比較的に簡単であり、精度は高い。
日常的に GPS軌跡データを補正したいわけではなく、たまに、平均歩行速度や平均歩幅などをチェックしたいだけであるので、 ルート設定プログラムを作成したい。
Google Mapには豊富なルート設定機能がある[2]。地点をクリック(スマホではタップ)して、 経路を決めると、始点から終点までの距離および高低差グラフが表示される。
Google Mapは機能が豊富なため、使うには慣れが必要であり、実際にこの機能を使った経験はない。
まずは、この機能を独自の仕様で実装してみよう。
メニューでルート設定を選ぶと、ルート設定モードに変わり、最初のクリック(/タップ)した場所が始点となる。 次々とクリックすることにより経路を設定する。
設定終了ボタンはルート設定モードに変わった時点で表示しておく。一切クリックせず、終了ボタンを押した場合および 始点だけで、終了ボタンを押した場合は、ルート設定はキャンセル終了となる。ルート設定後終了ボタンを押した場合、 最後のクリック点が終点となり、ルート名の設定を求める。ここでキャンセルすることもできるようにする。
高低差グラフは次々地点を入力している段階から表示しておく。
ルートの編集機能も用意する。
GPS軌跡上の点と設定ルート上の点を結ぶ付ける(時刻をコピーする)機能(手動Map Matching)を用意する。 これにより、GPS軌跡データの補正速度を求めることができる。
GUIとしては AlertDialog を使う[3]か、レイアウトactivity_main.xml にボタン等を配置して置く方法がある。
メニューでルート設定のON/OFFを決め、ルート名は通し番号とするのがプログラムは一番スリムである。
public static class SetRouteDialogFragment extends DialogFragment { @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { // Use the Builder class for convenient dialog construction AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setMessage("ルート設定") .setPositiveButton("開始", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // START! } }) .setNegativeButton("キャンセル", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // User cancelled the dialog } }); // Create the AlertDialog object and return it return builder.create(); } }
ルート設定の開始/終了はメニューのチェック ON/OFF とする。 ON の場合、onTouchEvent で MotionEvent.ACTION_UP でクリック(orタップ)された座標をキャッチして、逐次、リストに追加する。 そこまでの設定ルートを地図画面に表示する。
座標系はいずれ一元化する方が望ましいが、とりあえず、リストに追加する座標は値範囲を 0~230 とする世界XY平面座標とする。
最初のプログラムを以下に示す。Androidタブレットで Bluetoothマウスを使えば、精度高く、ルート設定ができることを確認した。
public boolean onTouchEvent(MotionEvent motionEvent) { mScaleGestureDetector.onTouchEvent(motionEvent); int eX = (int) motionEvent.getX(); int eY = (int) motionEvent.getY(); switch (motionEvent.getAction()) { case MotionEvent.ACTION_UP: if (setRoute) { double xt = (eX + (CX - W / 2.0)) / PX; double yt = (eY + (CY - H / 2.0)) / PX; double x = xt * GPSLog.B30 / (1 << zoom); // zoom 0 に換算して double y = yt * GPSLog.B30 / (1 << zoom); // 2^30 をかける points.add(new Point((int)x, (int)y)); break; } } } void drawMyRoute(Canvas canvas, List<Point> points) { paint.setColor(Color.BLACK); paint.setStrokeWidth(2.0f * Scale); double f = 1.0 / (1 << (30 - zoom)); float xb=-1, yb=-1; for (Point p : points) { float xe = getX(p.x, f); float ye = getY(p.y, f); if (xb >= 0) { canvas.drawLine(xb, yb, xe, ye, paint); } xb = xe; yb = ye; } }
これまでスマホとパソコン間のファイル転送は、スマホ側を FTPサーバー(ファイルマネージャー+)として、 パソコン側を FFFTP(FTPクライアント) とした。
パソコンにスマホとタブレットの地図アプリの全ファイルを置くことにすれば、 ファイルマネージャー+と FFFTP でパソコンを介してスマホとタブレット間のファイル転送も可能である。
バックアップのためにも、スマホ、タブレット、PCのファイル同期を簡単に行えるようにしたい。 このファイル同期機能により、タブレットで作成したルートファイルをスマホで利用したり、 スマホのGPSログファイルをタブレットで読み込めるようにしたい。
PCは介さず、タブレットとスマホ間のファイル同期でもよい。 少数のファイルならば、同期方法はいくつかあるが、FFFTP のミラーリングのように、ディレクトリ毎の同期をとりたい。