はじめに
この記事は 3D都市モデル Project PLATEAU Advent Calendar 2023 2日目の記事です。
3D都市モデル PLATEAU LT 05で@_shimizuさんが発表されていた、deck.glのTerrainExtensionを用いた事例を参考にさせていただきながら、3D都市モデルPLATEAU 3DTiles+GeoJSONで3D主題図を作成してみました。具体には、3D都市モデルPLATEAU 3DTilesと国土数値情報の用途地域データ(2019年)を組み合わせて、用途地域名で色分けした3D主題図を作成してみました。
アウトプットイメージ
deck.glとは
- オープンソースの地図ライブラリーです。
- WebGLによる可視化フレームワークで、大規模なデータセットをサポートしており、2Dおよび3Dデータの可視化を行えます。
- もともとはUber社が開発していましたが、現在はUrban Computing Foundationに移管されています。
- 可視化のための様々なレイヤーが用意されています。
Tile3DLayer
- 3Dタイルデータ(3DTilesなど)を読み込み、地図上に表示するレイヤです。
- 3D都市モデルPLATEAU 3DTilesを表示するために使用します。
GeoJsonLayer
- GeoJSONデータを読み込み、地図上に表示するレイヤです。
- 国土数値情報の用途地域データを表示するために使用します。
2D主題図と3D主題図の比較
- 通常、3D都市モデルPLATEAU 3DTilesと国土数値情報の用途地域データ(2019年)の2つのレイヤをdeck.glで重ねて表示すると下図のようになり、用途地域の2Dデータの一部が建物の3Dモデルに隠れてしまいます。
- 一方で、deck.glのTerrainExtensionを用いると、用途地域の2Dのデータが建物の3Dモデルのサーフェイスに沿ってレンダリングされ、3Dモデルのサーフェイスに2Dのデータがオーバレイされます。
ただし、TerrainExtensionは、現時点では実験的な位置付けの機能です。また、負荷が高く、巨大なGeoJSONをオーバレイすると固まります。
デモサイト
ソースコードと解説
- 全体のソースコードは、下記のGitHubから入手してください。
Tile3DLayer
-
onTileLoad
以下は、3Dモデルの高さをマップ平面に合うようにするための調整です。 - 詳細については、下記のブログ記事が詳しいです。
-
operation: 'terrain+draw'
とすることで、deck.glのTerrainExtensionが機能します。
// PLATEAU-3DTiles
new deck.Tile3DLayer({
id: "tile3dlayer",
data: 'https://plateau.geospatial.jp/main/data/3d-tiles/bldg/13100_tokyo/13104_shinjuku-ku/low_resolution/tileset.json', // 新宿区
loader: Tiles3DLoader,
opacity: 1,
pickable: false,
onTileLoad: d => {
const { content } = d;
const buffer = content.batchTableBinary.buffer;
const key = content.batchTableJson;
const len = key._gml_id.length;
const zMinView = new DataView(buffer, key._zmin.byteOffset, len * 8);
const zMins = [];
for (let i = 0; i < len; i++) {
zMins.push(zMinView.getFloat64(i * 8, true));
}
zMins.sort((a, b) => a - b);
content.cartographicOrigin.z -= 36.9702 + zMins[Math.floor(len / 2)];
},
operation: 'terrain+draw'
}),
GeoJsonLayer
-
getFillColor
国土数値情報の用途地域データの属性「用途地域コード(A29_004)」をもとに、色分けを行っています。 - 用途地域コード(A29_004)のコード表は下記を参照してください。
-
extensions: [new deck._TerrainExtension()]
とすることで、deck.glのTerrainExtensionが機能します。
// 用途地域(TerrainExtension)
new deck.GeoJsonLayer({
id: 'youtochiiki-1',
data: data,
stroked: false,
filled: true,
getFillColor: ({ properties }) => {
const { A29_004 } = properties;
if (A29_004 == 1)
return [0, 178, 133]
else if (A29_004 == 2)
return [145, 207, 185]
else if (A29_004 == 3)
return [120, 206, 63]
else if (A29_004 == 4)
return [173, 223, 33]
else if (A29_004 == 5)
return [235, 238, 94]
else if (A29_004 == 6)
return [255, 210, 182]
else if (A29_004 == 7)
return [255, 166, 56]
else if (A29_004 == 8)
return [255, 176, 195]
else if (A29_004 == 9)
return [255, 89, 61]
else if (A29_004 == 10)
return [167, 148, 197]
else if (A29_004 == 11)
return [185, 234, 255]
else if (A29_004 == 12)
return [95, 197, 251]
else if (A29_004 == 21)
return [196, 215, 155]
},
opacity: 0.5,
extensions: [new deck._TerrainExtension()]
}),
おわりに
deck.glのTerrainExtensionを用いて、3D都市モデルPLATEAU 3DTiles+GeoJSONで3D主題図を作成してみました。deck.glのTerrainExtensionを使用すると、主題図と3Dモデルを組み合わせて、様々な表現が可能です。例えば、国土数値情報の用途地域データには、用途地域名のほかに容積率などの属性を持っていますので、3D都市モデルPLATEAU 3DTilesと組み合わせて、容積率マップを作ってみるなど、面白そうな試みができそうです。容積率マップは、にゃんこそば(@ShinagawaJP)さんの書籍で紹介されていました。