Jpeg画像ファイルには位置情報、撮影日時、サムネイル画像、方角(縦向き、横向き等)など様々な情報が埋め込まれている。 位置情報は含めないようにもできる。
自作地図アプリは間もなく10年になり、この間、10インチWindowsタブレット、7インチWindowsタブレット、 Androidスマホと機種は変わった。サムネイル画像は含んでいないものもある。 ファイル名に日時を含んでおり、属性には日時が含まれていないものもある。
また、位置情報を含めなかった時期もある。地図アプリが動いていた場合には、GPSログデータから、 撮影位置を算出することができる。
最近撮った写真については、スマホのフォトアプリで見れば事足りる。
何年か前に撮った写真については、地図に撮影位置をアイコンを表示して、それをタップすると表示される方が使いやすい。場合によっては、サムネイル画像を地図に表示する案もある。
Jpeg画像ファイル自体はWindowsタブレット時代とスマホ時代のものは異なるフォルダに置いておく、 Sqliteデータベースでファイルパスや属性を一元管理したい。
表示回数も記録しておき、お気に入りの写真は地図上で目立つようにしたい。
Windowsタブレットの時には、サムネイル画像は使用していなかったが、 少なくとも、管理データベースには含めておきたい。
次のように、テーブル photo を定義した場合、 自動的に rowid integer が primary key になるものと思われる。
厳密には id integer primary key autoincrement とは少し異なるところがあるようだ。
撮影日時は unix time に置き換えて管理する。実際上、同一秒はないと思うが、 もしあれば、秒をずらして、この unixtime を primary key にする案もある。
rowid や id (id integer primary key autoincrement) には意味がないため、 写真の識別子にふさわしくない。
create table photo ( path text not null, unixtime integer not null, lon7 integer, lat7 integer, thumbnail blob, num_refs integer not null); create index lon_ix on photo(lon7); create index lat_ix on photo(lat7);
画面範囲内の撮影位置の全てを「+」マークで表示した結果を下に示す。
低ズームでは多くの重なりがあるが、高ズームでは重なりがなくなる。 Windows版では、いずれかの+マークをタップすると、 その写真を表示して、時刻上その前後の写真も表示できるようにしていた。
Android版では、最終的には同じ方法とするかもしれないが、まずは、よりよい方法がないか検討したい。
撮影位置がたくさんな場合、どれをタップしたのかわからないので、画面下部にサムネイル画像を最大5枚ほど 並べる。サムネイル画像をタップすると、その写真を表示する。取り消しボタンも表示して、選択をやり直せるように しておく。この方がWindows版よりプログラムは簡単になる。
地図や写真はパソコンでも見たい。パソコン上の地図アプリはAndroid版よりも限定的なものでよい。
Windows版地図アプリは C# で開発した。Javaに置き換えても Android Javaとは異なるが、C#よりは近くなる。
OSM地図のレンダリングは Androidタブレットかスマホで行い、HTTPサーバとする。
レンダリングでは極座標からタイル上の座標へに変換が必要になるが、 撮影位置はタイル毎のビットマップ画像に重ね書きするのではなく、 タイル画像を表示した後の地図画面(canvas)に描画する。
このため、レンダリングとは少し異なり、極座標から画面座標への変換が必要となる。
レンダリングの場合、次のようにしている。render.x、render.y はタイル座標、PX はタイルの画素数である。
Lib.lon2X、Lib.lat2Y は極座標から世界XY平面座標への変換メソッドである。
float x = (float)(Lib.lon2X(lon, zoom) - render.x) * PX; float y = (float)(Lib.lat2Y(lat, zoom) - render.y) * PX;
画面中心の画素単位の世界XY平面座標を (CX, CY)、地図画面サイズを W x H としているので、 画面原点(左上隅)のタイル座標は
float x0 = (CX - W/2f) / PX; // 画面左端タイルX座標 float y0 = (CY - H/2f) / PX;となる。render.x, render.y を x0, y0 に置き換えると、極座標から画面座標への変換となる。
float x = (float)Lib.lon2X(lon, zoom) * PX - (CX - W/2f); float y = (float)Lib.lat2Y(lat, zoom) * PX - (CY - H/2f);