プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

オフラインでの地図表示と経路検索 (OpenStreetMap と Graphhopper)

ある android アプリを作ろうと思い立ったのですが、そのためには、オフラインでの地図表示と経路検索を行う必要が出てきました。 当初は、Google Map での実現を考えたのですが、オフライン地図に対応していない地域もあるため、あきらめました。

で、次にあがった候補が、 OpenStreetMap です。OSM の Wiki を調べてみるとオフライン動作についての情報がまとまったページがありました。

ここを見ると、経路検索をオフラインで行えるものとして、 Graphhopper というライブラリが使えそうです。 日本語の情報もあまりないようなので、Graphhopper のデモapkを動かすところまで試したことをまとめておきます。

作業環境は以下の通りです。

  • Windows 10 Pro, 1607, 64bit なお、Bash on Ubuntu on Windows (以下 BoW) も併用してます
  • Android Studio
  • Nexus 5 (6.0.1)

Graphhopperの準備

Graphhopper を見ると商用サービスのように思えますが、オープンソース版があります。 このページのリンクをたどると、Github のプロジェクトページにたどり着きます。

github.com

ここの『For Mobile Apps』から、androidでのデモの説明ページに行きます。

https://github.com/graphhopper/graphhopper/blob/master/docs/android/index.md

android版のデモapkはgraphhopperのリポジトリに含まれているようです。 さて、デモを動かすには、デモ版のソースコードと各種データが必要になりますが、この説明ページの内容が少しわかりにくいので、自分の行った手順とまとめておきます。

まずは、Maps のセクションを参考に、デモapkに必要なデータを準備します。

  1. OpenStreetMap の raw データをダウンロードします。今回は、三重県を含むデータで試したので、kinki のデータを落としました。 なお、いろいろと書いてありますがよくわからない面もあったので、標準的と思われる、 kansai-latest.osm.pbf というファイルをダウンロードしました。
  2. map データを落とします。ダウンロードサイトから japan.map をダウンロードしました。なお、mapデータとはあとでも出てくる mapsforge という地図表示ライブラリで使うデータになります。

以下の作業は、Graphhopperのリポジトリをcloneしてから行います。なお、この部分は BoW 上で作業しています。また、シェルスクリプトを動作させるために、java と zip/unzip を BoW 上でインストールしています。

1. git clone を実行したディレクトリに kansai-latest.osm.pbf および japan.map ファイルがあるものとします

$ git clone git://github.com/graphhopper/graphhopper.git graphhopper

2. kansai-latest.osm-gh というディレクトリが作成されて、中に必要なデータが作成されます

$ cd graphhopper
$ ./graphhopper.sh import ../kansai-latest.osm.pbf

3. kansai-latest.osm-gh ディレクトリ内のすべてのファイル(edges, geometry など)を、androidの外部ストレージ領域にコピーします。

C:\Users\mor> adb push kansai-latest.osm-gh/edges /sdcard/Download/graphhopper/maps/kansai-gh/

この際、コピー先に kansai-gh (地域名-gh)のフォルダを用意しておきます。

4. japan.map もandroidの外部ストレージにコピーします

C:\Users\mor> adb push japan.map /sdcard/Download/graphhopper/maps/kansai-gh/

5. japan map を kansai.map にリネームします

C:\Users\mor> adb shell
$ cd /sdcard/Download/graphhopper/maps/kansai-gh/
$ mv japan.map kansai.map

ここまでできれば、データの準備は完了です。

なお、説明ページではzip圧縮したファイルを使うこともできるとあったので、androidへのコピー処理が簡単にできるかと思い、試したのですが、最終的なデモ動作がうまくいきませんでした。

デモapkプロジェクトの読み込み

以下のページに Android Studio でのデモapkを動作させる手順があります。

https://github.com/graphhopper/graphhopper/blob/master/docs/android/android-studio-setup.md

ただ、自分の環境だと、Android Studio が Windows 上にあるので、 BoW 上の先ほどcloneしたリポジトリとは別に、graphhopperのリポジトリをcloneしておきます。 また、リポジトリのブランチをmasterではなく、 0.8.2 のタグに切り替えておきます。

あとは、説明ページと同様に、 graphhopper/android をオープンするプロジェクトとして指定すれば完了です。

