|
|
|
@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
# 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 JSON,FreeCAD 这条 3D 线就能从临时验证变成可持续开发。
|