2025年10月17日金曜日

xeoglを使ってブラウザに東京都デジタルツインの点群データを表示する

Oracle Databaseにアップロードした点群データをブラウザに表示する方法をChatGPTに聞いてみたところ、そのような用途にはxeoglというJavaScriptライブラリが使えると勧められました。コード生成についてはClaude Sonnet 4.5の方が精度が高いので、Claudeでサンプルとなる点群データを生成し、xeoglで表示するHTMLページを作ってもらいました。こちらがそのコードになります。

Claudeが生成したコードを元に、東京都デジタルツイン実現プロジェクト区部点群データのLasデータをブラウザに表示するAPEXアプリケーションを作成してみました。

作成したAPEXアプリケーションは以下のように動作します。ページ左の選択リストで、アップロードしたメッシュを選択して表示します。ズームなどのカメラのコントロールはAPEXのページ・アイテムにスライダーが無かったため、リージョンにタイプがrangeのINPUT要素を直に記述しています。


カメラ・コントールについてはClaudeが生成したコードをほぼそのまま流用していて、あまり動作について精査できていません。動かしている限りでは、概ね期待した動作はしています。

以下よりAPEXアプリケーションの作成手順を簡単に紹介します。

最初に、データベースにロードするLasデータをダウンロードします。東京都デジタルツイン実現プロジェクトの区部点群データのオリジナルデータ(DSM)及びグランウドデータ(DEM)のページより、東京駅付近の09LD1884、09LD1885、09LD1894、09LD1895のメッシュを選択しダウンロードしました。他のメッシュは試していませんが表示できると思います。

この4つのメッシュ(Lasファイル)で合計1GB弱、CSVに変換すると1GBを超えます。Oracle Database Freeのような無料で使えるOracle Databaseの場合、サーバー側のリソースが潤沢ではないので、データベースに保存できるデータ量も限られていますし、また、サーバーが利用できるメモリも限られているため、1つのメッシュに含まれる点群も間引かないと(今回は1/10に間引きました)ブラウザにデータを返すことができません。


上記の4つのメッシュはZIPファイルとしてダウンロードされます。それらをunzipで解凍すると、それぞれ09LD1884.las、09LD1885.las、09LD1894.las、09LD1895.lasが作成されます。

これらのLasデータを含むファイルをCSVに変換します。変換にはLAStoolsに含まれるlas2txt64を使用します。LAStoolsの導入はプラットフォームごとに手順が異なります。本記事の作業で使用しているmacOSでは、リポジトリをクローンしてビルドしています。ビルド手順についてはこちらの記事で紹介しています。

ダウンロードしたZIPファイルが存在するディレクトリより、SQLclでLasデータのロード先となるデータベースに接続し、以下のスクリプトを実行します。この後の作業で、アップロードした点群データを表示するAPEXアプリケーションを作成するため、接続先はAPEXのワークスペース・スキーマにします。


tokyo_pc % sql wksp_apexdev@localhost/freepdb1                                  



SQLcl: 金 10月 17 11:42:07 2025のリリース25.2 Production


Copyright (c) 1982, 2025, Oracle.  All rights reserved.


パスワード (**********?) ******

接続先:

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.9.0.25.07


SQL> @prepare_tokyo_point_clouds


Table TOKYO_POINT_CLOUDSが削除されました。



Table TOKYO_POINT_CLOUDSは作成されました。


Archive:  09LD1874.zip

  inflating: 09LD1874.las            




csv

column_names off

delimiter ,

enclosures ""

double off

encoding UTF8

row_limit off

row_terminator default

skip_rows 0

skip_after_names


データを表にロードします WKSP_APEXDEV.TOKYO_POINT_CLOUDS

batch_rows 10000

batches_per_commit 10

clean_names transform

column_size rounded

commit on

date_format 

errors 50

map_column_names off

method insert

timestamp_format 

timestamptz_format 

locale

scan_rows 100

truncate off

unknown_columns_fail on


#INFO 処理された行数: 6,385,968

#INFO エラーのある行数: 0

#INFO 最後にコミットされたバッチで処理された最後の行: 6,385,968

成功: エラーなしで処理されました


6,385,968行更新しました。



コミットが完了しました。


[09LD1875, 09LD1884, 09LD1885のメッシュ分、繰り返し]


Table TOKYO_POINT_CLOUD_TILESが削除されました。



Table TOKYO_POINT_CLOUD_TILESは作成されました。


Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.9.0.25.07から切断されました

tokyo_pc %


