unvt/kata を使ってみる（第０弾）

# はじめに
:::note info
この記事「unvt/kata を使ってみる（第０弾）」は、unvt/kata v1.0.2での実験の記事です。その後、ツールが改善されまして、v.1.0.3での変換については以下のページの記事にまとめています。
https://qiita.com/T-ubu/items/4fa0ab633c6746574bdd

unvt/kataはベクトルタイルを作る際、フィルター機能を使うことで、ソースごとにレイヤ名、最大・最小ズームレベルを与えることが簡単にできます。また、ベクトルタイルのレイヤ一覧とプロパティ一覧を確認できるので、とても便利なツールだと思います。（データが数GBを超えてしまう場合だと、地域によって出力ファイルを分けるというようなセッティングがないので、このツールだけでなくて何か工夫が必要だと思いますが、小規模なデータには便利です。。）
:::

### unvt/kataの開発・公開
2022年3月28日(NY time)、国土地理院さんからベクトルタイル設計情報の処理ツール[unvt/kata](https://github.com/unvt/kata)がFOSS4Gとして公開されました。(Tweet は[こちら](https://twitter.com/gsi_cyberjapan/status/1508588257441095682))
UN Open GISイニシアティブの一員としての貢献ということで、unvtのGitHubレポジトリにソースコードが公開されています。

### unvt/kataで出来ること
unvt/kataには大きく分けて２つの機能があると理解しました。一つは、ベクトルタイル変換ツールtippecanoeに入れる前のデータを簡単に加工する機能（フィルタリング）で、もう一つはベクトルタイルのメタデータから、レイヤ一覧（レイヤ名、ズームレベル、属性）を表示する機能です。

### 今回の私の作業の動機
そもそもどんなことができるのか知るために、まず自分で手を動かしてみましたので、その記録・メモ・スタックポイントをQiitaに投稿します。個人的には小縮尺の地図用のベクトルタイルをkataを使って効率的に作れないかなと考えていて実験をしたものです。
今回、私の実験では、このツールのフィルタリング機能を使ってベクトルタイルを作成することを実験しています。

:::note info
この記事はunvt/kata version 1.0.2での実験を書いています。この記事のあと、unvt/kata は version 1.0.3としてバグが修正されていますので、tippecanoe入力用のgeojson sequenceに関する注意を共有する意味で公開します。
:::

# 目的
 unvt/kataのfilterを使ってベクトルタイル作成を試します。（ベクトルタイルのメタデータからベクトルタイルの目録を表示させる機能もありますが、そちらはまたの機会に試します。）

具体的には、シェープファイル形式のGISデータをgeojsonに変換し、それらにkataのfilterを適用させベクトルタイル生成のパラメータを追加したのちにベクトルタイル変換ツールtippecanoeに流し込みます。これらのテストはdockerコンテナで行います。

# 環境
* Windows 10 (Enterprise)
* Docker version 20.10.8, build 3967b7d
* つかったDocker container unvt/nanban:16
* 作業したレポジトリ　https://github.com/ubukawa/kata-test

これまでも別の記事で説明していますが、Windowsユーザーはtippecanoeを使える環境を準備するのが結構難しいと思います。ですので、Dockerを使いました。（Dockerについては、昨年から利用ポリシーが変わっていますので気を付けましょう。）


# 手順
## Step 1： ソースデータの準備
[NaturalEarth](https://www.naturalearthdata.com/)のページから小縮尺のデータをダウンロードしてきます。今回のテスト用にダウンロードしたシェープファイルは以下のものです。作業用レポジトリにいれてあります （[ここ](https://github.com/ubukawa/kata-test/tree/main/src)）。

* ne_110m_admin_0_boundary_lines_land.shp
* ne_110m_coastline.shp
* ne_110m_graticules_30.shp
* ne_110m_lakes.shp
* ne_110m_land.shp
* ne_110m_ocean.shp
* ne_110m_populated_places.shp
* ne_110m_rivers_lake_centerlines.sh



## Step 2: unvt/nanban:16を起動
今回の作業ではベクトルタイル生成ツールとしてTippecanoeを使うこと、また、nodejsのバージョンなど安定した環境で実験をしたいということから、unvt/nanban:16 のDockerイメージからDockerコンテナを作うことにしました。

* unvt/nanban はもともとnodejsのversion 12 を使っていたため、kataとitomaが入りませんでした。（v12は4月末でEnd of Lifeなのでそもそも更新しないといけなかったですね・・。）
* unvt/nanban:16 にはunvt/kataとunvt/itomaが入っています。nanban:16ではnodejsもversion16 を使っています。（vt-optimizerganodejs16と相性が悪いのか入らなくなったので、nanban:latestではなく、nanban:16として管理しています。）



Powershellで作業フォルダに行った後、以下のようにしてDockerをスタートします。

```
docker run -it --rm -v ${PWD}:/data unvt/nanban:16
cd /data
```

私のレポジトリで試したい場合は、最初にgit cloneをして実験用レポジトリをコピーしてください。（以下のような感じ）

```
git clone https://github.com/ubukawa/kata-test
cd kata-test
docker run -it --rm -v ${PWD}:/data unvt/nanban:16
cd /data
```

lsをするとsrcというフォルダがあると思いますが、その中にシェープファイルが入っています。

## Step 3: シェープファイルをgeojsonに変換
unvt/nanban:16にはgdalが入っています。これを使ってシェープファイルをgeojsonに変換します。以下のような感じです（inputとoutputはファイル名を入れます）。

```
ogr2ogr -f GeoJSON -1_geojson/output.geojson src/input.shp
```

実際に実行した画面が以下のものです。geojsonの名前はシェープファイルの名前より少し短くしています。
![2022-03-31-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/b440ac9b-1919-86af-25fc-fecf42323d30.png)

こんな感じでgeojsonファイルができています。

![2022-03-31-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/aca88974-3502-2a2a-2be3-309ee86d4d29.png)

### Step 3の備考
あとで重要になってくるのですが、ここにあるgeojsonはFeatureCollectionにラップされているFeaturesというオブジェクトの中に、featureタイプのオブジェクトが複数があるというものです。

FeatureCollectionのところを理解するために、例えば、下の図は同じgeojsonをgeojson形式で読み込んだものと、GeoJSONSeq形式で読み込んだものです。FeatureCollectionでラップされているかどうかが確認できると思います。
![2022-04-01-gdal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/bb8d8983-216e-eede-7383-8efab1e27b9e.png)

Tippecanoeのインプット用としては、FeatureCollectionのラップがないGeoJSONSeq形式のほうがよいです(下図：[mapbox/tippecanoe](https://github.com/mapbox/tippecanoe)のReadmeより)。普通のGeoJSONでFeatureCollectionでラップされているファイルからも変換はできるのですが、FeatureCollectionの中のFeaturesに入っているものがパースアウトされて処理され、そのほかのオブジェクトは無視されます。
![2022-04-01-tippecanoe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/bcefc03e-56e3-c18e-5799-6d9a115d42b9.png)


無視されるだけので無理にFeatureCollectionのラップを外さなくてもいいのですが、これを外す方法はgdalを使ってGeoJSON形式からGeoJSONSeq形式を作ればよいです。あるいはシェープファイルからインポートの時にGeoJSONSeq形式にしてしまえばよいです。また、Tippecanoe-json-toolを使ってもできました（Tippecanoe-json-toolは@hfuさんに教えていただきました。ありがとうございます。）。

```
ogr2ogr 1_geojson/no-wrap.geojsons 1_geojson/wrap.geojson
```

```
ogr2ogr -f GeoJSONSeq -1_geojson/output.geojsons src/input.shp
```

```
tippecanoe-json-tool input.geojson > out.geojsons
```

## Step 4: kata.yml を準備してkataによるフィルターを実行
Step 3までで、素材になるgeojsonファイルが（複数）準備できました。これをフィルタリングしてまとめます。
私の理解の範囲で簡単にいうと、フィルタリングは『ベクトルタイルを作るにあたって、インプットされたデータについて各レイヤの最大・最小ズームを決めたり、属性を加工したすること。』という感じです。

nodejsを使ってベクトルタイルの変換をやったときは、フィルタリングの過程において、それぞれの地物に対し、１）レイヤ名を指定する、２）最大・最小ズームレベルを与える、３）不要な属性を削除する、４)属性名を変更する、５）属性に応じて新しい属性を計算する（レイヤ名や最大・最小ズームレベルも属性から割り振ることがあります）、６）属性や条件によって地物をベクトルタイルに含めない（Nullを返す）、等の作業をしていました。

今回は、unvt/kata の Readmeにならって、準備したGeoJSON用のkata.ymlを準備します。今回は以下のような感じで準備しました。

```
bndl:
  source: 1_geojson/bndl.geojson
  minzoom: 1
  maxzoom: 5
coastl:
  source: 1_geojson/coastl.geojson
  minzoom: 0
  maxzoom: 5
grid30:
  source: 1_geojson/graticules30.geojson
  minzoom: 0
  maxzoom: 4
lake:
  source: 1_geojson/lake.geojson
  minzoom: 0
  maxzoom: 5
land:
  source: 1_geojson/land.geojson
  minzoom: 0
  maxzoom: 5
ocean:
  source: 1_geojson/ocean.geojson
  minzoom: 0
  maxzoom: 4
popp:
  source: 1_geojson/popp.geojson
  minzoom: 3
  maxzoom: 5
river:
  source: 1_geojson/river.geojson
  minzoom: 1
  maxzoom: 5
```

そして、以下のような感じで実行します。

```
kata filter ./kata.yml
```

このコマンドだとコンソールにフィルターされたものが表示されるだけなので、まずは、以下のような感じでファイルに出力しました。

```
kata filter ./kata.yml >　compiled.geojson
```

出力されたのを次のコマンドに渡すのであれば、以下のような感じでtippecanoeに渡せます。

```
kata filter ./kata.yml | tippecanoe -e tile 
```

### Step 4の備考
Step 3の備考と深く関係しますが、このStep 4で得られたフィルター済みのファイルは[unvt/kata](https://github.com/unvt/kata)のReadmeにあるとおりの構造です。つまり、tippecanoe用のminzoomとmaxzoomは、FeatureCollectionと並列のオブジェクトnotippecanoeの中でtippecanoe.minzoomとtippecanoe.maxzoomとして追加されています。
ただ、ここでtippecanoe.minzoomとtippecanoe.maxzoomはfeaturesの中のそれぞれのオブジェクトに与えてあげないといけないものかもしれません。tippecanoeでの変換する際には、featuresの中のオブジェクトだけが抜き出されるので（私ができる範囲なので知らない技があるかもしれませんが）、現在のkataのフィルターで与えたmaxzoomやminzoomは反映されないと思います。さらに、少し話が変わりますが、tippecanoe.layerがあればkata.ymlからベクトルタイルレイヤ名も指定できると思います。
![2022-04-01-kata.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/369384e4-864e-ee31-7892-a0de0bc5b89b.png)


## Step 5：　フィルターしたデータをTippecanoeで変換（ここでスタック）
kataでフィルターをかけたものをTippecanoeで処理します。

```
tippecanoe -e tile compiled.geojson
```
![2022-03-31-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/01d6a2fe-3c02-b462-13fe-c3181e7f4530.png)

と、変換自体は進んでいくのですが、レイヤ名がない（一つのレイヤ名）、地物のズームレベルが反映されていないというような状況になってしまいまして一旦スタックしています。私としては原因はStep 3の備考とStep 4の備考に書いてあるものだと思っています。


# まとめ

## 実験の結果
私の実験では、kataのフィルターを適用したデータをベクトルタイルに変換することはうまくできなかった。
（タイルはできるが、思った通りの最大・最小ズームレベルが与えられない）

:::note info
追記（2022.4.7）
フィルターの際のGeoJSONにつけるtippecanoeオブジェクトの場所がunvt/kata version 1.0.3で修正されました。また、kata.ymlから、tippecanoe.layerオブジェクトが指定されることになり、入力した情報が各ベクトルタイルレイヤに分けられるようになりました。
:::

## kataのフィルターでできそうなこと（予想）
まだ最後まで変換できていないので、**あくまで予想**ですが、どんなことができそうか私の予想を整理してみました。

|機能  |可否（私の見立）  |私見  |
|---|---|---|
|レイヤ名を指定する  |×  |tippecanoe.layerをkata.ymlで与えて読めるようにすれば対応できるのではないか。（4.7追記 ver1.0.3でできるようになりました）  |
|最大・最小ズームの指定  |〇  |ただし、tippecanoeオブジェクトの場所を少し考えた方がよいかも（FeatureCollectionと同列でなくて、Featuresの各地物にそれぞれ与える必要があるのでは）  |
|不要な属性を削除する  |？  |プロパティを指定するところがあるので、そこでできるかな？？  |
|属性名を変更する  |〇  |できそう  |
|属性に応じて新しい属性を計算する  |〇？×？  |yamlファイルのなかでif文とかを書いてできるのだろうか？？  |
|属性や条件によって地物をベクトルタイルに含めない  |×？  |今のfilterでは地物のところでnullを返すのはなさそう（featuresの各オブジェクトごとにフィルターしていない？？）  |

## 今後の予定
kataでフィルタリングしたデータを変換する方法を探る。


# 謝辞
unvt/kataを作成し、またFOSS4Gとして公開してくれている国土地理院さんに感謝します。また開発を受注されたGeoloniaの皆様にも感謝します。

# References
* UNVT/kata https://github.com/unvt/kata
* mapbox/tippecanoe https://github.com/mapbox/tippecanoe/
* NaturalEarth https://www.naturalearthdata.com/
* https://twitter.com/gsi_cyberjapan/status/1508588257441095682