Android、iOS用にGDALをビルドする

GDALライブラリをAndroidiOS用にビルドする方法をこちらにまとめました。
github.com

これを利用してReactNative用のモジュールを作成したので、EcorisMapからGeospatial PDFを投影変換して読み書きできるようになりました。
位置座標付きのGeospatial PDFは、QGISから簡単に作成できます。


Geospatial PDFを読み書きできるEcorisMapは、近々公開予定です。

スマホでPMTilesを利用する

これはFOSS4G Advent Calendar 2023の記事です。

野外調査のための地図アプリ「EcorisMap」を作ってます。そのアプリでPMTilesを読み込めるようにしたので、それについてのお話です。

なぜPMTilesが必要か?

 調査で使う地図は、地理院地図のような下図に調査地点など必要なデータを重ねて持っていきます。下図は、地理院さんが全国レベルでタイル配信しており、ありがたくアプリでも利用させてもらっています。一方、調査地点などのデータは、自分で用意するもので、ファイルサイズも大きくならないのでGeoJSONにしてアプリにインポートすることで利用することができます。
 しかし、問題はそのどちらでもないデータで、ファイルサイズもある程度大きいもののタイル配信されていないデータです。例えば、植生図のポリゴンとか河川距離標のラインデータなどです。こういうデータは市町村〜県レベルの範囲で整備されており、そのままGeoJSONとしてインポートすると重くてアプリが動作しなくなってしまいます。調査に必要な範囲だけを切り出せば良いのですが、調査範囲が広い場合はそうもいきません。
 そういう場合はどうするかと言うと、ベクタデータをラスタ形式の地図タイルに変換します。手順としては、まず、ベクタデータをQGISで色を付けたりラベルを表示させたりしてスタイリングします。次にそれを一枚のGeoTIFFとして書き出します(地図は重ねずデータ以外は透過)そしてgdal2tilesで必要なズームレベルでタイルに切り出し、サーバーにアップします。この方法でデータを地図タイルとして読むことはできますが、ファイルの数とサイズが増えてしまいサーバーのストレージも消耗してしまいます。

PMTilesとは?

 そこでPMTilesの出番です。PMTilesとは、簡単に言うとズームレベルごとにベクタデータをベクタ形式のままタイル状に切り出して一つのファイルにまとめたものです。似たようなものにmbtilesと言うものがあるのですが、mbtilesはデータの配信に専用のタイルサーバーが必要になりますが、PMTilesはファイルサーバーに置くだけで良いです。
 PMTilesだとベクタ形式のままなのでファイルサイズは大きくならずファイル数も一つなので取り扱いも簡単です。そして専用のサーバーも不要なのでホームページ用のファイルサーバーやGithub PagesやAmazon S3のような静的ホスティングサービスだけで配信できます。
 アプリではPMTilesから表示範囲だけのベクタタイルを取得してレンダリングの処理をすれば良いので、広範囲のデータであっても重くなりません。さらに、色やラベルなどのスタイルはユーザー側で設定できるようになります。
 気になるのは、ベクタタイルをPMTilesから取得する仕組みですが、HTTP Range RequestsというHTTPでファイルの一部分だけを取得する方法を利用しています。PMTilesは、各ズームレベルのX,Yタイルをヒルベクト曲線に基づいてバイナリファイルに配置しています。なので、z/x/yが分かれば、逆にバイナリの位置を計算することができ、それをRange Requestで取得しています。

https://docs.protomaps.com/pmtiles/
https://github.com/protomaps/PMTiles/blob/main/spec/v3/spec.md


PMTilesを使ってみよう!

前置きはこれぐらいにして、スマホでPMTilesを使ってみましょう。使用するデータはこちらです。GeoJSONのデータをPMTilesに変換して、Github Pagesに置いてあります。
github.com

1. EcorisMapを起動して、左下のボタンを押します。

2. 地図選択の画面で新規追加ボタンを押します。

3. 地図の名称とpmtilesのURLとスタイルファイルのURLを入力してOKを押します。(スタイルファイルを指定しないとデフォルトの色になります。)
https://tmizu23.github.io/santa/santa.pmtiles
https://tmizu23.github.io/santa/style.json


4. これでサンタクロースのPMTIlesを読み込むことができました。クリックすると、属性を表示できます。

