Android地図アプリの改良(残り距離を表示する)

前回東海自然歩道に行ったときに、バスの発車時刻ぎりぎりになってしまい、残り距離が表示された方が便利だと思った。
alasixosaka.hatenablog.com
そこで、地図アプリに残り距離を表示するように改良を施した。

画像の準備

アプリの地図画面上に残り距離に応じて1㎞毎に数字を表示することにする。まずはそのための画像を準備する必要がある。
数字なので、①、②などの丸数字を表示すれば良い。そのために丸数字を画像データにして背景を削除したファイルを用意する必要がある。
以前矢印を作成したときにペイントでやっているはずだが、今回はうまく背景が削除できなかったので、別の方法で行った。ペイントの仕様が変更になっているのかもしれない。
今回はWordを利用して背景を削除した。
ます、丸数字をフォンドでなく画像データとして扱わなければならないので、ペイントで例えば「①」を描いて、これを四角形選択で選択し、Wordに貼り付ける。別にペイントでなくても画像データとしてコピーできるソフトなら何でもよい。Wordに貼り付けたら、Wordで「図の形式」→「背景の削除」とクリックして背景を削除する。このとき注意することは、丸数字のぎりぎりを選択すると背景がうまく認識できず背景の削除が失敗するので少し余白をもって選択して貼り付けておく。うまく背景が削除出来たら、図のところを右クリックして、「図として保存」を選択し、png形式で保存する。保存したデータは、Android Studioのプロジェクトのdrawableにコピペする。これで画像の準備は完了。

アプリのコード

アプリのコードを修正する箇所は3カ所。
まず、先ほど作成した残り距離を表す数字を表示するためのオフセットを設定する。

        if (Build.VERSION.SDK_INT <= 27){
            ofset = 0;
            ofset2 = 0;
        }else if (Build.VERSION.SDK_INT >= 28) {
            ofset = -40;
            ofset2 = -20;
        }

これは、Android9以降で位置がずれる問題に対処したもので、単なるofsetはその時の修正値。今回はofset2とした。数字の場合は表示するサイズが小さいのでオフセットを20くらいに設定すれば丁度良かった。
alasixosaka.hatenablog.com

次に、GPXファイルを解析するループの下に下記のコードを追加する。

        int roop = GPXs.size()/4;
        int rest = 1;
        if (Tdistance>=1){
            for (int i = roop-1; i>=0; i--){
                double dis = GPXs.get(i*4+2);
                if ((Tdistance-dis)>=rest){
                    lati = GPXs.get(i*4);
                    longi = GPXs.get(i*4+1);
                    LatLong latLong = new LatLong(lati,longi);
                    rdis.add(latLong);
                    rest++;
                    }
                if ((rest>10) || (rest>=Tdistance)){
                    break;
                }

            }
        }

何をやっているかというと、GPXファイルで読み込んだ値から残り距離を計算している。GPXファイルの読み込み値は、緯度、経度、通算距離、標高の順に各ポイントごとにarrayのGPXsに格納されている。コースの総距離は変数Tdistanceに入っている。そこで、Tdistanceと各ポイントの通算距離を比較して、残りが何㎞あるか計算できる。GPXsを逆順に読みだして、1㎞毎に残り距離がその距離を超えた時点の位置をarrayのrdisに追記して行っている。残り距離のカウントは変数rest。ちなみに、総距離が1㎞未満では処理を実行しないようにループの前にif文で判断している。また、総距離が10㎞未満の場合はrestが総距離Tdistanceを越えた時点でループを終了する。

そして、最後にPOIを表示させるループのおわりの部分、Log.i("MainActivity","ドキュメント終了");の下に次の文を挿入する。

            Log.i("MainActivity", "ドキュメント終了");
            Drawable drawable;
            Bitmap bitmap;
            Marker poimarker;
            int count =1;
            int rdismax = rdis.size();
            while((count<11)||(count<rdismax)) {
                switch (count) {
                    case 1:
                        drawable = getResources().getDrawable(R.drawable.one);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                    case 2:
                        drawable = getResources().getDrawable(R.drawable.two);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                    case 3:
                        drawable = getResources().getDrawable(R.drawable.tre);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                    case 4:
                        drawable = getResources().getDrawable(R.drawable.fou);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                    case 5:
                        drawable = getResources().getDrawable(R.drawable.fif);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                    case 6:
                        drawable = getResources().getDrawable(R.drawable.six);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                    case 7:
                        drawable = getResources().getDrawable(R.drawable.sev);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                    case 8:
                        drawable = getResources().getDrawable(R.drawable.eig);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                    case 9:
                        drawable = getResources().getDrawable(R.drawable.nin);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                    case 10:
                        drawable = getResources().getDrawable(R.drawable.ten);
                        bitmap = AndroidGraphicFactory.convertToBitmap(drawable);
                        poimarker = new Marker(rdis.get(count-1),bitmap,ofset2,ofset2);
                        markers.add(poimarker);
                        break;
                }
                //bitmap = AndroidGraphicFactory.convertToBitmap(drawable);

                count++;
            }

先ほどのGPXファイル解析のところで、各残り距離の位置をarray rdisに格納したが、それに基づいて各残り距離の数字を表示させている。countが残り距離を表す変数で、1から順にカウントアップしていき、10まで表示する。通算距離が10km未満の場合は、rdismaxが10未満になっているので、While文で判断して途中で処理を打ち切っている。本来こういう処理はループで処理したいところだが、画像ファイルが固有の名前を持っているのでベタな処理になっている。本当はもっとうまい方法があるに違いないのだが、とりあえず動けばいいやという感覚でプログラムを作っているのでみっともないけどこんなスクリプトになってしまいました。
実際にどうなるか確かめてみると、この間行った東海自然歩道のコース図にちゃんと残り距離が表示されるようになった。

残り距離が数字で表示された。

2022/5/6 追記
実際に使ってみたところ、途中でハングアップした様子。また、バックグラウンドでのGPS取得に問題がありそうだった。家に帰ってからスマホの画面を見ると、バックグラウンドでの位置情報取得の許可画面が表示されたままになっていたので、これが原因かもしれないのでしばらく様子を見ることにする。

2022/5/18 追記
プログラムに一部バグがあったので修正しました。
alasixosaka.hatenablog.com