toggle Engineer Blog

トグルホールディングス株式会社のエンジニアブログでは、私たちの技術的な挑戦やプロジェクトの裏側、チームの取り組みをシェアします。

PLATEAUの3D建物データを用途別に色分けして地図表示する

PLATEAUの3D建物をMapboxで手軽に可視化する

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地図の様子もご覧ください

3D建物なしのビュー

  • 建物用途の種類が多いので、グループ分けをして、グループごとに色を決めました。
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
}

横浜市川崎市、東京23区の対比と災害リスク情報

PLATEAUデータの準備と注意点

データ変換時のプロセス

PLATEAUデータをWeb表示用に変換する際は、以下のステップが必要です:

  1. CityGML → GeoJSON変換
  2. 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で表示することで、以下のメリットが得られました:

  1. 開発期間の短縮

    • 一般的なWebフレームワーク(React)が使用可能
    • 豊富なサンプルコードやライブラリが利用可能(DeckGLのMVTレイヤーは事例豊富です)
  2. 運用コストの削減

    • ReactプロジェクトのpublicフォルダにPLATEAUの建物データを置くだけで済みます
  3. メンテナンス性の向上

    • Webの標準技術での実装
    • データの動的更新が容易
      • 描画エリアの拡大も、PLATEAUデータを変換して、publicに置くだけです

従来のゲームエンジンを使用した実装と比べ、より手軽にPLATEAUデータの可視化が実現できます。
ぜひ皆さんもMapboxでの実装を検討してみてください!

なお、私は10月からTypeScript, Reactを始めたばかりで、それまではPython中心にコーディングをしてきたので、TypeScriptのルールやマナーを知らず色々と苦労しましたが、このような地図が作成できました。
豊富なデータを提供してくださるPLATEAUプロジェクト、どんどん機能が拡充しているMapboxに、とてもとても感謝しております。
地図の沼へ、一緒にハマりましょう!

参考リンク