サンプルapkの動作

オープンしたプロジェクトを実行します。正常に実行できると下記の様な画面が表示されると思います。

f:id:junichim:20170515005829p:plain:w300

Local のラベルの隣のスピナーで、オフラインデータとして設定した地域名(今回の場合は kansai)を選択して、OKボタンを押すと地図が表示されます (ただ、最初に表示される場所は、海の中のため、適当にズームアウトしないと陸地が表示されません)。なお、地図で日本を表示しようとした場合、後述の対策が必要です。

地図が表示されれば、ロングタップで経路を求める始点を指定します。

f:id:junichim:20170515005844p:plain:w300

赤線で囲んだ緑の旗(伊勢神宮の外宮前あたりを指しています)が始点を表しています。なお、この際、親切にメッセージを表示したり、音やバイブレーションで設定完了を教えてくれないので注意深く画面を見てください。始点が表示されていれば、設定できた、という感じです。

経路を求める終点は同じく、ロングタップで設定します。 終点を設定すると自動的に経路を求めて表示します。下記画面内の赤線で囲った赤の旗が終点、ちょっと見にくいですが37という数字が振られた道路を経由している緑の点線が経路です。

f:id:junichim:20170515005857p:plain:w300

トーストでも情報を出してくれますが、消えるのが早すぎて何を出しているのか正直分かりません(距離ぐらいはあったかな?)。

次の経路を求めたければ、地図上のどこかの地点をロングタップして、再度始点・終点を指定することになります。 一応、これで、オフラインの動作ができているということになりそうです。

なお、このデモapkの他の動作は次のようになっているようです。 Remoteスピナーから、地域名を選択して『downloding』ボタンを押すと、該当地域の地図データおよび経路データをダウンロードしてくれます。 で、ダウンロード後のデータは、ローカルに保存され、次回起動からはローカルデータとしてアクセスできます。 (デモだけなら、データの準備いらないんじゃ・・・)

注意

実は、デモapkそのままでは、日本のデータ(japan.map)が対象の場合、正しく日本の地図が表示されません。

f:id:junichim:20170515005909p:plain:w300

Android Studio につないで実行してみると、どうも地図データのブロックサイズが制限オーバーの様です。

f:id:junichim:20170515003734p:plain

調べてみると、このGraphhopperのデモアプリでは、地図の表示に mapsforge というライブラリを利用しているようなのですが、そのライブラリ側のデータ読み込み時の制限に引っかかっているようです。 ネットにも類似の議論がありました。

github.com

