feat: add selectable demo flow tasks
This commit is contained in:
@@ -155,23 +155,53 @@ def main() -> int:
|
||||
offset_right = 700.0 * _math.tan(_math.radians(raw_right)) if 'raw_right' in dir() else 700.0 * _math.tan(_math.radians(theta_right))
|
||||
offset_ref = 375.0 * _math.tan(_math.radians(raw_ref)) if 'raw_ref' in dir() else 375.0 * _math.tan(_math.radians(theta_ref))
|
||||
|
||||
measurements = [
|
||||
{
|
||||
inspection_object = str((payload.get("context") or {}).get("inspectionObject") or "unknown")
|
||||
longitudinal_task_no = "10" if inspection_object == "head" else "12" if inspection_object == "middle" else None
|
||||
reference_task_no = "8" if inspection_object == "head" else "9" if inspection_object == "middle" else None
|
||||
raw_selected_task_nos = config.get("demoTaskNos")
|
||||
selected_task_nos = (
|
||||
{str(int(value)) for value in raw_selected_task_nos if isinstance(value, (int, float)) and float(value).is_integer()}
|
||||
if isinstance(raw_selected_task_nos, list)
|
||||
else None
|
||||
)
|
||||
|
||||
def _selected(task_no: str | None) -> bool:
|
||||
return selected_task_nos is None or (task_no is not None and task_no in selected_task_nos)
|
||||
|
||||
measurements = []
|
||||
if _selected(longitudinal_task_no):
|
||||
longitudinal_measurement = {
|
||||
"name": "车钩面板距纵向中心的右偏转角",
|
||||
"value": round(offset_right, 6),
|
||||
"unit": "mm",
|
||||
"baseline": 700.0,
|
||||
"tolerance": 1.0,
|
||||
"status": _status_for(offset_right, 1.0),
|
||||
},
|
||||
{
|
||||
}
|
||||
if longitudinal_task_no:
|
||||
longitudinal_measurement.update({
|
||||
"taskNo": longitudinal_task_no,
|
||||
"metricCode": "coupler.longitudinal_right_offset",
|
||||
"name": "纵向中心右偏转",
|
||||
})
|
||||
measurements.append(longitudinal_measurement)
|
||||
if _selected(reference_task_no):
|
||||
reference_measurement = {
|
||||
"name": "车钩面板距参考面的右偏转角",
|
||||
"value": round(offset_ref, 6),
|
||||
"unit": "mm",
|
||||
"baseline": 375.0,
|
||||
"tolerance": 0.8,
|
||||
"status": _status_for(offset_ref, 0.8),
|
||||
},
|
||||
}
|
||||
if reference_task_no:
|
||||
reference_measurement.update({
|
||||
"taskNo": reference_task_no,
|
||||
"metricCode": "coupler.reference_right_offset",
|
||||
"name": "参考面右偏转",
|
||||
})
|
||||
measurements.append(reference_measurement)
|
||||
measurements.extend([
|
||||
{
|
||||
"name": "最大 x 偏差 dx_y",
|
||||
"value": dx_y,
|
||||
@@ -198,7 +228,7 @@ def main() -> int:
|
||||
"unit": "mm",
|
||||
"status": "info",
|
||||
},
|
||||
]
|
||||
])
|
||||
|
||||
payload_out = {
|
||||
"schemaVersion": getattr(result, "schema_version", "1.1"),
|
||||
|
||||
@@ -226,8 +226,17 @@ def main() -> int:
|
||||
result_template_path = alg_dir / "excel" / "测量结果.xlsx"
|
||||
if not result_template_path.is_file():
|
||||
raise RuntimeError(f"内置测量结果模板不存在: {result_template_path}")
|
||||
selected_task_nos = config.get("demoTaskNos")
|
||||
selected_task_ids = (
|
||||
[str(int(value)) for value in selected_task_nos if isinstance(value, (int, float)) and float(value).is_integer()]
|
||||
if isinstance(selected_task_nos, list)
|
||||
else None
|
||||
)
|
||||
if selected_task_ids == []:
|
||||
raise RuntimeError("请至少选择一个轮廓测量任务")
|
||||
res = pipeline.run_contour_batch(
|
||||
all_tasks=True,
|
||||
task_ids=selected_task_ids,
|
||||
all_tasks=selected_task_ids is None,
|
||||
data_root=str(data_root),
|
||||
pointcloud_kind="noise",
|
||||
point_chunk_size=8192,
|
||||
|
||||
24
server/plugins/adapters/test_demo_task_selection.py
Normal file
24
server/plugins/adapters/test_demo_task_selection.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import importlib.util
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _load_adapter(name: str):
|
||||
path = Path(__file__).with_name(name)
|
||||
spec = importlib.util.spec_from_file_location(path.stem, path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
assert spec and spec.loader
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
class DemoTaskSelectionTest(unittest.TestCase):
|
||||
def test_train_task_number_parsing_and_selection(self):
|
||||
adapter = _load_adapter("train_measurement_run.py")
|
||||
self.assertEqual(adapter._task_no_from_name("任务46_车体横断面对角线差值"), "46")
|
||||
self.assertEqual(adapter._selected_task_nos({"demoTaskNos": [2, 46, 2]}), {"2", "46"})
|
||||
self.assertIsNone(adapter._selected_task_nos({}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -19,6 +19,7 @@ v2.2 变更:
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
@@ -33,6 +34,18 @@ from _plugin_io import (
|
||||
)
|
||||
|
||||
|
||||
def _task_no_from_name(name: object) -> str | None:
|
||||
match = re.match(r"^任务\s*(\d+)", str(name or ""))
|
||||
return match.group(1) if match else None
|
||||
|
||||
|
||||
def _selected_task_nos(config: dict) -> set[str] | None:
|
||||
raw = config.get("demoTaskNos")
|
||||
if not isinstance(raw, list):
|
||||
return None
|
||||
return {str(int(value)) for value in raw if isinstance(value, (int, float)) and float(value).is_integer()}
|
||||
|
||||
|
||||
def _to_float(value):
|
||||
if value is None:
|
||||
return None
|
||||
@@ -155,6 +168,13 @@ def main() -> int:
|
||||
if t.get("enabled", True)
|
||||
}
|
||||
tm.tasks = [t for t in tm.tasks if t.name in _enabled_names]
|
||||
selected_task_nos = _selected_task_nos(config)
|
||||
if selected_task_nos is not None:
|
||||
available_task_nos = {_task_no_from_name(task.name) for task in tm.tasks}
|
||||
missing_task_nos = selected_task_nos - available_task_nos
|
||||
if missing_task_nos:
|
||||
raise RuntimeError(f"测距配置中找不到所选任务:{','.join(sorted(missing_task_nos, key=int))}")
|
||||
tm.tasks = [task for task in tm.tasks if _task_no_from_name(task.name) in selected_task_nos]
|
||||
|
||||
# 注入可视化输出目录
|
||||
viz_dir = out_dir / "visualizations"
|
||||
|
||||
@@ -49,6 +49,11 @@ def main() -> int:
|
||||
try:
|
||||
emit_progress(0.05, "加载挠度算法包 v1.2.1")
|
||||
|
||||
selected_task_nos = config.get("demoTaskNos")
|
||||
if isinstance(selected_task_nos, list) and 5 not in selected_task_nos:
|
||||
write_error_result(out_dir, "构架挠度插件仅支持任务 5")
|
||||
return 1
|
||||
|
||||
# ── 输入文件 ────────────────────────────────────────────────────────
|
||||
pointcloud_path = first_pointcloud(payload)
|
||||
if not pointcloud_path:
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
"category": "几何测量",
|
||||
"requiresPointCloud": true,
|
||||
"requiresCad": false,
|
||||
"demoSelection": { "kind": "task-nos", "param": "demoTaskNos" },
|
||||
"demoTasks": [
|
||||
{ "taskNo": 8, "name": "车钩面板到参考面的右偏转", "category": "车钩", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 9, "name": "车钩面板到参考面的右偏转", "category": "车钩", "inspectionObjects": ["middle"] },
|
||||
{ "taskNo": 10, "name": "车钩面板到纵向中心的右偏转", "category": "车钩", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 12, "name": "车钩面板到纵向中心的右偏转", "category": "车钩", "inspectionObjects": ["middle"] }
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"name": "profile",
|
||||
|
||||
@@ -8,6 +8,29 @@
|
||||
"category": "几何测量",
|
||||
"requiresPointCloud": false,
|
||||
"requiresCad": false,
|
||||
"demoSelection": { "kind": "task-nos", "param": "demoTaskNos" },
|
||||
"demoTasks": [
|
||||
{ "taskNo": 11, "name": "车钩面板的平整度", "category": "轮廓", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 13, "name": "车长方向平面度", "category": "轮廓", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 17, "name": "车高方向弧形轮廓测量", "category": "轮廓", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 20, "name": "门柱平整度", "category": "轮廓", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 22, "name": "从门口到外部轮廓的距离", "category": "轮廓", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 23, "name": "从窗口到外部轮廓的距离", "category": "轮廓", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 25, "name": "内风挡外圈平面度", "category": "轮廓", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 26, "name": "内风挡区域平面度", "category": "轮廓", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 27, "name": "外风挡区域平面度", "category": "轮廓", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 31, "name": "车头前墙区域平面度", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 34, "name": "司机室门外弧形轮廓", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 35, "name": "前窗框侧轮廓", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 36, "name": "前窗框弧形轮廓", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 37, "name": "顶灯框侧轮廓", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 38, "name": "顶灯框弧形轮廓", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 39, "name": "逃生窗侧轮廓", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 40, "name": "逃生窗弧形轮廓", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 41, "name": "曲面窗侧轮廓", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 42, "name": "曲面窗弧形轮廓", "category": "轮廓", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 45, "name": "地板平度", "category": "轮廓", "inspectionObjects": ["head", "middle"] }
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"name": "useBatchDatasets",
|
||||
|
||||
@@ -8,6 +8,25 @@
|
||||
"category": "尺寸测量",
|
||||
"requiresPointCloud": true,
|
||||
"requiresCad": false,
|
||||
"demoSelection": { "kind": "task-nos", "param": "demoTaskNos" },
|
||||
"demoTasks": [
|
||||
{ "taskNo": 1, "name": "转向架距离", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 2, "name": "车体长度", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 7, "name": "边梁下平面到参考线的距离", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 15, "name": "侧墙最大点到参考平面距离", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 16, "name": "车体最大宽度", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 18, "name": "门口宽度", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 21, "name": "侧门高度", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 28, "name": "端门口宽度", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 29, "name": "端门口高度", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 30, "name": "参考线到司机室辅助孔距离", "category": "尺寸", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 32, "name": "司机室登车门门口宽度", "category": "尺寸", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 33, "name": "司机室登车门门口高度", "category": "尺寸", "inspectionObjects": ["head"] },
|
||||
{ "taskNo": 43, "name": "窗口下沿高度", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 44, "name": "车顶高度", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 46, "name": "车体横断面对角线差值", "category": "尺寸", "inspectionObjects": ["head", "middle"] },
|
||||
{ "taskNo": 47, "name": "内端墙门口高度", "category": "尺寸", "inspectionObjects": ["head", "middle"] }
|
||||
],
|
||||
"uiPanel": "train-measurement",
|
||||
"inputs": [
|
||||
{
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
"category": "几何测量",
|
||||
"requiresPointCloud": true,
|
||||
"requiresCad": false,
|
||||
"demoSelection": { "kind": "task-nos", "param": "demoTaskNos" },
|
||||
"demoTasks": [
|
||||
{ "taskNo": 5, "name": "纵向梁到直线的垂直偏差(挠度)", "category": "挠度", "inspectionObjects": ["head", "middle"] }
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"name": "leftRoiPath",
|
||||
|
||||
@@ -68,6 +68,22 @@ export interface PluginRuntimeMock {
|
||||
|
||||
export type PluginRuntime = PluginRuntimeProcess | PluginRuntimeMock;
|
||||
|
||||
export type DemoInspectionObject = 'head' | 'middle';
|
||||
|
||||
/** 插件可在“全流程任务选择”中暴露的正式检验任务。 */
|
||||
export interface PluginDemoTask {
|
||||
taskNo: number;
|
||||
name: string;
|
||||
category: string;
|
||||
inspectionObjects?: DemoInspectionObject[];
|
||||
}
|
||||
|
||||
/** 任务选择如何转换为插件参数。 */
|
||||
export interface PluginDemoSelection {
|
||||
kind: 'task-nos';
|
||||
param: string;
|
||||
}
|
||||
|
||||
/** 插件 manifest(写在 server/plugins/manifests/*.json) */
|
||||
export interface PluginManifest {
|
||||
/** 全局唯一 ID(kebab-case,例如 coupler-panel) */
|
||||
@@ -89,6 +105,10 @@ export interface PluginManifest {
|
||||
requiresCad?: boolean;
|
||||
/** 是否需要点云(默认 true) */
|
||||
requiresPointCloud?: boolean;
|
||||
/** “选择任务运行”模式的权威任务目录。 */
|
||||
demoTasks?: PluginDemoTask[];
|
||||
/** 选中任务传给适配器的方式。 */
|
||||
demoSelection?: PluginDemoSelection;
|
||||
runtime: PluginRuntime;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user