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...

5.9 KiB

FreeCAD 端子模板语义设计

目标:把端子位置、端子命名、端子朝向和接线资格从几何模型里分离出来,放进可维护的模板语义层。

Goal: 让 FreeCAD 的端子显示、手动连线和最小保存回写依赖真实模板语义,而不是长期依赖包围盒猜位。

Architecture:FreeCADExchange 的 Python 层为主体。DeviceImport.py 负责把设备模型导入到设备组,TemplateSemantics.py 负责把模板输入统一成端子槽位,TerminalImport.py 负责创建或更新端子 LCSManualWiring.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::LocalCoordinateSystemPartDesign::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_keyconnection_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>
  • 端子对象带 QetTerminalUuidRole="Terminal"
  • 用户只能从端子连到端子
  • 保存后生成 3d_to_2d.json
  • 3d_to_2d.json 里只保留设备实例和端子实例的最小回写结果

12. 结论

这条路线的核心不是“先把所有模型做完”,而是先把模板语义建立起来。只要常用设备的端子位置从 fallback 升级到 FCStd LCS 或 sidecar JSONFreeCAD 这条 3D 线就能从临时验证变成可持续开发。