feat: 升级算法包 delivery_v1.1 → v1.2,新增任务级 CAD 与测距面板

- 算法包替换为 delivery_v1.2(coupler_panel 新增 autotune/layer_select,underframe_deflection 新增 single_beam 管线),删除 delivery_v1.1
- manifests/adapters 的 PYTHONPATH 与版本说明同步更新到 v1.2
- 新增任务级 CAD 文件支持(task_cad_files 表、上传/读取路由、TaskManager 全选与加载显示)
- 新增 train-measurement 自定义前端面板(YAML 编辑器 + 可视化 ROI 配置 + 3D 取点)
- PointCloudViewer 支持 PLY 叠加层渲染与 ROI 拾取
- Dockerfile 改用 Miniforge 安装 pythonocc-core,修复 libgomp/libstdc++ 依赖
This commit is contained in:
2026-06-11 02:30:04 +00:00
parent 16811100d1
commit cec0766e67
143 changed files with 3087 additions and 12604 deletions

View File

@@ -0,0 +1,176 @@
"""Command-line entry point installed by ``pyproject.toml``.
The DEFAULT mode is single-beam measurement: the ROI(s) already isolate one
beam each, the cloud is cropped and measured directly (no registration, no
dual-beam tracking). Provide ``--roi`` for one beam, or ``--left-roi`` and
``--right-roi`` to measure both in one invocation.
The legacy dual-beam pipeline (registration + left/right tracking on a
car-bottom slab) is still available via ``--mode dual``.
"""
from __future__ import annotations
import argparse
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Measure underframe longitudinal beam deflection from a point cloud.",
)
parser.add_argument(
"--mode",
default="single",
choices=["single", "dual"],
help="'single' (default): ROI isolates one beam, measure directly. "
"'dual': legacy car-bottom slab with left+right tracking + registration.",
)
parser.add_argument(
"--input-cloud",
required=True,
help="Path to input scan point cloud (.ply or .xyz). Large binary PLYs "
"are stream-cropped by the ROI in single mode.",
)
parser.add_argument(
"--out-dir",
required=True,
help="Output directory for report.json/.xlsx, CSV, and PNG.",
)
# --- single mode ---
parser.add_argument(
"--roi",
default=None,
help="Single mode: ROI JSON isolating ONE beam (native frame "
"x=length, y=height, z=width).",
)
parser.add_argument(
"--left-roi",
default=None,
help="Single mode: ROI JSON for the left beam (use with --right-roi).",
)
parser.add_argument(
"--right-roi",
default=None,
help="Single mode: ROI JSON for the right beam (use with --left-roi).",
)
parser.add_argument(
"--side",
default=None,
help="Single mode label for --roi (left/right); inferred from the file name if omitted.",
)
parser.add_argument(
"--enable-registration",
action="store_true",
help="Single mode: rigidly align the cloud to --cad before measuring. "
"Default OFF (cloud assumed already registered). Requires --cad as a "
"sampled .ply/.stl/.obj (.stp must be converted first).",
)
# --- shared ---
parser.add_argument(
"--config",
default=None,
help="Optional JSON config override file.",
)
parser.add_argument(
"--skip-excel",
action="store_true",
help="Skip writing the .xlsx report.",
)
parser.add_argument(
"--skip-plot",
action="store_true",
help="Single mode: skip the PNG plot.",
)
# --- dual (legacy) mode ---
parser.add_argument(
"--cad",
default=None,
help="Dual mode: CAD reference (.ply/.xyz/.stl/.obj) for registration.",
)
parser.add_argument(
"--profile",
default="auto",
choices=["auto", "M", "TC", "TP", "custom"],
help="Dual mode: profile for scale-related tuning.",
)
parser.add_argument(
"--skip-registration",
action="store_true",
help="Dual mode: bypass ICP even when --cad is supplied.",
)
parser.add_argument(
"--no-bilateral",
action="store_true",
help="Dual mode: disable bilateral denoising.",
)
parser.add_argument(
"--input-axis",
default="y_up",
choices=["z_up", "y_up"],
help="Dual mode: height axis convention (default y_up).",
)
return parser.parse_args()
def _load_config(path):
if not path:
return None
import json
from pathlib import Path
return json.loads(Path(path).read_text(encoding="utf-8"))
def main() -> None:
args = parse_args()
if args.mode == "single":
from .single_beam_pipeline import run_single_beam_pipeline, run_both_beams
config = _load_config(args.config)
if args.left_roi and args.right_roi:
run_both_beams(
input_cloud=args.input_cloud,
left_roi=args.left_roi,
right_roi=args.right_roi,
out_dir=args.out_dir,
config=config,
cad_path=args.cad,
enable_registration=args.enable_registration,
skip_excel=args.skip_excel,
skip_plot=args.skip_plot,
)
elif args.roi:
run_single_beam_pipeline(
input_cloud=args.input_cloud,
roi_path=args.roi,
out_dir=args.out_dir,
side=args.side,
config=config,
cad_path=args.cad,
enable_registration=args.enable_registration,
skip_excel=args.skip_excel,
skip_plot=args.skip_plot,
)
else:
raise SystemExit(
"single mode requires --roi (one beam) or both --left-roi and --right-roi."
)
return
# dual (legacy) mode
from .pipeline import run_measurement_pipeline
run_measurement_pipeline(
input_cloud=args.input_cloud,
out_dir=args.out_dir,
config_path=args.config,
profile=args.profile,
cad_path=args.cad,
roi_path=args.roi,
skip_registration=args.skip_registration,
enable_bilateral=not args.no_bilateral,
skip_excel=args.skip_excel,
input_axis=args.input_axis,
)
if __name__ == "__main__":
main()