スタイルを変更したい場合は、上記のstyle.jsonをコピーして、色などを変更したのち、自分のサイトに置いてスタイルファイルのURLを変更してください。

ということで良いクリスマスを!

補足1 PMTilesの作り方

PMTilesのデータは、go-pmtilesを使ってmbtilesから変換するか、tippecanoeを使ってGeoJSONから変換して作成します。GeoJSONからPMTilesへの変換は、以下のコマンドでできます。データによっては、変換オプションを指定して最適化する必要があります。詳しい説明は、また期を改めて。

tippecanoe -o santa.pmtiles santa.geojson

ちなみに、GeoJSONのデータは「サンタの絵を書いて、それをポリゴンにして、スケールと座標は、東北地方ぐらいの仙台付近、GeoJSONでダウンロードしたい!」とChatGPTに言って作ってもらいました。

補足2 スタイルファイルについて

スタイルファイルは、ベクタタイルに色やラベルをつけるための設定ファイルです。そのルールは基本的にはMapLibre Style Spec
に準拠していますが以下の点が異なります。

  • {layers:[]}のみが必須項目です。
  • id、sourceはダミーでOKです。
  • source-layerはPMTilesのレイヤ名と対応させる必要があります。
  • filter関連は、sampleにある形式のみ対応しています。(matchと==だけ)

(今後、少しずつ色々なfilterに対応するように実装しようと思ってます)

補足3 react-native-mapsへのPMTilesの実装方法

 EcorisMapはreact-native-mapsを利用して作成しています。しかしreact-native-mapsはPMTilesはもとより、ベクタータイルもサポートしていません。なので、新機能が欲しければ自分で実装するしかありません。React Nativeは、Typescriptを書けばAndroid用とiOS用のアプリを同時に作成できるのが良いところなのですが、裏を返せば新機能を追加するためには、Android用のJavaiOS用のObjective-Cの両方のコードを書く必要が出てきます。Objective-Cは見たこともないし、Javaは25年前にアプレットを作ったきりです。
 こういう状況なので、去年までならPMTilesを実装しようなどとは、露ほども考えなかったのですが、ChatGPTが状況を変えました。PMTilesのGithubには、Cとjavascriptの実装コードと仕様(spec)が置いてあります。これらを関数ごとにコピペして「javaObjective-Cに移植して!」とお願いすることでコードが作成されます。それをコンパイルしてエラーが出たら再びChatGPTに修正してもらいます。これを繰り返すことでなんとか実装できました。
 ベクタータイルの実装も同様の方法ですが、Maplibreのようにグラフィックライブラリで高速に描画を行う工夫がされているのではなく、単純にCanvasへの描画です。ただ、野外調査で使うデータのように少ないレイヤに色やラベルを付けるだけで良い場合は、十分速く描画することができます。

補足4 代替手段の検討

MapLibre GL JS

MapLibre GL JSでWeb用のサイトを作ってスマホのブラウザで見る方法です。もしかすると、これでも良いかもしれません。ただ、アプリじゃないとできないこととか、パフォーマンスが気になります。あと、地理院地図以外の地図や衛星画像を使うためにはアクセス数に応じて課金が発生するサービスの利用が必要になります。(もしくは、自分で配信)

MapLibre Native

GitHub - maplibre/maplibre-native: MapLibre Native - Interactive vector tile maps for iOS, Android and other platforms.

上記と違ってスマホ用のアプリを作ることになるのでパフォーマンスは問題なさそうです。ただ、開発にはAndroid用にはKotlin、iOS用にはSwiftを使用するようです。両方に対応したアプリを作る場合は大変になります。

MapLibre GL SDK for React Native

github.com

これが本命?試してないので分かりませんが、react-native-maps+ベクタータイルの代替には、これが良さそうです。ただ、react-native-mapsだと、Maps SDK for Android, iOSをベースにしているので、googleの地図と衛星画像が無課金で利用できます。それが使えなくないのは弱点です。

RTKGPS+(カスタムバージョン)の更新。Pixel7シリーズ用

以前ビルドしたものがpixel7aで起動できなくなってたので修正しました。pixel7シリーズからは64bitのアプリのみの対応になった影響です。

修正したapkはこちらからダウンロードできます。pixel7a以外の動作検証はしていません。64bitに対応していないものは、以前のリリースを利用ください。

