Files
massive-cloud/server/plugins/adapters/underframe_deflection_run.py

181 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""underframe-deflection 算法适配器 (v1.1)。
v1.1 变更:
- 入口改为 run_measurement_pipeline(返回 dict,同时落盘 report.json / xlsx / PLY)
- 新增 cad_path(CAD 基准 PLY/STL)和 roi_path(ROI JSON)可选输入
- 新增 skip_registration / enable_bilateral 配置项
- PYTHONPATH 指向 delivery_v1.1
- 结果从 report dict 中读取,而非 DeflectionResult 对象字段
"""
from __future__ import annotations
import os
import sys
import traceback
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from _plugin_io import (
emit_progress,
ensure_ascii_ply,
first_pointcloud,
load_input,
write_error_result,
write_result,
)
def _status_for(value: float | None, tolerance: float | None) -> str:
if value is None or tolerance is None:
return "info"
if abs(value) <= tolerance:
return "pass"
if abs(value) <= tolerance * 1.5:
return "warning"
return "fail"
def _safe_float(v: object) -> float | None:
try:
return float(v) # type: ignore[arg-type]
except (TypeError, ValueError):
return None
def main() -> int:
payload = load_input(sys.argv)
inputs = payload.get("inputs") or {}
config = inputs.get("config") or {}
out_dir = Path(payload["outDir"])
out_dir.mkdir(parents=True, exist_ok=True)
try:
emit_progress(0.05, "加载 underframe_deflection v1.1 算法包")
from underframe_deflection.pipeline import run_measurement_pipeline # type: ignore
pc_path = first_pointcloud(payload)
emit_progress(0.15, f"读取点云:{os.path.basename(pc_path)}")
# 若是二进制 PLY,先转成 ASCII PLY(算法内置 reader 不依赖 open3d)
pc_path = ensure_ascii_ply(pc_path, out_dir / "_ply_cache")
profile = str(config.get("profile") or "auto")
skip_registration = bool(config.get("skipRegistration") or False)
enable_bilateral = bool(config.get("enableBilateral") if "enableBilateral" in config else True)
# 可选 CAD 基准(PLY/STL)和 ROI JSON
cad_path = inputs.get("cadPath") or None
roi_path = inputs.get("roiPath") or None
emit_progress(0.20, "调用 run_measurement_pipeline")
# run_measurement_pipeline 内部会打印进度到 stdout,
# 我们在调用前后各报一次进度即可。
report: dict = run_measurement_pipeline(
input_cloud=pc_path,
out_dir=str(out_dir),
profile=profile,
cad_path=cad_path,
roi_path=roi_path,
skip_registration=skip_registration,
enable_bilateral=enable_bilateral,
skip_excel=False,
)
emit_progress(0.92, "整理结果")
# ── 从 report dict 中提取核心测量值 ──────────────────────────────────
deflection = report.get("deflection") or {}
left_sel = (deflection.get("left") or {}).get("selected_measurement") or {}
right_sel = (deflection.get("right") or {}).get("selected_measurement") or {}
left_mm = _safe_float(left_sel.get("signed_deflection_mm"))
right_mm = _safe_float(right_sel.get("signed_deflection_mm"))
registration = report.get("registration") or {}
reg_rms = _safe_float(registration.get("rms_mm"))
quality_flags: list[str] = report.get("quality_flags") or []
# 容差:高铁底架挠度通常要求 ≤ 3 mm(可在 manifest inputs 中暴露)
tol = _safe_float(config.get("toleranceMm")) or 3.0
measurements = [
{
"name": "左梁挠度",
"value": left_mm if left_mm is not None else float("nan"),
"unit": "mm",
"tolerance": tol,
"status": _status_for(left_mm, tol),
},
{
"name": "右梁挠度",
"value": right_mm if right_mm is not None else float("nan"),
"unit": "mm",
"tolerance": tol,
"status": _status_for(right_mm, tol),
},
]
if reg_rms is not None:
measurements.append(
{
"name": "配准 RMS",
"value": reg_rms,
"unit": "mm",
"status": "pass" if reg_rms <= 1.0 else "warning" if reg_rms <= 2.0 else "fail",
}
)
# ── 3D 叠加层:优先 out_dir/ply/ 子目录,回退到 out_dir 根目录 ──────────
overlay3d: dict = {"kind": "none"}
ply_files: list = []
ply_dir = out_dir / "ply"
if ply_dir.exists():
ply_files = sorted(ply_dir.glob("*.ply"))
if not ply_files:
# 算法直接输出到 out_dir 根目录;优先取 full overlay
for name in ("roi_measurement_overlay_full.ply", "roi_cropped_cloud.ply"):
candidate = out_dir / name
if candidate.exists():
ply_files = [candidate]
break
if not ply_files:
ply_files = sorted(out_dir.glob("*.ply"))
if ply_files:
rel = ply_files[0].relative_to(out_dir)
overlay3d = {
"kind": "ply",
"file": str(rel),
}
payload_out = {
"schemaVersion": report.get("schema_version", "1.1"),
"status": "completed",
"measurements": measurements,
"overlay3d": overlay3d,
"extra": {
"algorithmVersion": report.get("algorithm_version"),
"qualityFlags": quality_flags,
"registration": registration,
"deflectionFull": deflection,
},
}
write_result(out_dir, payload_out)
emit_progress(1.0, "完成")
return 0
except Exception as exc:
traceback.print_exc()
write_error_result(
out_dir,
f"underframe-deflection 计算失败:{exc}",
extra={"traceback": traceback.format_exc()},
)
return 1
if __name__ == "__main__":
sys.exit(main())