以上でデータの準備は完了です。

APEXアプリケーションの作成に移ります。

空のAPEXアプリケーションを作成します。名前xeogl point cloudとします。


アプリケーションが作成されます。機能はすべてホーム・ページに実装します。

ページ・デザイナでホーム・ページを開き、ページのデザインから始めます。


表示するタイルの選択とカメラのコントールを配置するリージョンを作成します。

識別名前Controls外観テンプレートBlank with Attributesを選択します。このリージョンは、タイル選択のリージョンとカメラ・コントロールのリージョンを横並びにするために作成しています。


タイル選択のためのリージョンTile Selectionを、リージョンControlsサブ・リージョンとして作成します。タイルIDはそれほど長い値ではないので、レイアウト列スパンを指定します。


表示するタイルを選択するページ・アイテムP1_TILE_IDを作成します。タイプ選択リストラベルTile IDとします。

LOVタイプSQL問合せを選択し、SQL問合せとして以下を記述します。

select tile_id d, tile_id r from tokyo_point_cloud_tiles 

追加値の表示オフにします。


選択したタイルの点群をブラウザに表示するボタンDRAWを作成します。動作アクション動的アクションで定義とします。


ボタンDRAWをクリックしたときに実行される動的アクションをonClick DRAWとして作成します。TRUEアクションJavaScriptコードの実行を選択し、設定コードに以下を記述します。

createPointCloud();

ファンクションcreatePointCloudは静的アプリケーション・ファイルに記述し、ページ・ロード時にロードします。


リージョンControlsに、カメラ・コントロールを含むサブ・リージョンを作成します。名前Zoomとします。

タイプ静的コンテンツソースHTMLコードとして以下を記述します。直書きされたINPUT要素はAPEXのページ・アイテムとしては扱えませんが、APEXのアプリケーションで作れないわけではありません。
<label>ズーム: <span id="zoomValue">400</span></label>
<input type="range" id="zoom" min="-600" max="0" value="0" step="5">
<label>水平回回転: <span id="yawValue">0</span>°</label>
<input type="range" id="yaw" min="-180" max="180" value="0" step="5">     
<label>垂直回転: <span id="pitchValue">0</span>°</label>
<input type="range" id="pitch" min="-89" max="89" value="0" step="5">
<label>中心座標 X: <span id="centerXValue">81308.9</span></label>
<input type="range" id="centerX" min="-800000" max="800000" value="0" step="5">
<label>中心座標 Y: <span id="centerYValue">-35609.3</span></label>
<input type="range" id="centerY" min="-800000" max="800000" value="0" step="5">
<label>中心座標 Z: <span id="centerZValue">10</span></label>
<input type="range" id="centerZ" min="-100" max="800" value="0" step="5">
リージョンTile Selectionの右隣に配置するため、レイアウト新規行の開始オフにします。


xeoglで使用するCANVAS要素を配置するリージョンを作成します。名前xeoglとします。

ソースHTMLコードに以下を記述します。

<canvas id="myCanvas" style="width:100%; height:800px"></canvas>

装飾は不要なので外観テンプレートBlank with Attributesを選択します。


ページ・プロパティCSSインラインに以下を記述します。
#myCanvas {
    background: linear-gradient(to bottom, #1a1a2e, #0f0f1e);
}
input[type="range"] {
    width: 100%;
}

以上でページのデザインは完成です。アプリケーションを実行すると、ホーム・ページが以下のように表示されます。


APEXアプリケーションにコードを埋め込みます。

データベースから点群データを取り出すAjaxコールバックを、GET_POINT_CLOUDSとして作成します。

ソースPL/SQLコードとして以下を記述します。

メッシュに含まれるすべての点群を取り出すにはサーバーのメモリが足りないため、点群を取り出すにあたってSAMPLE(10)を付加し、取り出すデータを10%(1/10)に削減しています。



静的アプリケーション・ファイルとしてapp.jsを作成します。ファイルには以下のコードを記述します。



ページ・プロパティJavaScriptファイルURLに以下を記述し、ページ・ロード時にxeoglのライブラリと静的アプリケーション・ファイルapp.jsをロードするようにします。

https://cdn.jsdelivr.net/npm/xeogl@0.9.0/build/xeogl.min.js
#APP_FILES#app#MIN#.js


以上でアプリケーションは完成です。

アプリケーションを実行すると、タイルとして09LD1884、09LD1885、09LD1894、09LD1895が選択でき、それぞれをページに表示することができます。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/xeogl-point-cloud.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。