コードはこちら
github.com

以下作業メモ

armeabi-v7aとなっている部分をarm64-v8aに変更

  • JDKのバージョンを13に更新

File-->Settings-->Build Tools で Download JDK...で選択
古いJDKだとrelease用のビルドで署名のときにエラーになるため

React Native Mapsで野外調査アプリを作ってみた


2022年冬、野外調査アプリが群雄割拠しています。DXの掛け声のもと、仕事で使う野外調査アプリを探していた私は、四角い車輪を再発明したのでした。


これはFOSS4G Advent Calendar 2022の記事です。


群雄割拠する野外調査で使えそうなアプリたち
上から、定番、日本製、海外製、オープンソース、登山用、そして拙作


野外調査の必須アイテムと言えば、紙の野帳と図面、GPS、デジカメでした。スマホの普及とともに、数々の野外調査アプリがそれに取って代わろうと、しのぎを削っています。アプリの使い勝手は一長一短、淘汰されるものもあるでしょうが、多様性があることは健全です。


オープンソースの野外調査アプリ

FOSS4GのAdventCalendarなので、オープンソースのものをピックアップしました。どのアプリも現在進行形で開発が進んでいます。

注目ポイントは、利用している開発フレームワークです。Mergin Maps Input とQFieldは「Qt」、SMASHは「Flutter」です。採用しているフレームワークでどれぐらい開発効率やアプリのパフォーマンスが違うのか気になるところです。


四角い車輪の再発明

DXの掛け声のもと、野外調査アプリの導入を検討していたつもりが...


突然ですが、既存のものを自前で作り直すことを車輪の再発明と言います。さらに作ったものが役に立たない場合は、四角い車輪と揶揄されます。

これだけ野外調査アプリがある中、素人が似たようなものを作るのは、四角い車輪の再発明に他ならないかもしれません。

でも、まあいいか、スペアタイヤのつもりで自前の野外調査アプリを作ってみました。名前は「EcorisMap」です。React Native Mapsを利用していて、アプリもオープンソースです。



とりあえず使ってみよう![PR]

まずは、アプリをインストールしましょう。iOSAndroid、Web版があります。


起動すると日本へそ公園を中心とした地図が表示される

なんでここ?って思うかもしれませんが、日本の中心は北緯35度、東経135度だと刷り込まれた世代だからです。

操作は直感で分かるように、それっぽいアイコンになっています。直感で分かると言っておきながらボタンの説明をします。上から、ヘディングアップ切り替え、ズーム、GPS、下にいって左から、地図選択、トラックログの記録、レイヤ表示、データ追加、各種設定になってます。


自分のデータを表示してみよう


QGISで作成したGeoJSONのポリゴンとハンディGPSで取得したGPXのログを読み込んだところ。秋田駒ケ岳にはムーミン谷と呼ばれる素敵な場所があります。

データをインポートして確認する方法を説明します。

1.レイヤ表示ボタンを押して、2.レイヤ一覧の画面になったら、3.左下のデータ読み込みボタンを押して、4.スマホに保存されているGeoJSONやGPXのデータを指定するとインポートできるので、5.レイヤ一覧からレイヤを選択したあと、6.データ一覧からデータを選択して、7.左下の飛行機ボタンを押すとデータの場所にジャンプするので、8.読み込んだデータを確認します。


言葉だと上手く言えないけど思いは伝えました。色とかラベルも設定できます。


電波がなくても大丈夫?
 
調査の現場は、五分五分の確率で電波がありません。でも、地図をダウンロードできるので大丈夫。

現地が圏外の場合は、ネット環境がある場所で事前に地図をダウンロードしておきます。地図選択画面でダウンロードボタンを押して、必要な範囲を選択してダウンロードします。

地図は自前のタイル地図も登録できます。例えばドローンから作成したオルソ画像をQGISでタイル地図にして、それをGitHubにあげてURLを登録すると読み込めます。


現地でデータを取得しよう
  
1. 入力項目を設定して、2. 現在地のポイントを落として、3. データを入力します。

現地ではGPSをオンにして目的地にでかけます。素敵なお花を見つけたら現在地にポイントを落とします。お花の写真を上手に撮ったら、その名前と写真を入力します。入力したい項目は、レイヤの設定で変更できます。トラックをオンにしておけば、花の種をこぼして帰らなくても歩いた軌跡を残せます。


