🕳️

全国のボーリング調査を可視化しよう

に公開

ボーリングデータ3Dビューア - 18万本のボーリングをWebで可視化する

はじめに

KuniJibanで公開されているボーリングデータのXMLを解析し、3DTilesへ変換し、Cesiumで描画することによって可視化を行いました。サイトのURLは以下です。

https://soil-stack.groovyjovy.dev/map

2. データソースと課題

KuniJibanとは

KuniJiban(国土地盤情報検索サイト)は、国土交通省・土木研究所・港湾空港技術研究所が共同運営する地盤情報データベースです。2008年3月に公開され、全国の道路・河川・港湾等の公共事業で取得されたボーリング柱状図や土質試験結果を無償で閲覧することができます。

約20万本のボーリングデータが登録されており、現在でもデータの拡充が続いているようです。

従来の課題:2次元表現の限界

KuniJibanでは、ボーリングデータは従来2次元の柱状図として提供されてきました。地図上でボーリング地点を選択すると、柱状図をpngで閲覧できます。

しかし、この2次元表現には以下の課題がありました:

  • 空間的な把握が困難:複数のボーリングの位置関係や地層の連続性を直感的に理解しにくい
  • 周辺地形との関係が不明:標高や地形との対応を別途確認する必要がある
  • 大量データの俯瞰ができない:20万本ものデータを一度に概観することが難しい

前回の実装:PostGIS + Rails

実は以前、PostGIS + Ruby on Railsを使った可視化を実装していました。

[XMLファイル] → [Railsパーサー] → [PostgreSQL/PostGIS] → [WebAPI] → [Cesium]

この構成では、カメラの表示範囲(BBox)に応じてPostGISから動的にデータを取得し、GeoJSON形式でCesiumに渡していました。

しかし、プロトタイプを作成してみるとすぐに以下の問題が浮き彫りになってきました:

  • パフォーマンス:カメラ移動のたびにDBクエリが発生し、レスポンスが遅い
  • コスト:PostgreSQLサーバーを常時稼働させる必要がある
  • スケーラビリティ:データ量が増えるとクエリ負荷が増大

これらの課題から、事前にタイル化した静的ファイル配信へ方針転換しました。3D Tilesと呼ばれるしくみを採用することで、DBサーバーなしでストレージサービスへの静的ホスティングのみで運用できるようになります。

BED XML形式

KuniJibanのボーリングデータはBED(Boring Exchange Data)XML形式で提供されています。国土交通省が策定した土木業界の電子納品標準フォーマットです。

詳しくは別記事にまとめていますが、概要を説明します。

バージョンと分布

バージョン ファイル数 割合
Ver 4.00 46,541件 25%
Ver 3.00 31,446件 17%
Ver 2.10 109,349件 58%
Ver 1.10 878件 <1%

いくつかのバージョンが存在しており、ver 4.00が現行のバージョンです。Ver 2.10が過半数を占めているようです。

XMLの構造

各XMLファイルには以下の情報が含まれています:

  • 位置情報:緯度・経度(度分秒形式)、測地系コード
  • 基本情報:ボーリング名、総削孔長、孔口標高
  • 地質情報:地層区分、土質名、記号
  • 試験結果:標準貫入試験(N値)、地下水位

パース時の課題

BED XMLには解析行う上で少々扱いづらい特徴があります:

  1. DTDベースで型情報がない:XSDではなくDTDで定義されているため、XMLスキーマから型を取得できない。「この要素は数値」「この要素は列挙型」といった情報は、別途PDFの仕様書を参照する必要がある

  2. 測地系が混在:Tokyo測地系(2002年以前)、JGD2000、JGD2011が混在しており、WGS84への変換が必要となります

boring-parser:XMLパーサーの自作

上記の課題を解決すべく、Rustライブラリ boring-parser を自作しました。XMLファイルを放り込むといい感じの構造体を吐き出してくれます。

use boring_parser::boring_structs_400::Boring400;
use boring_parser::parser::Parse;

let boring = Boring400::parse_from_str(&xml_content)?;

大量のデータを扱う課題

約18万7千本のボーリングデータを3D可視化するにあたり、以下の技術的課題がありました:

  • データ量:全XMLファイルの解析・変換に要する処理時間
  • 描画性能:18万本の3Dオブジェクトをブラウザで滑らかに描画
  • ネットワーク:必要なデータのみを効率的にロード

これらの課題に対し、次章で説明する3D TilesとImplicit Tilingを採用することで解決しました。

3. 技術選定

3D Tiles

3D Tilesは、OGC(Open Geospatial Consortium)が策定した大規模3D地理空間データのストリーミング仕様です。

前述のPostGIS構成の課題を踏まえ、3D Tilesを選んだ理由を表にまとめました:

