フリーソフトで2D断面作成
iPhone LiDAR(Scaniverse)とCloudCompareで作る!手軽で高精度な3D断面➡2D断面図の作成手順
iPhoneアプリ「Scaniverse」で取得した点群データから、CADで使える2次元の横断図(距離と標高のプロット)をサクッと作成する一連のワークフローをご紹介します!
現地での調査からCAD作業に入るまでの時間を劇的に短縮できるので、ぜひ試してみてください。
STEP 1:Scaniverseでデータ取得
まずは現場でiPhoneを使い、対象となる地形や水路などをScaniverseでスキャンします。取得した3Dモデルは、点群データとして「LAS形式」でエクスポートし、PCに取り込みます。
STEP 2:CloudCompareへの取り込みとノイズ除去
PCで無料の点群処理ソフト「CloudCompare」を立ち上げ、LASデータを読み込みます。
自然地形をスキャンすると、雑草や落ち葉、スキャン時のブレによる空中のノイズが含まれるため、以下の方法で事前に綺麗にしておきます。
- SORフィルターで自動除去:
Tools > Clean > SOR filterを使い、空中に浮いた細かい孤立点を一掃します。 - ハサミツールで手動カット: 明らかに邪魔な草などは、画面上部のハサミアイコン(Segmentツール)で囲って切り取ります。これが一番確実です。
STEP 3:3D断面(DXF)の抽出
綺麗になった点群から断面を切り出します。
- メニューの「Cross Section(断面ツール)」を起動。
- 枠(クリッピングボックス)のサイズを調整します。ここで重要なのが「スライスの厚み(Z軸など奥行き方向)を限界まで薄くする(デォでok)」こと!分厚いと手前と奥のノイズを拾ってしまい、断面がギザギザになってしまいます。
- パネルの「点群の抽出ボタン(緑の下矢印)」を押し、切り出された点群をDXF形式で保存します。
(注意:この時、出力された3DのDXFをLibreCADなどの2D専用CADで開いて上書き保存しないでください。高さデータが消えてしまいます)
STEP 4:Pythonで2D DXFへ一括変換
CloudCompareから出力したDXFは「3Dデータ」のため、真上から見るとただの直線になってしまいます。CADで横断面として扱うために「X軸=水平距離、Y軸=最低地点からの比高」に計算し直した2Dデータへ変換します。
今回は、指定したフォルダ内にあるすべてのDXFファイルを一括で2次元化するPythonスクリプトを作成しました。以下のコードをコピーして実行するだけで、一瞬で変換が完了します!
import os
import glob
import math
import re
import tkinter as tk
from tkinter import filedialog
def batch_convert_to_2d_dxf():
# 画面を隠す
root = tk.Tk()
root.withdraw()
# フォルダ選択ダイアログ
dir_path = filedialog.askdirectory(title="DXFファイルが入っているフォルダを選択してください")
if not dir_path:
print("フォルダ選択がキャンセルされました。")
return
print(f"選択されたフォルダ: {dir_path}")
# フォルダ内のdxfファイルを検索(すでに変換済みの _2D.dxf は除外)
search_pattern = os.path.join(dir_path, "*.dxf")
all_dxf_files = glob.glob(search_pattern)
target_files = [f for f in all_dxf_files if not f.lower().endswith("_2d.dxf")]
if not target_files:
print("変換対象のDXFファイルが見つかりませんでした。")
return
print(f"\n{len(target_files)}個のファイルを一括処理します...\n")
success_count = 0
for file_path in target_files:
print(f"処理中: {os.path.basename(file_path)}")
try:
with open(file_path, 'r', encoding='shift_jis', errors='ignore') as f:
dxf_text = f.read()
# X, Y, Z座標を抽出
pattern = r"10\n\s*([-\d\.]+)\n\s*20\n\s*([-\d\.]+)\n\s*30\n\s*([-\d\.]+)"
matches = re.findall(pattern, dxf_text)
vertices = [(float(m[0]), float(m[1]), float(m[2])) for m in matches]
# ダミー座標(0,0,0)を除外
vertices = [v for v in vertices if v != (0.0, 0.0, 0.0)]
if not vertices:
print(f" -> スキップ: 有効な頂点データがありませんでした。")
continue
# 地盤の最低標高を取得し、それをY=0の基準とする
min_z = min(v[2] for v in vertices)
p2d_vertices = []
accum_dist = 0.0
prev_x, prev_y, prev_z = vertices[0]
p2d_vertices.append((0.0, prev_z - min_z, 0.0))
for i in range(1, len(vertices)):
cx, cy, cz = vertices[i]
# ピタゴラスの定理で水平距離を計算
dist_step = math.sqrt((cx - prev_x)**2 + (cy - prev_y)**2)
accum_dist += dist_step
# 最低地点からの比高をY座標にセット
relative_y = cz - min_z
p2d_vertices.append((accum_dist, relative_y, 0.0))
prev_x, prev_y, prev_z = cx, cy, cz
# シンプルな2D DXFを組み立て
output_dxf = [
" 0", "SECTION",
" 2", "ENTITIES",
" 0", "POLYLINE",
" 8", "0",
" 66", "1",
" 70", "0",
" 10", "0.0", " 20", "0.0", " 30", "0.0"
]
for vx, vy, vz in p2d_vertices:
output_dxf.extend([
" 0", "VERTEX",
" 8", "0",
" 10", f"{vx:.6f}",
" 20", f"{vy:.6f}",
" 30", f"{vz:.6f}"
])
output_dxf.extend([" 0", "SEQEND", " 8", "0", " 0", "ENDSEC", " 0", "EOF"])
# 保存
base_name = os.path.splitext(os.path.basename(file_path))[0]
out_file_path = os.path.join(dir_path, f"{base_name}_2D.dxf")
with open(out_file_path, 'w', encoding='shift_jis') as f:
f.write("\n".join(output_dxf))
print(f" -> 成功: {len(p2d_vertices)}頂点 (最低標高 {min_z:.2f}m基準)")
success_count += 1
except Exception as e:
print(f" -> エラー: {e}")
print(f"\n完了! {len(target_files)}ファイル中、{success_count}ファイルの変換に成功しました。")
if __name__ == "__main__":
batch_convert_to_2d_dxf()
input("Enterキーを押して終了...")
STEP 5:CADで読み込んで仕上げ
出力された _2D.dxf をAutoCADなどのCADソフトで開きます。
すでに平面上のグラフとして展開されているので、視点変更の必要はありません。
高価な専用システムがなくても、このワークフローなら高精度かつスピーディーに現況断面を取得できます。ぜひお試しください!
もちろん、QGISでも標高断面図から2D-dxf出力できるが断面幅が広く、加工が必要。
返信削除