データをエクスポートするよ

データはGeoJSON、CSV、GPXの形式でエクスポートできます。

エクスポートしたいデータを選択して、エクスポートボタンを押すとzipファイルが作成されます。スマホ内に保存したり、Google Driveに保存したり、Slackで飛ばしたりすると便利です。でもGmailはzipファイルをブロックするから使えません。


Web版と連携すれば便利かも

Web版だと3D表示もできてカッコいい。ファイルのインポートも地図画面にドラッグ&ドロップでできます。

必要な操作はスマホで全部できますが、データの準備はパソコンからWeb版を利用すると簡単です。Web版で、調査に必要なデータをインポートして、色やラベルを設定しておきます。設定画面で「データをファイルに保存」とすると拡張子ecorismapの設定ファイルを書き出します(中身はデータと設定をzipで保存したもの)。このecorismapファイルをスマホに送って設定画面から「データファイルを読み込み」とすると、そっくりそのまま開きます。あら便利。


Web版のセキュリティが気になるかもしれませんが、データはすべてブラウザ側だけで処理してます。サーバーにデータを送ってません。でも、今後はクラウド対応も考えてたり。


ちょっとだけ技術的な説明をするよ!

React Native

EcorisMapの開発に利用しているフレームワークは、React Nativeです。React Nativeは、Meta(旧Facebook)とコミュニティによって開発されているモバイル用のフレームワークで、ReactでネイティブコードをラップすることでTypeScript(JavaScript)でAndroidiOSアプリ開発ができます。最近は、Flutterに人気が押されがちでMetaさんも元気がないので、ちょっと心配です。ソースコードは、基本的にはTypeScriptなので、JavaScriptになじみがあれば、始めやすいかも(?)

React Native Maps

GoogleのMaps SDK for AndroidiOSと、AppleのMapKitをラップしてReact Nativeで使えるようにしたライブラリです。EcorisMapでは、MapKitは使わずに、Android版、iOS版ともにMaps SDKGoogle Mapsの地図を利用しています。モバイル用だとGoogle Mapsの地図データや衛星データを無課金で利用できるのでありがたいです。

EcorisMapのWeb版

Web版は、React Native for Webを利用してスマホ用のコードからWeb版を生成しています。もともとWebの技術であったReactをNativeに適用して、それをまたWebに戻すという加工貿易的なイメージ?の技術です。ただ、Web版はスマホ版と少しコードが違う部分があって、地図ライブラリにMapLibreを使っています。その関係で、デフォルトの地図はGoogle Mapsではなく、MapTilerの地図と地形データを読み込んでいます。そのためMapTilerの無料枠を超えると地図が表示されなくなるかもしれません...という意味で現在Web版はお試し中です。MapLibreも3Dの地形表示ができるようになったのでコミュニティーに感謝です。(MapBoxも嫌いじゃないよ)

国際化