上記の記事からもわかるように、動的に読み込みバッファサイズを変更できるようなので、その部分だけ手直ししてみます。 具体的には、デモapkの MainActivity.java の 346行目付近に MapFile を生成する処理があったので、その直前にバッファサイズを変更するメソッドを追加してみました。

    void loadMap(File areaFolder) {
        logUser("loading map");
        ReadBuffer.setMaximumBufferSize(7000000); // for test
        MapDataStore mapDataStore = new MapFile(new File(areaFolder, currentArea + ".map"));

なお、指定のバッファサイズは、上記ログ画面で出力されているサイズをカバーするように適当に設定しています。

この状態で試すと問題なく表示できました。 ただし、レンダリングに結構時間がかかっているので、テスト時にはご注意ください。

まとめ

今回試してみた印象としては、

  • オフラインでの地図表示、経路検索はできそう
  • 経路検索の条件指定などは詳しく調べる必要がある
  • 地図のレンダリングは思っていたより遅い(端末のせいか?)
  • 地図データのセットアップ方法を考える必要がありそう

という感じでした。必要に応じて詳しく調べていきたいと思います。

第16回伊勢IT交流会を開催しました

2017年4月15日(土)に第16回伊勢IT交流会を開催しました。

伊勢IT交流会とは、伊勢志摩地域のIT系のエンジニアを始め、多くの方々がお互いに知り合って、雑談などをできる場が欲しいと思い、スタートしたものです。 概要をまとめたものを slideshare にあげてありますので、そちらもご参照ください。

www.slideshare.net

当日用の様子は参加者の方がまとめてくれたブログやfacebookページ等に記事があるので、そちらを見てもらうとして、ここでは主催者としての感想などを書いておきます。

開催しての感想

当初、1月に伊勢IT交流会を開催する予定でしたが、主催者の私がまさかのインフルエンザにかかったため、開催直前に中止となっていました。 今回はその仕切り直しという形でした。 とはいえ、日付が変わると、参加予定だった方が都合あわずに来れなくなったりして、申し訳なかったです。

最近は、参加者が10名前後で推移しており、一時期のようにやめたくなるほど誰も来ないというのはなくなりました(参加者の皆さま、ありがとうございます)。 今回も予定していた定員いっぱいになり、うれしい限りです。

参加者は伊勢近郊の方が多いのは当然として、最近、松阪付近からこられる方が増えてきました。 参加者の方とお話ししているときにも話題になっていたのですが、松阪でこういう会はないのか?という話も出ていました。 新しい勉強会なり交流会なりを立ち上げてみるのも面白いかもしれませんね > 松阪近郊の皆様

さて、LTの詳しい内容は、前述のブログ等をご覧いただくとして、最近のLTの傾向としては、なんとなくIoT絡みのものが増えてきているような印象があります。 たまたまなのかもしれませんが、やはり時流というのはあるんでしょうね。あと、この近辺って意外と電子機器系の会社とかがあるので、その影響もあるかもしれません(根拠なしの憶測ですが)。

まだ、当面はやっていこうと思っていますので、今後ともご参加のほどよろしくお願いします。

なお、次回は 2017年8月~10月 ぐらいのどこかでできればと思っていますので、告知を見かけて、都合が合えばお気軽にご参加ください。

EC2 t1.micro -> t2.nano への移行( Redmine 2.4.1 -> 3.3.2 へ移行) その1

開発時のサーバーとして今までは、 EC2 を使って、Subversion+Redmineを立ち上げていました。構築時の記事はこちらをご覧ください。

でも、最近はソースコード管理は Git (Bitbucket) ばかりだし、運用していた EC2 は t1.micro で、そろそろいろいろ新しくしたいなと思っておりました。 このサーバーは t1.micro のリザーブドインスタンスで運用していたのですが、昨年、無事にリザーブドインスタンスの期間が満了したので、新しいサーバーへ移行することにしました。

目をつけていたのは、運用費用を抑えられそうな t2.nano のインスタンス。自分の開発用のredmine動かすぐらいなら、これで十分じゃないかな?という目論見です。

ということで、 t1.micro 上の Redmine 2.4.1 を t2.nano 上の Redmine 3.3.2 へ移行したので、その際の作業を自分用のメモとしてまとめておきます。

一応、移行前後の情報をまとめておきます。

移行前 移行後
EC2インスタンス t1.micro t2.nano
仮想化種類 PV HVM
OS, Ubuntu 64bit 12.04 14.04
Redmine 2.4.1 3.3.2

※ 両方とも、Bitnamiのスタックを利用して立ち上げ

なお、移行前は Subversion のリポジトリも運用していましたが、最近は使ってないので、新サーバーでは Subversion は使わないことにします。

EC2 インスタンスの立ち上げ

というわけで、まずは t2.nano のインスタンスを立ち上げます。といっても、目的は Redmine を動かすことなので、前と同じく、 Bitnami を利用したいと思います。 リンク先ページで東京リージョンを選択して、amiのリンクをクリックするか、AWS のコンソールにログインして、インスタンスの立ち上げを選択して、コミュニティAMIで検索すれば、立ち上げたいAMIを見つけることができます。インスタンスは、財布にやさしい t2.nano を選択しておきます。

あとは、デフォルト設定で起動すれば、新しい環境が出来上がりです。 さて、ここからが、面倒そうなデータのマイグレーションになります。

Redmine 3.3.2 へマイグレーション

さて、新しいサーバー(とRedmine)が立ち上がったので、古いサーバー上の Redmine のデータを移行したいと思います。 幸い、Redmineのプラグインとかは一切入れていなかったので、比較的簡単に移行できると思います。

移行データの取得

古いサーバーにログインして、移行に必要なデータを取得しておきます。下記などに、データのバックアップ方法が載っているので、その通りにします。

データのバックアップ方法 — Redmine.JP

Bitnami のRedmineスタックの場合、 /opt/bitnami/apps/redmine/htdocs/ にファイルなどがあります。

bitnami@ip-10-134-200-227:~$ cd /opt/bitnami/apps/redmine/htdocs/
bitnami@ip-10-134-200-227:/opt/bitnami/apps/redmine/htdocs$ tar zcvf ~/files.tgz files/
bitnami@ip-10-134-200-227:/opt/bitnami/apps/redmine/htdocs$ cd
bitnami@ip-10-134-200-227:~$ 
bitnami@ip-10-134-200-227:~$ mysqldump -u bitnami -pxxxxxx bitnami_redmine > redmine.dump

こんな感じですね。mysqlへの接続時のユーザー名・パスワード・データベース名などは、

bitnami@ip-10-134-200-227:~$ cat /opt/bitnami/apps/htdocs/config/database.yml

で確認できます。

データのリストア

ネットを調べると、いろいろと移行手順が見つかりますが、最終的に、下記のドキュメントを参考に作業を行いました。

Bitnami Redmine Stack for AWS Cloud

準備として、先ほど取得したredmineのデータを新しいサーバーにアップロードしておきます。 次に、mysqlにログインします。

bitnami@ip-172-30-0-93:~$ mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
(略)

mysql> 

このときのパスワードが何かがちょっとわからなかったのですが、下記ページのデフォルトのアプリケーションパスワードと同じでした。

Redmine Cloud Hosting on AWS

既存のredmineのデータベースを削除して、もう一度作り直します。

mysql> drop database bitnami_redmine;
Query OK, 55 rows affected (2.01 sec)

mysql> create database bitnami_redmine;
Query OK, 1 row affected (0.00 sec)

mysql> grant all privileges on bitnami_redmine.* to 'bitnami'@'localhost' identified by 'データベースのパスワードを指定';
Query OK, 0 rows affected (0.00 sec)

mysql> 

ここで、パスワードは、 /opt/bitnami/apps/redmine/htdocs/config/database.yml 記載のものと一致させています。 自分で、パスワードを設定した場合は、 database.yml 側のパスワードを変更することになると思います(未確認)。

次に、データのインポートを行います。

bitnami@ip-172-30-0-93:~$ mysql -u root -p bitnami_redmine < redmine.dump 
Enter password: 
bitnami@ip-172-30-0-93:~$ 

上記のredmine.dumpが既存サーバーから落としたデータです。

bitnami@ip-172-30-0-93:~$ cd /opt/bitnami/apps/redmine/htdocs/
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs$ 
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs$ mv files/ files.org                                                                                          
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs$ sudo tar zxvf ~/files.tgz                                                                                    
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs$ 

次にマイグレーションを行うのですが、その前に、ログファイルの所有者を変更しておきます。というのも、デフォルトのままマイグレーションを行ったら、ログファイルへの書き込み権限がないというエラーで、マイグレーションが失敗したためです。

bitnami@ip-172-30-0-93:~$ cd /opt/bitnami/apps/redmine/htdocs/
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs$ cd log
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs/log$ ls -l
total 4
-rw-r--r-- 1 daemon daemon 2253 Apr  3 15:23 production.log
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs/log$ cp -p production.log production.log.org                                                                  
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs/log$ sudo chown bitnami production.log                                                                        
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs/log$ ls -l
total 8
-rw-r--r-- 1 bitnami daemon  2253 Apr  3 15:23 production.log
-rw-r--r-- 1 bitnami bitnami 2253 Apr  3 15:23 production.log.org
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs/log$ 

ここまで来たら、マイグレーションを行います。

bitnami@ip-172-30-0-93:~$ cd /opt/bitnami/apps/redmine/htdocs/
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake db:migrate RAILS_ENV=production

エラーが表示されなければOKだと思います。

あとは、キャッシュのクリアをして、

bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake tmp:cache:clear
bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs$ ruby bin/rake tmp:sessions:clear

Redmineをリスタートさせます。

bitnami@ip-172-30-0-93:/opt/bitnami/apps/redmine/htdocs$ cd ../../..
bitnami@ip-172-30-0-93:/opt/bitnami$ sudo ./ctlscript.sh restart

新サーバーへアクセスすると、既存のRedmineのユーザーでログインしたり、プロジェクトやチケットが見れればOKだと思います。

あとは、サーバーとしていろいろ設定を行いたいと思います。