OpenStreetMapから、UNVTを使ってベクトルタイルを作る（dockerベースのunvt/nanban）

# はじめに
以下の記事を日本語でもメモしておきます。

https://qiita.com/T-ubu/items/b112ec739a99f92f32dd

FOSS4Gなどに参加しても、ベクトルタイル技術の利用は年々増えてきているように思います。ベクトルタイルを作成するツールはたくさんあります。たとえば、[OpenMapTiles](https://openmaptiles.org/)、 [tilemaker](https://github.com/systemed/tilemaker) 、 [onthegomap/planetiler](https://github.com/onthegomap/planetiler) などを使えば、ＯＳＭからベクトルタイルを作ることができます。 

国連ベクトルタイルツールキット [UN Vector Tile Toolkit (UNVT)](https://github.com/unvt)でも、ＯＳＭからベクトルタイルを作成する方法を開発しています。ここではUNVTを使ってどのようにベクトルタイルを作るか紹介したいと思います (特に ~~[unvt/naru](https://github.com/unvt/naru)~~ [unvt/nanban](https://github.com/unvt/nanban)).

[unvt/naru](https://github.com/unvt/naru) は数年前に開発されまして、nodejs ver.12で動いていました。このDocker環境を構築しようとすると、少なくとも私の環境ではできなかったので、今回の作業のために新しいレポジトリ[ubukawa/mini-naru](https://github.com/ubukawa/mini-naru)をつくり、unvt/naruの中からデータ変換に必要なものを抜き出しました。これらをunvt/nanbanの上で処理することで作業を進めたいと思います。


# 私の環境
* Windows 10 (Enterprise)
* Docker version 20.10.8
* PowerShell version 5.1.19041.1237
* git version 2.25.0.windows.1



# 手順

## Step 1: ファイルのダウンロード
["GEOFABRIK"](https://download.geofabrik.de/)などのOSMデータをダウンロードできるサイトからosm.pbfファイルをダウンロードします。今回は米国のオハイオ州のOSMデータをダウンロードすることにしました。"ohio-latest.osm.pbf"が保存されます。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/d0d9cdc7-1a82-a46f-deca-91f1a4fbe1f9.png)


## Step 2: mini-naru のクローン
必要なファイルを得るために、レポジトリをクローンしておきます。
```bash
git clone https://github.com/ubukawa/mini-naru
cd mini-naru
```

## Step 3: Dockerコンテナの起動
作業場所に移動したら、保存したOSMデータを**src**ディレクトリに保存します。そしてunvt/nanban をスタートします。unvt/nanban は、今回行うベクトルタイル処理に必要なツールがほとんど入っているdockerイメージです。unvt/nanban のを使ったことがない場合はdocker pull unvt/nanbanしてからコンテナを起動します。作業フォルダを/dataに関連付けておきます。 

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



## Step 4: コンフィグファイルを参照しながらデータのエクスポートを試してみる
データ(src/ohio-latest.osm.pbf)を読み込むにはosmisumというツールを使います。このツールを使った読み込みのためのコンフィグファイル[osmium-export-config.json](https://raw.githubusercontent.com/ubukawa/mini-naru/main/osmium-export-config.json)はすでにレポジトリにありますが、これを参照させて、以下のようにコマンドを実行してみます。

```bash
 osmium export --config osmium-export-config.json --index-type=sparse_file_array --output-format=geojsonseq --output=- src/ohio-latest.osm.pbf
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/810d7871-98b1-caf0-17d6-1f4585f4653b.png)
地物がGeoJSON sequenceの形で出力されているのがわかります。ここまでは成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/f9aee2d5-4fb7-96dd-5487-b99bae5c9081.png)
[osmium-export-config.json](https://raw.githubusercontent.com/ubukawa/mini-naru/main/osmium-export-config.json)について、中身を丸々紹介しませんが、どういう設定で出力させているのかを確認する際にはこちらを確認するとよいです。



## Step 5: フィルターを使ってGeoJSONを加工
前のステップで出力された GeoJSON sequence にたいし、 **filter.js** と **modify.js**　でベクトルタイル関係の情報を追加したりします。nodejsを使うので最初に以下の2つのnpmパッケージをインストールしておきます。

```bash
npm install --save json-text-sequence @mapbox/geojson-area
```

**[filter.js](https://raw.githubusercontent.com/ubukawa/mini-naru/main/filter.js)** と **[modify.js](https://raw.githubusercontent.com/ubukawa/mini-naru/main/modify.js)** は、もうレポジトリに入っています。ここにコピペしませんが、このmodify.jsがこれまでの努力の結晶というか、OSMから変換されるベクトルタイルの構造を決めるものなので大変重要です。よくできる方は、このmodify.jsを加工することで自分好みのベクトルタイルにできます。

コマンド自体は、前までのコマンドにパイプをくっつけて、nodejsにつなげるという感じのものです。

```bash
osmium export --config osmium-export-config.json --index-type=sparse_file_array --output-format=geojsonseq --output=- src/ohio-latest.osm.pbf | node filter.js
```

これで出力成果が見られます。前のステップのものと比べると、ベクトルタイル変換用の情報、tippecanoeがついているのがわかります。これで変換の準備ができています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/d1d38dc4-b4c0-4024-3bb2-b3579de7d410.png)

## Step 6: ベクトルタイル変換（まずはmbtiles形式）
前のステップまでの成果をパイプを使ってtippicanoeに流し込みます。

```bash
osmium export --config osmium-export-config.json --index-type=sparse_file_array --output-format=geojsonseq --output=- src/ohio-latest.osm.pbf | node filter.js | tippecanoe --no-feature-limit --no-tile-size-limit --force --simplification=2 --maximum-zoom=15 --base-zoom=15 --hilbert --output=src/output.mbtiles
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/74e04e03-85a7-7557-9ab1-b1e201eeba40.png)
少し時間がかかるかもしれません。作業マシンの性能や、ソースデータのサイズによると思います。



## Step 7: mbtiles形式からpbf形式への変換
GitHubページ等での静的なホスティングにも対応するため、mbtiles形式のベクトルタイルをpbfに変換します。tippecanoe の中にあるtile-joinを使います。しかし、pbfタイルにするとデータサイズが３～4倍程度になることもあるので、もともとのmbtilesのサイズによってpbfにするかどうかを考えた方がよいです。mbtilesでホストする場合には、/onyx(https://github.com/un-vector-tile-toolkit/onyx )のようなサーバーサイドの処理が必要になると思います。

```bash
tile-join --force --no-tile-compression --no-tile-size-limit --output-to-directory=docs/zxy src/output.mbtiles
```

## 成果：　PBF形式でのベクトルタイル
このようにして、zxyフォルダ構造に格納されたpbfタイルを得ることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/ef968aeb-6e3e-15dc-fd56-20cc77ce0d93.png)

メタデータなどを確認すると中心位置なども確認できます。（デフォルトスタイルの修正の時に使える。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/fcbc91cf-8733-b27f-608f-753f33bd4bb7.png)




# 追加説明：　ベクトルタイル地図のホスティング 

## 地図のスタイル
ここで作成したベクトルタイルのデータ構造はunvt/naru の **filter.js** と **modify.js** によるものですから、unvt/naru で準備されたデフォルトのスタイルを使うことも可能です[こちらにコピー](https://raw.githubusercontent.com/ubukawa/mini-naru/main/docs/style.json) 。ただし、中心、データソース、sprites、glyphsなどは修正しないといけません。

## ホスティング
GitHubページに必要なライブラリやファイルを一緒にアップするのがやりやすいかと思います。unvt/naru ではマップシンボルを作るツールもありますし、テキストフォントなども準備されています。今回の作業レポジトリ mini-naru (https://github.com/ubukawa/mini-naru/tree/main/docs) にunvt/naruのファイルと最新の MapLibre GL JSをコピーしておいたので、ウェブマップ環境構築にも使えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/4b27513c-c032-0d15-ee28-b4ce36c6057c.png)

# 謝辞
今回の試行は、これまでに積み上げられた努力と unvt/naru にまとめられた成果に基づいたものです。 @hfu さんと仲間たちの努力に感謝します。

# 参考
* unvt/naru https://github.com/unvt/naru
* unvt/nanban https://github.com/unvt/nanban
* ubukawa/mini-naru https://github.com/ubukawa/mini-naru
* GEOFABRIK https://download.geofabrik.de/