PLATEAUの3D建物をMapboxで手軽に可視化する
こちらはtoggle engineer blogで2024年12月6日(金)にポストした記事です。
トグルホールディングスのグループ会社つくるAIのmapチームのエンジニアの火原です。
今回は、国土交通省が提供する3D都市モデルデータ「PLATEAU」を使って、Web上で3D地図を作成する方法をご紹介します。
ポイントは、従来のUnityやUnreal Engineではなく、Mapboxを使用したアプローチです。これにより、より手軽で低コストな実装が可能になります。
なぜMapboxなのか?
従来のPLATEAU可視化では、以下のような課題がありました:
- Unityの場合、WebGLビルドの容量が大きい
- Unreal Engineの場合、サーバーリソースが必要
- どちらも開発コストと実行環境の要件が高い
- 私はUnityもUnreal Engineも使ったことがないので、私にとって学習コストが高い
一方、Mapboxを使用すると:
- ブラウザだけで動作(追加のプラグイン不要)
- 軽量で高速な表示が可能
- Reactで実装可能
実装例
今回は、PLATEAUの建物用途に応じて建物を色塗りした地図を作成します。
- 地図の範囲は東京都23区、川崎市、横浜市にしてみました。
- マウスを建物の上に置くと、建物の情報が追加されるホバー機能もつけてみました。
- mapboxの地図を使うので、mapboxのアクセストークンが必要になりますが、無料の範囲でもたっぷり使えます。
1. 基本的なセットアップ
mapboxの地図に、PLATEAUの建物のレイヤーを追加するシンプルなモデルはこちらです。
レイヤー作成にはDeckGLを使います。
PLATEAUのCityGMLデータをmapbox向けのMVTタイル形式に変換して読み込むことで、サクサク描画するようにしています。
// App.tsx
import 'mapbox-gl/dist/mapbox-gl.css'
import Map from 'react-map-gl'
import DeckGL from '@deck.gl/react/typed'
const MAPBOX_TOKEN = 'YOUR_MAPBOX_TOKEN'
# 初期視点は東京駅に設定しました
const INITIAL_VIEW_STATE = {
longitude: 139.7670,
latitude: 35.6810,
zoom: 14,
pitch: 45,
bearing: 0
}
export default function App() {
const [viewState, setViewState] = useState(INITIAL_VIEW_STATE)
const plateauLayer = usePlateauBuildingLayer('plateau-buildings')
return (
<DeckGL
viewState={viewState}
onViewStateChange={({ viewState }) => setViewState(viewState)}
layers={[plateauLayer]}
controller={true}
getTooltip={({object}) => object && ({
html: formatTooltip(object.properties)
})}
>
<Map
mapboxAccessToken={MAPBOX_TOKEN}
mapStyle="mapbox://styles/mapbox/light-v10"
/>
</DeckGL>
)
}
2. 建物用途による色分け
- 東京都23区は、2023年版で、建物のプロパティの'buildingDetailAttribute.0.detailedUsage'を参照して、建物用途の種類を決めて色を決めます。
- 川崎市は、2022年版で、建物のプロパティの'usage.0'を参照して、建物用途の種類を決めて色を決めます。
- 横浜市は、2023年版で、建物のプロパティには用途が記述されていないので、デフォルトで全て灰色で描画します。
legendはこんな感じにしました。
3D建物レイヤーを表示しないプレーンなMapbox地図の様子もご覧ください
- 建物用途の種類が多いので、グループ分けをして、グループごとに色を決めました。
const getBuildingUsage = (properties: BuildingProperties): string | undefined => {
// 23区と川崎市で異なる属性名に対応
if (properties['buildingDetailAttribute.0.detailedUsage']) {
return properties['buildingDetailAttribute.0.detailedUsage']
}
if (properties['usage.0']) {
return properties['usage.0']
}
return undefined
}
- 色設定は用途ごとにグループ化して管理:
export const PLATEAU_USEING_COLORS = {
// 商業系は赤系統
商業施設: [235, 85, 85, 200],
事務所建築物: [235, 145, 145, 200],
// 公共系は青系統
医療施設: [65, 105, 225, 200],
教育施設: [85, 120, 225, 200],
// 住宅系は緑系統
独立住宅: [95, 185, 95, 200],
集合住宅: [115, 185, 115, 200]
// ...
}
3. 災害リスク情報の表示
建物の保持している情報には、災害リスク情報があります。
東京都23区、川崎市、横浜市の今回の対象エリアは、全て、災害リスク情報は保持していました。
建物によって、災害リスクがなしのものも、複数のものもあり、災害リスク情報の件数が決まっていないことを前提に対応します。
- 建物ごとの複数の災害リスク情報を効率的に取得:
const getAllDisasterRisks = (properties: BuildingProperties): DisasterRisk[] => {
const risks: DisasterRisk[] = []
let index = 0
while (true) {
const description = properties[`buildingDisasterRiskAttribute.${index}.description`]
if (!description) break
risks.push({
description,
rank: properties[`buildingDisasterRiskAttribute.${index}.rank`],
depth: properties[`buildingDisasterRiskAttribute.${index}.depth`],
scale: properties[`buildingDisasterRiskAttribute.${index}.scale`]
})
index++
}
return risks
}
PLATEAUデータの準備と注意点
データ変換時のプロセス
PLATEAUデータをWeb表示用に変換する際は、以下のステップが必要です:
- CityGML → GeoJSON変換
- GeoJSON → MVT(Mapbox Vector Tile)変換
この変換プロセスでは、特に以下の点に注意が必要です:
- 高いメモリ要求
- GeoJSON変換時に大量のメモリを消費
- 32GB以上のメモリを搭載したマシンでの作業を推奨
- MVT形式はタイルを作成するので、隣接区域はまとめて処理する必要があります
- データサイズ
- テクスチャを除いた建物データのみでも、MVTファイルは約2.4GB
$ du -sh public/mvt
> 2.4G public/mvt
- データを以下の形式で置くだけで、サーバーを立てるような手間なく、建物が描画されます。
public/mvt/{z}/{x}/{y}.pbf
. - ここがMVTタイル形式のメリットだと感じました。
CityGMLからMVTへの変換に関するtipsは、ニーズが高いようでしたら、別の機会に書かせていただきますね。
まとめ
PLATEAUの3D都市モデルデータをMapboxで表示することで、以下のメリットが得られました:
-
開発期間の短縮
- 一般的なWebフレームワーク(React)が使用可能
- 豊富なサンプルコードやライブラリが利用可能(DeckGLのMVTレイヤーは事例豊富です)
-
運用コストの削減
- ReactプロジェクトのpublicフォルダにPLATEAUの建物データを置くだけで済みます
-
メンテナンス性の向上
- Webの標準技術での実装
- データの動的更新が容易
- 描画エリアの拡大も、PLATEAUデータを変換して、publicに置くだけです
従来のゲームエンジンを使用した実装と比べ、より手軽にPLATEAUデータの可視化が実現できます。
ぜひ皆さんもMapboxでの実装を検討してみてください!
なお、私は10月からTypeScript, Reactを始めたばかりで、それまではPython中心にコーディングをしてきたので、TypeScriptのルールやマナーを知らず色々と苦労しましたが、このような地図が作成できました。
豊富なデータを提供してくださるPLATEAUプロジェクト、どんどん機能が拡充しているMapboxに、とてもとても感謝しております。
地図の沼へ、一緒にハマりましょう!
参考リンク
- PLATEAU:https://www.mlit.go.jp/plateau/
- Mapbox GL JS:https://docs.mapbox.com/mapbox-gl-js/
- deck.gl:https://deck.gl/