[Astro] #112 Point Cloud Viewer v7 — 任意直線断面+SOR進捗表示
概要
前回[#111]で計測ラベル3D表示・元座標復元・Voxel Downsamplingを追加した。今回は「任意直線断面」と「SOR進捗表示」の2機能を追加する。
[Astro] #111 Point Cloud Viewer v6 — 計測ラベル3D表示・元座標復元・Voxel Downsampling
計測結果の3D Spriteラベル表示、LAS元座標オフセット保持、Voxel Downsamplingを追加。
lain-lab.com今回の追加機能
| 機能 | 概要 |
|---|---|
| 任意直線断面 | 2点クリックで自由角度の垂直断面を定義→プロファイル生成→DXFエクスポート |
| SOR進捗表示 | K近傍計算をチャンク分割し、進捗パーセンテージをリアルタイム表示 |
スクリーンショット
任意直線断面
SOR進捗表示
「Apply SOR Filter」でフリーズしていたのを
動画(GIF)
任意直線断面
v5の軸平行スライスとの違い
v5の断面機能は軸平行(X/Y/Z軸に平行な面)でしか断面を取れなかった。道路の横断面を取りたい場合、道路がX軸やZ軸と平行でなければ正しい断面にならない。
今回の「任意直線断面」は、ユーザーが3Dビュー上で2点をクリックするだけで、その2点を通る任意角度の垂直断面を定義できる。
使い方
- TOOL → Section をクリック
- 点群上で2点クリック(S1, S2がオレンジで表示される)
- Thicknessスライダーで断面の厚さを調整(デフォルト0.01)
- Generate Section → 断面プロファイルが緑ラインで表示
- Export DXF → CADソフトで開ける
断面の数学
S1→S2のXZ方向ベクトルに対して法線方向を計算し、垂直平面を定義する。
// S1→S2のXZ方向ベクトル
const lineDirXZ = new THREE.Vector2(p2.x - p1.x, p2.z - p1.z);
lineDirXZ.normalize();
// 法線(水平面内で直交する方向)
const normalX = -lineDirXZ.y;
const normalZ = lineDirXZ.x;
各点について:
- 面までの距離を計算 → thickness/2以内なら抽出
- ライン方向の位置を計算 → ソートに使用
- ビン分割して各ビンの最高点(地表面)を抽出
for (let i = 0; i < count; i++) {
const qx = positions.getX(i) - p1.x;
const qz = positions.getZ(i) - p1.z;
// 面までの距離
const dist = qx * normalX + qz * normalZ;
if (Math.abs(dist) > halfThick) continue;
// ライン方向の位置
const along = qx * lineDirXZ.x + qz * lineDirXZ.y;
extracted.push({ along, height: positions.getY(i), pos: ... });
}
土木での用途
- 道路の横断面: 斜めに走る道路でも正しい断面が取れる
- 河川の断面: 蛇行する河川の任意地点での断面
- 法面の傾斜確認: 崖の任意方向での断面形状
- 施工前後の比較: 同じラインで切った断面を重ね合わせ
SOR進捗表示
問題:200万点のSORが15分フリーズ
SOR(統計的外れ値除去)は各点について近傍K点を探索し、平均距離を計算する。200万点でK=10の場合、約200万×近傍探索×ソートの計算量になる。これがメインスレッドで同期実行されるため、UIが15分間固まっていた。
解決:チャンク分割+非同期進捗表示
K近傍計算ループを50,000点ごとのチャンクに分割し、各チャンク間でsetTimeout(0)を挟んでUIスレッドに制御を返す。既存のloadingオーバーレイに進捗を表示する。
const CHUNK = 50000;
for (let start = 0; start < count; start += CHUNK) {
const end = Math.min(start + CHUNK, count);
const pct = Math.round((start / count) * 100);
setLoading(`SOR: K近傍計算中... ${pct}% (${start.toLocaleString()} / ${count.toLocaleString()})`);
await new Promise((r) => setTimeout(r, 0));
for (let i = start; i < end; i++) {
// K近傍計算...
}
}
これによりSOR実行中もスピナーと進捗パーセンテージが表示され、処理がフリーズしたのか進行中なのかが分かるようになった。
今後の改善
SOR自体の処理速度は変わっていない(15分は15分のまま)。本質的な高速化にはWeb Workerでのバックグラウンド実行が必要。メインスレッドから完全に分離すれば、SOR中もカメラ操作が可能になる。
また、SORのフィルタリングで従来はcolorのみ保持していたが、intensity/classificationも保持するように修正した。
変更ファイル
| ファイル | 変更内容 |
|---|---|
| PointCloudApp.tsx | crossSection state/handler追加、SOR async化+チャンク分割+intensity/classification保持 |
| PointCloudScene.tsx | crossSection click対応、S1/S2マーカー+ライン描画 |
| ControlPanel.tsx | Sectionボタン、thickness/generate/clear/DXF UI追加 |
まとめ
- v1: PLY読み込み、ヒートマップ、スライス、計測、SOR
- v2: LAS/PCD読み込み、200万点サンプリング、正規化
- v3: LAZ読み込み、XYZ/CSV入出力、ローディング
- v4: Intensity/Classification表示、LAS/PCD/スクショエクスポート
- v5: ボックス選択+削除、断面ポリライン+DXF、Octree LOD、座標系変換
- v6: 計測ラベル3D表示、元座標復元、Voxel Downsampling
- v7: 任意直線断面+DXF、SOR進捗表示
今後の課題
- SOR高速化(Web Worker化 — メインスレッドから完全分離)
- Octreeに全点対応(サンプリング前の数千万点を扱う)
- カメラパスアニメーション(ウォークスルー録画)
- メッシュ化(Delaunay / Poisson Reconstruction)