観点 PostGIS + API 3D Tiles
サーバー DB + APIサーバー必要 静的ファイルのみ
コスト 常時稼働コスト S3等で低コスト
LOD 自前実装が必要 仕様でサポート
キャッシュ クエリ結果のキャッシュもできるが面倒 CDNで容易

18万本のボーリングを常に全て描画するのは非現実的なので、ズームレベルに応じて表示内容を切り替える必要があり、LODの仕組みが必須でした。3D Tilesはこれを仕様レベルでサポートしています。

タイル生成ツールの自作

BED XMLから3D Tilesへの変換ツールは、既存のツールでは対応できない(しづらい)ため、Rustでフルスクラッチ実装しました。18万ファイルの処理を1分未満で完了できます。まだまだ早くはできるのですが、とりあえず動けばいいのでこの辺で...

フロントエンドはCesium + Resium(React統合)で実装しています。

4. 3D Tiles生成の実装

Implicit Tilingの採用

3D Tilesには2つのタイル構造があります:

  • Explicit Tiling:全タイルの情報をtileset.jsonに列挙
  • Implicit Tiling:タイル座標から自動的にURLを解決

18万本のボーリングでは数千〜数万のタイルが生成されるため、Explicit Tilingではtileset.jsonが巨大になります。Implicit Tilingならtileset.jsonは数KBで済み、必要なタイルのみを効率的にロードできます。

{
  "implicitTiling": {
    "subdivisionScheme": "QUADTREE",
    "availableLevels": 11,
    "subtrees": {
      "uri": "subtrees/{level}.{x}.{y}.subtree"
    }
  }
}

本実装では日本全域(経度122°〜154°、緯度20°〜46°)をLevel 0とし、Level 10まで4分木で分割します。

GLBとメタデータ拡張

各タイルのコンテンツはGLB(glTF Binary) 形式です。ボーリングの属性情報をクリック時に取得できるよう、以下のglTF拡張を使用しています:

  • EXT_mesh_features:メッシュの各部分(地層)にFeature IDを割り当て
  • EXT_structural_metadata:Feature IDに紐づくメタデータ(ボーリング名、深度、土質名等)を格納
  • CESIUM_primitive_outline:円柱の輪郭線(アウトライン)を描画

Cesium側ではscene.pick()でクリックした地層のFeature IDを取得し、PropertyTableから属性を読み出します。

LOD戦略:レベル別の表現

18万本を常に詳細表示するのは不可能なので、ズームレベルに応じて表現を変えています:

Level 表現 説明
4-6 クラスタマーカー タイル内のボーリングを集約し、件数を表示
7-9 個別マーカー ボーリング位置に円形マーカーを表示
10 円柱(詳細) 地層ごとに色分けした円柱を描画
  • Level 4-6(広域)
    ※タイル内のボーリングをグループ化しています。

  • Level 7-9(中域)

  • Level 10(詳細)

以上で3D Tilesの生成ができました。次に、フロントエンドで実装した主な機能を紹介します。

5. フロントエンドの実装

標高タイル

地形の起伏を表示するため、地理院標高タイルを使用しています。

Cesiumは標準でQuantized Mesh形式の地形に対応していますが、地理院標高タイルはPNG形式で標高値をエンコードしています。そこで、gsj_numerical_png_terrain_providerNumericalPngTerrainProviderを使用して読み込んでいます。

const terrainProvider = new NumericalPngTerrainProvider({
  url: 'https://tiles.gsj.jp/tiles/elev/land/{z}/{y}/{x}.png',
});

<Viewer terrainProvider={terrainProvider}>
  ...
</Viewer>

断面図機能

複数のボーリングを選択し、その断面図を描画する機能を実装しました。

  1. 画面左にあるハサミのマークをクリックし、「断面図モード」をONにする
  2. 地図上でボーリングを複数クリックして選択
  3. 選択順に断面図を生成

断面図はCanvasで描画し、地層の色分け・N値グラフ・水位線などを表示します。

内部的には、選択されたボーリング間の距離を計算し、直交座標系(X: 水平距離、Y: 標高)でデータを保持しています。このため、Canvas描画もDXF出力も同じ座標データをそのまま使えます。

DXFエクスポート

断面図をCADソフト(AutoCAD、QCAD等)で編集できるよう、DXF形式でエクスポートする機能も実装しました。

前述の通り断面図データは直交座標で管理しているため、Canvas描画用のロジックをほぼそのままDXF生成に流用できます。線分・ポリライン・テキストを出力し、地層の色分けも維持されます。

6. 追加したい機能

  • ボーリング柱状図テクスチャ
    • (おそらく)仕様が厳密に決められておらず、KuniJibanを完全再現することは叶いませんでした。いずれは実装してみたいです。
  • ボーリングの色
    • こちらもKuniJibanではなんらかの法則性を持って実装しているようですが、再現することは叶いませんでした。

Discussion