You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
LightWork3D/docs/superpowers/specs/2026-05-20-freecad-terminal...

191 lines
5.9 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# FreeCAD 端子模板语义设计
> 目标:把端子位置、端子命名、端子朝向和接线资格从几何模型里分离出来,放进可维护的模板语义层。
**Goal:** 让 FreeCAD 的端子显示、手动连线和最小保存回写依赖真实模板语义,而不是长期依赖包围盒猜位。
**Architecture:**`FreeCADExchange` 的 Python 层为主体。`DeviceImport.py` 负责把设备模型导入到设备组,`TemplateSemantics.py` 负责把模板输入统一成端子槽位,`TerminalImport.py` 负责创建或更新端子 LCS`ManualWiring.py` 负责端子到端子的人工连线,`ExchangeWriteBack.py` 负责生成 `3d_to_2d.json`。FreeCAD 文档 `scene.FCStd` 是 3D 状态真相源,数据库只保留第一版最小绑定表。
**Tech Stack:** FreeCAD Python API, `App::DocumentObjectGroup`, `Part::LocalCoordinateSystem` / `PartDesign::CoordinateSystem`, JSON sidecar files, FreeCAD document observer.
---
## 1. 设计目标
1. 端子必须有稳定的语义来源。
2. 端子必须能被看见、选中、更新。
3. 手动连线只能从端子连到端子。
4. 保存时只回写第一版最小结果,不把 3D 位姿塞回数据库。
5. 常用设备最终要补成真实模板,不能长期靠 `bbox fallback`
## 2. 设计边界
本设计只覆盖以下内容:
- 端子模板语义解析
- 端子对象创建 / 更新
- 手动连线对象创建
- 保存时生成 `3d_to_2d.json`
本设计不覆盖:
- 自动布线
- FreeCAD C/C++ 核心修改
- `D:\code\zwl\sources\ThreeD` 旧 3D 引擎
- 新增 3D 场景数据库表
- 将完整线几何回写到 QET
## 3. 模板语义优先级
端子位置来源按下面优先级解析:
1. `FCStd` 模板里已有的 `LCS`
2. 同目录 sidecar JSON
3. `bbox fallback`
解释:
- `FCStd` 模板是正式答案,适合已经整理过的常用设备。
- sidecar JSON 是过渡方案,适合 STEP 几何已经有了,但还没整理成 FCStd 模板的设备。
- `bbox fallback` 只用于打通流程,不代表真实端子位置。
## 4. 模板资产约定
### 4.1 FCStd 模板
FCStd 模板里,端子用 LCS 表达,建议对象满足:
- 类型是 `Part::LocalCoordinateSystem``PartDesign::CoordinateSystem`
- `Role = "Terminal"`
- `CanWire = true`
这些属性的作用是:
- `Role` 让 FreeCADExchange 识别它是端子
- `CanWire` 让连线命令只接受有效端子
- 端子对象的 `QetTerminalUuid` 由导入流程补齐,不依赖模板文件本身已有的 2D 绑定字段
### 4.2 sidecar JSON
sidecar JSON 与模型同目录,当前支持的文件名后缀约定:
- `.terminals.json`
- `.qet_terminals.json`
- `.terminal_slots.json`
- `.qet_template.json`
sidecar 中可接受的槽位字段:
- `name`
- `label`
- `position`
- `base`
- `origin`
- `point`
- `x / y / z`
如果某个槽位已经有明确位置,就直接作为端子坐标。名称和标签只用于显示和调试,不作为业务主键。
### 4.3 bbox fallback
当模板里没有 LCS也没有 sidecar JSON 时,才用包围盒生成临时端子位置。
这个 fallback 只做三件事:
- 让导入链路跑通
- 让用户能先看到端子对象
- 给后续补模板留出验证空间
它不能作为最终模板方案。
## 5. 端子对象模型
每个端子对象都必须挂在对应设备实例下的 `QETTerminals_<element_uuid>` 组内。
端子对象必须保存这些语义属性:
- `QetProjectUuid`
- `QetElementUuid`
- `QetTerminalUuid`
- `QetInstanceId`
- `Role = "Terminal"`
- `CanWire = true`
补充属性:
- `QetTemplateSlotName`
识别规则只认 `terminal_uuid`,不依赖 `terminal_key`、`connection_point_key` 这类旧字段。
## 6. 连线对象模型
手动连线只允许连接两个端子。
连线对象保存:
- `QetProjectUuid`
- `QetStartTerminalUuid`
- `QetEndTerminalUuid`
- `QetStartInstanceId`
- `QetEndInstanceId`
- `RouteType = "Manual"`
连线几何保存在 `scene.FCStd`,第一版不把完整路径几何写回数据库。
## 7. 数据流
1. QET 导出 `2d_to_3d.json`
2. FreeCAD 读取 `devices / terminals / device_models`
3. `DeviceImport.py` 导入设备模型并形成 `QETExchangeDevices` 树。
4. `TemplateSemantics.py` 为每个设备解析端子槽位。
5. `TerminalImport.py` 创建或更新端子对象。
6. 用户通过命令手动连线。
7. 保存文档时 `ExchangeWriteBack.py` 输出 `3d_to_2d.json`
## 8. 实现约束
1. 第一版只改 `FreeCADExchange` Python 层。
2. 第一版不改 FreeCAD C/C++。
3. 第一版不依赖旧 3D 场景表。
4. 第一版 3D 状态以 FreeCAD 文档为准。
5. 第一版绑定只认:
- `project_uuid`
- `element_uuid`
- `terminal_uuid`
- `instance_id`
## 9. 模板建设顺序
建议先补这几类常用设备:
1. 机柜 / 安装板
2. DIN 导轨
3. 断路器或继电器
4. 端子排
先把这些设备补成 FCStd LCS 或 sidecar JSON可以最快验证“端子显示 + 手动连线 + 保存回写”这条链路。
## 10. 失败处理
1. 模型文件不存在,跳过设备并记录警告。
2. 没有端子模板,退回 sidecar。
3. 没有 sidecar退回 bbox fallback。
4. 端子 `terminal_uuid` 缺失,直接跳过该条。
5. 同一个 `terminal_uuid` 已存在时,更新旧端子而不是重复创建。
6. 保存回写失败时,保留 FreeCAD 文档状态,错误写入调试日志。
## 11. 验收标准
满足下面结果,就说明这套设计可用:
- 设备模型导入后,树里能看到 `QETDevice_<element_uuid>`
- 每个设备下有对应的 `QETTerminals_<element_uuid>`
- 端子对象带 `QetTerminalUuid``Role="Terminal"`
- 用户只能从端子连到端子
- 保存后生成 `3d_to_2d.json`
- `3d_to_2d.json` 里只保留设备实例和端子实例的最小回写结果
## 12. 结论
这条路线的核心不是“先把所有模型做完”,而是先把模板语义建立起来。只要常用设备的端子位置从 fallback 升级到 FCStd LCS 或 sidecar JSONFreeCAD 这条 3D 线就能从临时验证变成可持续开发。