一応、国際化してあります。現時点では、日本語と(つたない)英語です。世界中のみんなが使ってくれる妄想を抱きながら作業しました。現時点のダウンロード数は36人です(笑

その他

ソースコードを見てもらえれば分かる通り、クソコードです。テストコードもろくにありません。恥の多い生涯を送って来ました。オープンソースとは残酷なものです。これからリファクタリングをします。


やりたいこと

今後やりたいことをリストアップしてみました。

  • ローカルのラスタ読み込み(TIFF, MBTiles, GeoPDF)
  • ライン、ポリゴン編集(お絵描きアプリみたいに描きたい)
  • クラウド対応(Firebase)
  • 課金(サブスク、アプリ内課金)
  • スマートウォッチ対応(AppleWatch, PixelWatch)


地図データはネット経由のタイルの読み込みだけ対応してるので、ローカルで持っているGeoTIFFとかMBTilesとかGeoPDFを読み込めるようにできたら便利かなーと思ってます。

ラインの編集は今も一応できますが、いまいちです。お絵描きアプリみたいに、さら、さら、さらーと描けるようにしたいです。ポリゴンにも対応したいです。できることならトポロジーも考慮して。

Firebaseを利用したクラウド対応は、社内用のテストアプリでは実装済みで、すでに利用しています。でも、みんなが使うサービスとして公開するにはセキュリティの面でハードルが高いなーと怖気付いてます。

当然のことながら仕事で扱う位置情報は、漏洩したらタダじゃ済まないものばかりです。アプリとFirebase間をEnd to Endで暗号できるVirgil SecurityのE3Kitを導入してますが、利用人数増えたらお安くないし、暗号化するとアプリの輸出制限に引っかかって、アプリを公開するには色々と手続きが必要になり大変そうです。

Mergin MapsやQFieldはクラウドサービスもありますが、そのあたりどう考えてるのか気になります(利用者側も)。クラウドのサーバー側もオープンソースで公開してるので、気になる人は自分でサーバー立ててねってことですかね。

課金ねぇ......先立つものは必要ですよね.....

スマホを出して現在地を確認するのは面倒なので、スマートウォッチで確認できるようにしたいです。スマートウォッチは持ってません。

サンタさんにお願いするスマートウォッチの画像を張っておきます。


 



最後になりましたが、バグは色々あると思いますので、不具合、ご要望があれば以下に書き込むなり、Pull Requestを送るなり、よろしくお願い致します。


github.com

Happy Merry Christmas !


我が家のクリスマスケーキ

Cloud Optimized Point Cloud(COPC)の作成と表示方法

ドローン画像のフォトグラメトリで作成した点群データをブラウザで快適に表示できるCOPC形式の点群データの作成と表示をやってみました。

copc.io

las、lazファイルの用意

地理座標系(緯度、経度)以外で書き出したlasファイルもしくはlazファイルの点群データを用意します。高度は楕円体高です。(標高になっている場合は補足で説明している方法で変換します。)

COPCへの変換

変換方法は2通りあります。

その1

QGIS3.26以降を用意します。las、lazファイルを画面にドラッグするとxxx.copc.lazのようなファイルが出来上がります。今のところファイル名に日本語は使えません。

その2

PDALを使用します。WindowsならQGIS3.26をインストールした際に入るOSGeo4Wで利用できます。
OSGeo4Wで以下のコマンドを実行しするとlazをcopcに変換できます。

pdal translate -i xxx.laz -o xxx.copc.laz --writers.copc.forward=all

COPCファイルのアップロード

どこかのWEBサーバーにCOPCに変換したファイルをアップロードします。WEBサーバーではCORSを受け付けるように.htaccessを以下のように設定しておきます。

Header set Access-Control-Allow-Origin "https://viewer.copc.io"

COPCデータの表示

https://viewer.copc.io
にアクセスしてデータボタンからAdd point cloudを押してcopcファイルのURLを貼り付けます。
もしくは以下のように直接URLを指定してアクセスします。
https://viewer.copc.io/?copc=https://www.example.com/xxx.copc.laz

  • Ctrlを押しながらドラッグで回転できます。
  • 色はデフォルトでElevationになっているのでパネルからRGBに変更すると実際の色で表示できます。
  • 点のサイズを変えたり、表示数(Point budget)を変えたりすると見た目の詳細さが変わります。

COPC Viewerについて

以下によるとオープンソースではないようです。見た目はなんとなくCesiumっぽいので、そのCOPC対応版なのかな?と思ってみたり。
https://hobu.co/copc-viewer.html

補足 lazが標高になっている場合

手元にある点群データが平面直角座標系10で高さは標高値となっている場合の変換方法です。COPC Viewerの地形データは楕円体高となっているため高さを合わせるためにはcopcのデータも楕円体高に変換しておく必要があります。(点群データの高さは一般的には楕円体高なんですかね?知りません)

PDALのパイプライン用のファイルを以下のように作成します。

  • xxx.lazは読み込むファイル
  • 最初のin_srsは平面直角座標系10(epsg:6678)のproj指定にgeoidgridを追加したもの。geoidgridで指定しているgtxファイルはこちらで説明しているものを使用。
  • 最初のout_srsはEPSG:6667(緯度、経度、楕円体高)。ここで一旦、平面直角座標系10の標高を緯度経度の楕円体高に変換する。
  • 次のout_srsはEPSG:6678(平面直角座標系10)。これで楕円体高の平面直角座標系10になる。ただ、EPSG:6678は2D用なので3D用には別のものがある気がするけど分かりません。(EPSG:6678+224みたいな感じ??)
  • 最後にwriters.copcでcopcに変換します。

pipeline.json

[
{
"type" : "readers.las",
"filename" : "xxx.laz"
},
{
"type":"filters.reprojection",
"in_srs":"+proj=tmerc +lat_0=40 +lon_0=140.833333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +geoidgrids=D:/PDAL/jp_gsi_gsigeo2011.gtx",
"out_srs":"EPSG:6667"
},
{
"type":"filters.reprojection",
"in_srs":"EPSG:6667",
"out_srs":"EPSG:6678"
},
{
"type" : "writers.copc",
"filename" : "xxx.copc.laz"
}
]

pdal pipeline pipeline.json で変換を実行します。

Phantom4 RTKの飛行ログを取得する方法

1. プロポとPCをUSBで接続します。
2. GS RTK アプリを起動して、画面を上からスワイプします。
3. USB ストレージを接続する ボタンを押します。
4. PCのエクスプローラでD:\DJI\dji.prof.mg.gsp\LOG\tcp_769にアクセスします。
5. フォルダ内の飛行ログをコピーします。
6. DJI Flight Log Viewer | Phantom Help このサイトに飛行ログをアップロードしてKMZファイルに変換します。

標高demデータから楕円体高のデータをgdalで作成する方法

なんだか楕円体高のdemデータが欲しくなるときがあります。
そんな時のために取得方法を紹介します。


2022.8.19追追記
Phantom4 RTKの地形認識モード使用時にPPKの場合(D-RTK 2を使用しない)は、高度は気圧計で算出されるため、標高やその日の天気で誤差が大きくなってしまうようです。で、やっぱり楕円体高でDEMを用意する必要があるようです。

https://forum.dji.com/forum.php?mod=redirect&goto=findpost&ptid=264115&pid=2734061

ジオイド高の分だけ高く飛んだというのは、偶然それぐらいの誤差が出ていただけだった可能性が高いので取り消し

2021.10.19追記
Phantom4 RTKの地形認識モードのDSMは、普通に標高で良いのかもしれません....実際に飛ばしたら、ジオイド高の分だけ高く飛んでいました...

1.

QGIS 3.20をインストールして最新のgdal(とproj)を使えるようにします。

QGISのダウンロード

2.

C:\Program Files\QGIS 3.20.3\share\proj に入っている jp_gsi_gsigeo2011.tifを作業フォルダにコピーします。

3.

OSGeo4W shellを起動して作業フォルダに移動します。

4.

日本のgeoidモデルのtifをgtx形式に変換します。

gdal_translate -ot Float32 jp_gsi_gsigeo2011.tif jp_gsi_gsigeo2011.gtx

ジオイドモデルの元データは、国土地理院で提供されています。使用に関する許可申請等は国土地理院のサイトおよびprojファイルに入っているjp_gsi_README.txtを確認ください。

5.

jp_gsi_gsigeo2011.gtxをC:\Program Files\QGIS 3.20.3\share\projのフォルダにコピーします。

6.

標高demデータを緯度経度(epsg:6668)で用意します。

例えばこれで作成
基盤地図情報 標高DEMデータ変換ツール | コンテンツ | 株式会社エコリス

7.

gdalwarpで楕円体高になるようにパラメータを指定して変換します。

gdalwarp -s_srs "+init=epsg:6668 +geoidgrids=jp_gsi_gsigeo2011.gtx" -t_srs epsg:6667 merge.tif merge_ellipsoidal.tif

※ Warning 1: +init=epsg:XXXX syntax is deprecated. と出ますが気にしません。

補足

  • こんなことをしなくても gdalwarpで -s_srs をepsg:6697 (標高)-t_srsをepsg:6667(楕円体高)と指定すれば変換できると思ったのですが駄目でした。なんで駄目かを誰か教えてください!
  • -co TFW=YES を追加すると.tfwも出力できます。
  • これはDEMなので、DSMとして利用する場合は、建物とか木の高さを考慮して飛行高度を設定してください。
  • 水域などnodataの場所がある場合は気をつけてください!(nodataを0とかにしてるとジオイド高が値に入って、それっぽくなってしまいます。そのままドローンを飛ばすと水域にダイブすることになります。)