3D都市モデルPLATEAUの建物データ（LOD1）からPMTilesを生成する方法

# はじめに
:::note info
この記事は [3D都市モデル Project PLATEAU Advent Calendar 2023](https://qiita.com/advent-calendar/2023/plateau) 11日目の記事です。
:::
GIS界隈ではCloud Optimizedが重要なキーワードになっています。Cloud Optimizedとは、特別なサーバ実装を必要とせず、大きな位置情報データの一部分を配信することを可能とするファイル形式の総称です。本記事は、Cloud Optimized形式のうち、[PMTiles](https://github.com/protomaps/PMTiles)の生成方法に焦点を当てた記事になります。具体には、国土交通省がオープンデータとして公開している、[3D都市モデルPLATEAUの建物データ（LOD1）](https://www.geospatial.jp/ckan/dataset/plateau)から[PMTiles形式](https://github.com/protomaps/PMTiles)の建物データ（LOD1）を生成する方法について説明します。

# PMTilesの特徴
- 単一ファイル形式のタイルデータ
- ラスタータイル、ベクトルタイルともに対応
- 地球規模のタイルマップの保存
- S3 のようなストレージとHTTP Range Requestsのみを使用

https://protomaps.com/docs/pmtiles

# PC環境
OS：Windows 10 Pro
CPU：Intel Core i7-9700
メモリ：32GB

# 前提条件
- 下記のサイトより3D都市モデルPLATEAUの建物データのファイルジオデータベース（以下、FGDB）をダウンロードし、解凍済みであること。
- 本記事では、FGDBが提供されている、2020年のデータ（56都市）を使用します。

https://www.geospatial.jp/ckan/dataset/plateau

# 環境構築
:::note info
ベクターデータからPMTilesの生成は、手元にMBTilesがあるならProtomaps公式の[go-pmtiles](https://github.com/protomaps/go-pmtiles)を使用したほうが良さそうです。一方で、手元にGeoJSONやFlatGeobufがあるならfeltの[tippecanoe](https://github.com/felt/tippecanoe)を使用したほうが良さそうです。今回は、後者のfeltのtippecanoeを用いた、PMTilesの生成方法について説明します。
:::
- OSGeo4W（GDAL）がインストール済みであること。
- GDALのバージョンは、GDAL 3.6.3（released 2023/03/07）です。

https://trac.osgeo.org/osgeo4w/

- WSL2（Ubuntu-20.04）がインストール済みであること。

https://learn.microsoft.com/ja-jp/windows/wsl/install

- feltのtippecanoeがインストール済みであること。

https://github.com/felt/tippecanoe

- Windows 10へのtippecanoeのインストール方法は下記のとおりです。

https://gist.github.com/ryanbaumann/e5c7d76f6eeb8598e66c5785b677726e

- ただし、上記に記載の`git clone https://github.com/mapbox/tippecanoe.git`の箇所を`git clone https://github.com/felt/tippecanoe.git`への変更が必要です。
- tippecanoeのバージョンはv2.23.0です。

# FGDBからFlatGeobufを生成
- FGDBからFlatGeobufの生成には[GDALのogr2ogr](https://gdal.org/programs/ogr2ogr.html)を使用します。
- FGDBには複数のレイヤが含まれているので、下記のコマンドでFGDBのレイヤ名を調べます。
- OSGeo4W Shellを起動し、cdコマンドでFGDBの格納されているフォルダ（11100_saitama-shi.gdb）まで移動して、`ogrinfo 11100_saitama-shi.gdb`を実行すると下記のとおりレイヤ名が取得できます。
```
D:\GIS\PLATEAU-2020\fgdb\11100_saitama-shi_fgdb>ogrinfo 11100_saitama-shi.gdb
INFO: Open of `11100_saitama-shi.gdb'
      using driver `OpenFileGDB' successful.
Layer: lod2_Building (3D Unknown (any))
Layer: lod1_Building (3D Multi Polygon)
Layer: lod0_Building (3D Multi Polygon)
Layer: lod2_BuildingPart (3D Multi Polygon)
Layer: lod1_BuildingPart (3D Multi Polygon)
Layer: lod2_RoofSurface (3D Multi Polygon)
Layer: lod2_WallSurface (3D Multi Polygon)
Layer: lod2_GroundSurface (3D Multi Polygon)
Layer: lod2_OuterCeilingSurface (3D Unknown (any))
Layer: lod2_OuterFloorSurface (3D Unknown (any))
Layer: lod1_Road (3D Multi Polygon)
Layer: lod1_TinRelief (3D Multi Polygon)
Layer: lod0_UrbanPlan (3D Multi Polygon)
Layer: lod0_AreaClassification (3D Multi Polygon)
Layer: lod0_DistrictAndZones (3D Multi Polygon)
Layer: lod1_LandUse (3D Multi Polygon)
```
- 今回使用するデータは、建物データ（LOD1）ですので、レイヤ名が「lod1_Building」のデータを使用します。
- OSGeo4W Shellで`ogr2ogr -f FlatGeobuf 出力ファイル 入力ファイル レイヤ名`を指定してogr2ogrを実行します。
```
ogr2ogr -f FlatGeobuf 11100_saitama-shi_lod1_Building.fgb 11100_saitama-shi.gdb lod1_Building
```
# FlatGeobufからPMTilesを生成
- FlatGeobufからPMTilesの生成には[feltのtippecanoe](https://github.com/felt/tippecanoe)を使用します。
- WSLを起動して、下記のコマンドを実行します。
```
tippecanoe -o 11100_saitama-shi_lod1_Building.pmtiles 11100_saitama-shi_lod1_Building.fgb -pf -pk -P
```
- tippecanoeのオプション
-P：並列読み込み
ただし、下記の記事によると、-Pオプションが有効なのは、GeoJSONSeqのみのようです。

https://qiita.com/Kanahiro/items/ceeb20c158b4c70b62b6

-pf：地物数制限を無視する（1タイルあたり200,000フィーチャに制限しない）
-pk：ファイルサイズ制限を無視する（1タイルあたり500Kバイトに制限しない）

-z, -Z：ズームレベル指定
- ズームレベルを指定する場合は下記のとおりになります。
- -Z10 -z18とすると、ズームレベル10-18の範囲でタイルを生成します。
- 指定しない場合は自動的に設定されます（ズームレベル0～14）。
- 大文字のZが最小ズームレベル、小文字のzが最大ズームレベルを示すことに注意が必要です。
```
tippecanoe -o 11100_saitama-shi_lod1_Building.pmtiles -Z10 -z18 11100_saitama-shi_lod1_Building.fgb -pf -pk -P
```

- 下記でズームレベルごとの地理分解能の概数がわかります。
- ズームレベル14で0.5m相当となり、これは一般的なWeb地図では十分な分解能と言えます。
- お好みでより高い精度を求めることは可能ですが、タイル数とのトレードオフになります。

https://github.com/felt/tippecanoe#zoom-levels

- 複数のFlatGeobufから複数のPMTilesの生成には、下記のシェルスクリプトが便利です。
（ちなみに、ChatGPT（GPT-4）が書いたコードになります。）
```process_fgb_files.sh
#!/bin/bash

for input_file in *.fgb; do
    output_file="${input_file%.fgb}.pmtiles"
    echo "Processing ${input_file} ..."
    tippecanoe -o "${output_file}" "${input_file}" -pf -pk -P
done

echo "All files processed."
read -p "Press any key to continue . . . " -n1 -s
```
```
# 改行コードを Windows 形式（CR+LF）から Unix/Linux 形式（LF）に変換
dos2unix ./process_fgb_files.sh
# 実行権限を付与
chmod +x process_fgb_files.sh
# スクリプトを実行
./process_fgb_files.sh
```

# 生成したPMTilesの確認
- 生成したPMTilesの確認には、[PMTiles Viewer](https://protomaps.github.io/PMTiles/)が便利です。
- PMTilesをドラッグ&ドロップすると、フィーチャが地図上に表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205045/7cde89fd-e705-cdb5-a56e-15f51fd843be.png)

# 生成したPMTilesをMapLibre GL JSで表示する
- 上記の方法で生成したPMTilesを下記のGitHubにて公開しています。

https://github.com/shi-works/plateau-lod1-bldg-pmtiles

- 生成したPMTilesと[MapLibre GL JS](https://maplibre.org/maplibre-gl-js/docs/)で作成したデモサイトです。

https://shi-works.github.io/plateau-lod1-bldg-pmtiles/#16.02/43.066866/141.347619/-115.2/76

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/205045/292a719b-75d9-a789-51dc-cdacffd47a30.png)

# 参考文献

https://qiita.com/Kanahiro/items/ceeb20c158b4c70b62b6

https://github.com/protomaps/PMTiles

https://github.com/felt/tippecanoe