From a2f7c6dda4564ae254afdb13fdc94d8a15a36803 Mon Sep 17 00:00:00 2001 From: zhanghao <2024138486@qq.com> Date: Thu, 21 May 2026 11:06:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84QET=E4=BA=A4=E6=8D=A2?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE=E4=B8=8E=E8=AE=BE=E5=A4=87=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/2D-3D交换协议.md | 87 +++++++++++++++++++++---- src/Mod/FreeCADExchange/DeviceImport.py | 31 +++++++-- 2 files changed, 103 insertions(+), 15 deletions(-) diff --git a/docs/2D-3D交换协议.md b/docs/2D-3D交换协议.md index b0d1474..27b1ba8 100644 --- a/docs/2D-3D交换协议.md +++ b/docs/2D-3D交换协议.md @@ -101,7 +101,7 @@ ```json { - "schema_version": "1.1", + "schema_version": "1.2", "project_uuid": "string", "generated_at": "2026-05-18T10:30:00+08:00", "source": { @@ -111,7 +111,8 @@ "cabinet": {}, "devices": [], "terminals": [], - "device_models": [] + "device_models": [], + "wires": [] } ``` @@ -125,6 +126,7 @@ - `devices`:设备实例绑定 - `terminals`:端子实例绑定 - `device_models`:设备 3D 模型解析结果 +- `wires`:导线起点/终点与标注快照 --- @@ -258,26 +260,89 @@ - `terminal_key` - `connection_point_key` - `symbol_terminal` -- `wire_label` -- `net_id` -原因: +--- + +## 8. `wires` 结构 + +### 8.1 作用 + +`wires` 负责表达: + +> 当前图纸中每一条逻辑导线,连接了哪两个端子,以及它当前的导线标注。 + +第一版先只解决: + +- 导线是谁 +- 起点端子是谁 +- 终点端子是谁 +- 当前导线标注是什么 + +不在这一版里解决: + +- 3D 路径点 +- 3D 线束位姿 +- 导线自动布线路由结果 -- 这些字段当前都不是 FreeCAD 第一版创建端子对象的硬前提 -- 端子语义可以通过 `terminal_uuid` 回查 QET -- 先把绑定关系打通,比先堆字段更重要 +### 8.2 第一版字段 + +```json +{ + "wire_id": "string", + "net_uuid": "string", + "group_uuid": "string", + "wire_mark": "string", + "wire_mark_is_manual": false, + "start_element_uuid": "string", + "start_terminal_uuid": "string", + "end_element_uuid": "string", + "end_terminal_uuid": "string", + "start_terminal_display": "string", + "end_terminal_display": "string", + "conductor_uuids": [] +} +``` + +### 8.3 字段说明 + +| 字段 | 中文 | 必需 | 说明 | +| --- | --- | --- | --- | +| `wire_id` | 导线交换ID | 是 | JSON 交换层稳定标识;优先使用单根导线 UUID,退回 `net_uuid + index` | +| `net_uuid` | 网络UUID | 否 | 当前逻辑导线所属网络 | +| `group_uuid` | 网络分组UUID | 否 | 当前逻辑导线所属网络分组 | +| `wire_mark` | 导线标注 | 否 | 导线当前标注;为空时导出为 `无标注导线` | +| `wire_mark_is_manual` | 导线标注是否手工 | 否 | 是否手工修改过导线标注 | +| `start_element_uuid` | 起点设备UUID | 是 | 起点端子所属 2D 设备实例 | +| `start_terminal_uuid` | 起点端子UUID | 是 | 起点 2D 端子实例 | +| `end_element_uuid` | 终点设备UUID | 是 | 终点端子所属 2D 设备实例 | +| `end_terminal_uuid` | 终点端子UUID | 是 | 终点 2D 端子实例 | +| `start_terminal_display` | 起点端子显示号 | 否 | 起点端子在 QET 中的显示编号 | +| `end_terminal_display` | 终点端子显示号 | 否 | 终点端子在 QET 中的显示编号 | +| `conductor_uuids` | 几何导线UUID列表 | 否 | 当前逻辑导线对应的 2D 几何导线 UUID 列表 | + +### 8.4 说明 + +- `wire_mark` 来源于当前图纸导线方向信息里的 `wireMark` +- 它是**导线标注** +- 不是设备实例标注,也不是符号设备标注 + +- `wires` 是交换 JSON 的扩展层 +- 不意味着第一版数据库绑定表要新增导线绑定表 + +- 第一版 FreeCAD 侧即使暂时不消费 `wires` +- 也建议先由 QET 输出出来,方便后续 3D 布线与调试 --- -## 8. `device_models` 结构 +## 9. `device_models` 结构 -### 8.1 作用 +### 9.1 作用 `device_models` 不是绑定表本身,而是: > QET 在导出时,顺手把设备对应 3D 模型资源解析出来,减少 FreeCAD 再回查 QET 内部数据库的复杂度。 -### 8.2 第二步设备导入推荐字段 +### 9.2 第二步设备导入推荐字段 ```json { diff --git a/src/Mod/FreeCADExchange/DeviceImport.py b/src/Mod/FreeCADExchange/DeviceImport.py index 2239df7..b8fc2d7 100644 --- a/src/Mod/FreeCADExchange/DeviceImport.py +++ b/src/Mod/FreeCADExchange/DeviceImport.py @@ -214,6 +214,18 @@ def _device_label_text(display_tag, instance_id, element_uuid): return "QET Device" +def _device_warning_subject(display_tag, element_uuid): + label = (display_tag or "").strip() + element_uuid = (element_uuid or "").strip() + if label and element_uuid: + return "设备 {0} ({1})".format(label, element_uuid) + if label: + return "设备 {0}".format(label) + if element_uuid: + return "设备 {0}".format(element_uuid) + return "设备" + + def _ensure_device_group(doc, root_group, element_uuid, instance_id, model_path, display_tag, layout_index): created_now = False device_group = _find_device_group(doc, element_uuid) @@ -438,21 +450,29 @@ def import_devices_from_payload(payload, scene_path=""): if not resolved_model_path: report["skipped_missing_model"] += 1 report["warnings"].append( - "设备 {0} 缺少 resolved_model_path,已跳过。".format(element_uuid) + "{0} 缺少 resolved_model_path,已跳过。".format( + _device_warning_subject(display_tag, element_uuid) + ) ) continue if not os.path.isfile(resolved_model_path): report["skipped_missing_file"] += 1 report["warnings"].append( - "设备 {0} 的模型文件不存在:{1}".format(element_uuid, resolved_model_path) + "{0} 的模型文件不存在:{1}".format( + _device_warning_subject(display_tag, element_uuid), + resolved_model_path, + ) ) continue if not _supported_for_import(resolved_model_path): report["skipped_unsupported_format"] += 1 report["warnings"].append( - "设备 {0} 的模型格式暂不支持:{1}".format(element_uuid, resolved_model_path) + "{0} 的模型格式暂不支持:{1}".format( + _device_warning_subject(display_tag, element_uuid), + resolved_model_path, + ) ) continue @@ -481,7 +501,10 @@ def import_devices_from_payload(payload, scene_path=""): except Exception as exc: report["skipped_import_error"] += 1 report["warnings"].append( - "设备 {0} 导入失败:{1}".format(element_uuid, exc) + "{0} 导入失败:{1}".format( + _device_warning_subject(display_tag, element_uuid), + exc, + ) ) _append_debug_log( "DeviceImport import failed for element_uuid={0}: {1}".format(