|
|
# FreeCAD 端子显示、手动连线、保存回写开发文档
|
|
|
|
|
|
## 1. 当前任务边界
|
|
|
|
|
|
本文档只面向当前由一个人负责的 FreeCAD 3D 工作台能力:
|
|
|
|
|
|
- 端子显示
|
|
|
- 端子手动连线
|
|
|
- FreeCAD 文档保存
|
|
|
- 最小 3D -> 2D 回写
|
|
|
|
|
|
当前不做:
|
|
|
|
|
|
- 自动布线
|
|
|
- `D:\code\zwl\sources\ThreeD` 旧 3D 引擎扩展
|
|
|
- 复杂 UI 改造
|
|
|
- FreeCAD 核心 C/C++ 源码改造
|
|
|
- 3D 位姿写入数据库
|
|
|
- 新增或依赖旧 3D 场景表
|
|
|
|
|
|
第一版 3D 真相源是 FreeCAD 文档,即 `scene.FCStd`。QET/zwl 只负责 2D 数据、交换 JSON、启动 FreeCAD、后续读取最小回写结果。
|
|
|
|
|
|
## 2. 已有代码与文档现状
|
|
|
|
|
|
### 2.1 LightWork3D / FreeCAD 侧
|
|
|
|
|
|
已有模块:
|
|
|
|
|
|
- `src/Mod/FreeCADExchange/ExchangeBootstrap.py`
|
|
|
- `src/Mod/FreeCADExchange/DeviceImport.py`
|
|
|
- `src/Mod/FreeCADExchange/InitGui.py`
|
|
|
|
|
|
当前已经做到:
|
|
|
|
|
|
- 从环境变量 `QET_2D_TO_3D_JSON` 读取 `2d_to_3d.json`
|
|
|
- 校验 `project_uuid / devices / terminals / device_models`
|
|
|
- 根据 `resolved_model_path` 导入 STEP / IGES / FCStd 等本地模型
|
|
|
- 将导入的设备放入 `QETExchangeDevices` 根组
|
|
|
|
|
|
当前还没有真正完成:
|
|
|
|
|
|
- 根据 `terminals` 创建设备端子对象
|
|
|
- 端子对象的 LCS / 标记属性
|
|
|
- 端子之间的手动连线
|
|
|
- `3d_to_2d.json` 回写
|
|
|
|
|
|
### 2.2 zwl / QET 侧
|
|
|
|
|
|
已有模块:
|
|
|
|
|
|
- `sources/FreeCAD/FreeCADExchangeExportService.cpp`
|
|
|
- `sources/FreeCAD/FreeCADLaunchService.cpp`
|
|
|
|
|
|
当前已经做到:
|
|
|
|
|
|
- 导出 `<ProjectRoot>/.qet_freecad/2d_to_3d.json`
|
|
|
- 返回 `<ProjectRoot>/.qet_freecad/scene.FCStd`
|
|
|
- 启动 FreeCAD,并设置:
|
|
|
- `QET_2D_TO_3D_JSON`
|
|
|
- `QET_FREECAD_SCENE_FILE`
|
|
|
|
|
|
第一版数据库约束:
|
|
|
|
|
|
- 只允许依赖 `project_2d3d_symbol_binding`
|
|
|
- 只允许依赖 `project_2d3d_terminal_binding`
|
|
|
- 设备绑定只依赖 `project_uuid / element_uuid / instance_id`
|
|
|
- 端子绑定只依赖 `project_uuid / terminal_uuid / instance_id`
|
|
|
- 第一版端子绑定唯一依据是 `terminal_uuid`
|
|
|
|
|
|
### 2.3 代码落地约束
|
|
|
|
|
|
当前第一版实现优先放在:
|
|
|
|
|
|
```text
|
|
|
D:\LightWork3D\src\Mod\FreeCADExchange
|
|
|
```
|
|
|
|
|
|
实现形式优先使用 Python 文件,例如:
|
|
|
|
|
|
```text
|
|
|
src/Mod/FreeCADExchange/DeviceImport.py
|
|
|
src/Mod/FreeCADExchange/TerminalImport.py
|
|
|
src/Mod/FreeCADExchange/ManualWiring.py
|
|
|
src/Mod/FreeCADExchange/ExchangeWriteBack.py
|
|
|
```
|
|
|
|
|
|
第一版尽量只改 FreeCAD 插件层:
|
|
|
|
|
|
- 可以新增 `FreeCADExchange` 下的 `.py` 文件。
|
|
|
- 可以修改 `FreeCADExchange\ExchangeBootstrap.py` 做流程调度。
|
|
|
- 可以修改 `FreeCADExchange\InitGui.py` 注册简单命令。
|
|
|
- 可以修改 `FreeCADExchange\CMakeLists.txt`,把新增 `.py` 加入安装/复制列表。
|
|
|
|
|
|
第一版尽量不改:
|
|
|
|
|
|
- FreeCAD 核心 C/C++ 源码。
|
|
|
- `D:\code\zwl\sources\ThreeD` 旧 3D 模块。
|
|
|
- 数据库旧 3D 场景表。
|
|
|
|
|
|
这样做的好处是:你的端子显示、手动连线、保存回写可以先作为 FreeCAD 工作台插件跑通;后续 csm 改 UI、qdj 做自动布线时,可以直接调用这些 Python 层能力,不需要他们理解或修改 FreeCAD 核心源码。
|
|
|
|
|
|
## 3. 本地设备模板是否可以使用
|
|
|
|
|
|
可以,而且第一版建议优先使用本地模板。
|
|
|
|
|
|
QET 导出的 `device_models[].resolved_model_path` 本来就是给 FreeCAD 使用的本地模型路径。FreeCADExchange 当前支持导入:
|
|
|
|
|
|
- `.step`
|
|
|
- `.stp`
|
|
|
- `.iges`
|
|
|
- `.igs`
|
|
|
- `.brep`
|
|
|
- `.brp`
|
|
|
- `.fcstd`
|
|
|
|
|
|
因此本地 STEP 文件可以直接作为第一批几何资源导入。
|
|
|
|
|
|
但从当前开发方向开始,正式可复用的设备模板建议统一保存为 `.FCStd`。也就是说:
|
|
|
|
|
|
```text
|
|
|
STEP / STP / STE 原始几何
|
|
|
-> 在 FreeCAD 里添加端子 LCS 和电气语义
|
|
|
-> 保存为 FCStd 设备模板
|
|
|
-> 后续不同工程、不同人员统一使用这个 FCStd
|
|
|
```
|
|
|
|
|
|
STEP / STP / STE 适合作为模板制作的输入,不建议作为长期带电气语义的最终交付文件。因为 STEP 可以稳定保存几何,但不能可靠保存 FreeCAD LCS、动态属性、端子角色、接线资格等二次开发语义。
|
|
|
|
|
|
但需要注意:
|
|
|
|
|
|
> 本地 STEP 只提供几何,不天然提供“哪个位置是端子”。
|
|
|
|
|
|
所以要实现端子显示和端子连线,本地模板还必须补一层端子语义。第一版采用下面的优先级:
|
|
|
|
|
|
1. 正式方式:使用 FCStd 模板,在模板里提前放好 LCS 端子对象。
|
|
|
2. 过渡方式:STEP + sidecar JSON,在同目录下保存端子槽位坐标。
|
|
|
3. 如果没有模板语义,则跳过端子生成并输出警告,不再用 bbox fallback 猜端子位置。
|
|
|
|
|
|
sidecar 只作为 FreeCAD 端模板辅助文件,不进入第一版数据库绑定主键。
|
|
|
|
|
|
sidecar 里除了端子坐标,还可以继续补端子朝向,例如 `rotation`,让模板端子不只是“有位置”,还可以“有方向”。
|
|
|
|
|
|
FCStd 模板里的 LCS 如果已经带了 Placement 朝向,导入时要把位置和朝向一并读取出来,这样生成的工程端子不只是有坐标,还能保留真实出线方向。
|
|
|
|
|
|
### 3.1 FCStd 设备模板制作约定
|
|
|
|
|
|
FCStd 设备模板用于解决“这个模型本身就带端子语义”的问题。模板端子是跨工程复用的槽位,不绑定某个具体工程里的 `terminal_uuid`。
|
|
|
|
|
|
推荐模板结构:
|
|
|
|
|
|
```text
|
|
|
电流互感器.FCStd
|
|
|
ModelGeometry
|
|
|
Terminal_P1
|
|
|
Terminal_P2
|
|
|
```
|
|
|
|
|
|
模板端子使用 LCS 表示,至少保存:
|
|
|
|
|
|
- `Role = "Terminal"`
|
|
|
- `CanWire = true`
|
|
|
- `QetTemplateSlotName = "P1"` / `"P2"`
|
|
|
- `QetTerminalLabel = "P1"` / `"P2"`
|
|
|
- `QetTerminalType = "primary"` 等可选分类
|
|
|
|
|
|
模板端子不保存:
|
|
|
|
|
|
- `QetTerminalUuid`
|
|
|
- `QetInstanceId`
|
|
|
- `project_uuid`
|
|
|
- 任意工程内绑定字段
|
|
|
|
|
|
这些工程级字段由导入项目时的 `2d_to_3d.json` 和 FreeCADExchange 运行时补齐。这样同一个 FCStd 设备模板才能在多个工程、多台机器、多人之间复用。
|
|
|
|
|
|
### 3.1.1 FCStd 导入运行时约定
|
|
|
|
|
|
FCStd 模板中的端子 LCS 是“模板槽位定义”,不是最终留在工程场景里的端子对象。
|
|
|
|
|
|
导入到 `QETScene` 时,FreeCADExchange 的处理顺序是:
|
|
|
|
|
|
1. 复制 FCStd 中的几何对象到设备组。
|
|
|
2. 读取模板 LCS 的 `QetTemplateSlotName / Label / Placement`。
|
|
|
3. 将槽位位置和朝向序列化到设备组属性 `QetTemplateSlotsJson`。
|
|
|
4. 删除复制出来的模板 LCS 及其 `OriginFeatures`,避免这些模板对象留在 `App::Part` 中参与变换或选择。
|
|
|
5. 后续由 `TerminalImport.py` 按 `terminal_uuid` 在 `QETTerminals_*` 下创建工程端子 LCS。
|
|
|
|
|
|
这样做不会改变第一版数据库约束:`QetTemplateSlotsJson` 只是 FreeCAD 文档内部的运行时缓存,不进入 `project_2d3d_symbol_binding` 或 `project_2d3d_terminal_binding`。
|
|
|
|
|
|
如果同一个设备从 FCStd 切回 STEP / IGES / BREP 等非 FCStd 模型,导入时会清空旧的 `QetTemplateSlotsJson`,避免继续沿用上一次 FCStd 的端子槽位。
|
|
|
|
|
|
### 3.2 模板制作工具目标
|
|
|
|
|
|
后续在 `FreeCADExchange` 中新增模板制作能力,目标是让用户不需要手工给 LCS 添加属性:
|
|
|
|
|
|
1. 导入 STEP / STP / STE 几何模型。
|
|
|
2. 在模型真实接线位置添加端子,例如 `P1`、`P2`。
|
|
|
3. 自动创建 LCS,并写入模板端子语义。
|
|
|
4. 保存为 `.FCStd` 设备模板。
|
|
|
5. 后续 LightWork3D 工程引用该 `.FCStd` 后,自动识别模板端子并生成工程端子对象。
|
|
|
|
|
|
### 3.2.1 方案 2:设备模板端子制作面板
|
|
|
|
|
|
当前 Python 控制台方式只适合开发验证,不适合 CAD 工作人员。下一步开发目标改为在 FreeCAD 右侧任务区提供“设备模板端子制作”面板。
|
|
|
|
|
|
第一版面板能力:
|
|
|
|
|
|
- 显示当前文档中的模板端子列表。
|
|
|
- 输入端子名,例如 `P1`、`P2`。
|
|
|
- 用户选择模型上的孔、点或对象后,点击“添加端子”。
|
|
|
- 点击“校验端子”显示总数、有效数和警告。
|
|
|
- 点击“保存为 FCStd”选择路径并保存模板。
|
|
|
|
|
|
该面板只包装现有 Python 能力,不改 FreeCAD C/C++ 源码:
|
|
|
|
|
|
- `TemplateAuthoring.create_template_terminal`
|
|
|
- `TemplateAuthoring.validate_template_terminals`
|
|
|
- `TemplateAuthoring.save_template_as_fcstd`
|
|
|
|
|
|
目标是让 CAD 工作人员只通过鼠标选择和按钮点击完成模板制作,不再直接输入 Python 代码。
|
|
|
|
|
|
### 3.3 A 方案资产流转约定
|
|
|
|
|
|
A 方案下,`.FCStd` 是正式可复用设备资产,STEP / STP / STE 只作为模板制作的原始几何输入。
|
|
|
|
|
|
完整流转固定为:
|
|
|
|
|
|
```text
|
|
|
STEP / STP / STE 原始几何
|
|
|
-> FreeCAD 中添加端子 LCS 和模板语义
|
|
|
-> 保存为 FCStd 设备模板
|
|
|
-> zwl/QET 选择该 FCStd 作为设备 3D 资产
|
|
|
-> 3D 视图导出 2d_to_3d.json
|
|
|
-> FreeCAD 导入 FCStd 并绑定工程端子
|
|
|
-> 手动连线并保存 scene.FCStd
|
|
|
-> 生成 3d_to_2d.json
|
|
|
```
|
|
|
|
|
|
zwl/QET 侧只需要支持 `.FCStd` 的选择、复制、保存和导出路径,不解析 `.FCStd` 内部的 LCS、端子属性或装配结构。`.FCStd` 的内部语义由 FreeCADExchange 读取。
|
|
|
|
|
|
详细设计见:
|
|
|
|
|
|
- `docs/superpowers/specs/2026-05-20-freecad-fcstd-asset-flow-design.md`
|
|
|
|
|
|
## 4. 为什么要先落地设备模板
|
|
|
|
|
|
这里的“设备模板”不是要求先把所有设备都建完,而是要先有一个稳定样板,证明端子显示和连线可以依附在真实设备上。
|
|
|
|
|
|
原因:
|
|
|
|
|
|
- 端子必须依附在设备实例上,不能只是空间中的孤立点。
|
|
|
- 端子连线需要稳定的起点、终点和出线方向。
|
|
|
- STEP 普通顶点不稳定,不适合作为端子主对象。
|
|
|
- 如果没有模板层,后续每种设备都要手工猜端子位置。
|
|
|
- 自动布线后续会依赖当前手动布线沉淀出的端子对象和路径对象。
|
|
|
|
|
|
因此第一版只需要选 1 到 2 个设备样板,例如断路器、端子排或继电器,把模板约定跑通。
|
|
|
|
|
|
## 5. 第一版对象模型
|
|
|
|
|
|
### 5.1 设备实例组
|
|
|
|
|
|
每个 2D 设备实例在 FreeCAD 中对应一个设备组。
|
|
|
|
|
|
建议对象:
|
|
|
|
|
|
```text
|
|
|
QETExchangeDevices
|
|
|
QETDevice_<element_uuid>
|
|
|
imported model objects
|
|
|
QETTerminals
|
|
|
QETWires
|
|
|
```
|
|
|
|
|
|
设备组至少保存属性:
|
|
|
|
|
|
- `QetProjectUuid`
|
|
|
- `QetElementUuid`
|
|
|
- `QetInstanceId`
|
|
|
- `QetResolvedModelPath`
|
|
|
|
|
|
`QetInstanceId` 如果输入为空,由 FreeCAD 生成,并在保存回写时写入 `3d_to_2d.json`。
|
|
|
|
|
|
### 5.2 端子对象
|
|
|
|
|
|
端子使用 FreeCAD LCS 表示。推荐对象为:
|
|
|
|
|
|
```text
|
|
|
Datum CoordinateSystem + Role="Terminal"
|
|
|
```
|
|
|
|
|
|
端子对象至少保存属性:
|
|
|
|
|
|
- `QetProjectUuid`
|
|
|
- `QetElementUuid`
|
|
|
- `QetTerminalUuid`
|
|
|
- `QetInstanceId`
|
|
|
- `Role = "Terminal"`
|
|
|
- `CanWire = true`
|
|
|
|
|
|
端子判断规则:
|
|
|
|
|
|
1. 对象必须有 `Role`
|
|
|
2. `Role == "Terminal"`
|
|
|
3. 对象必须有 `QetTerminalUuid`
|
|
|
4. `CanWire == true`
|
|
|
|
|
|
第一版禁止把 `terminal_key` 或 `connection_point_key` 当作绑定主键。模板内部可以有槽位名,但最终业务识别只认 `terminal_uuid`。
|
|
|
|
|
|
### 5.3 手动连线对象
|
|
|
|
|
|
手动连线可以先用 FreeCAD 中的折线对象表示,例如 Draft Wire 或 Part 曲线。
|
|
|
|
|
|
连线对象至少保存属性:
|
|
|
|
|
|
- `QetProjectUuid`
|
|
|
- `QetStartTerminalUuid`
|
|
|
- `QetEndTerminalUuid`
|
|
|
- `QetStartInstanceId`
|
|
|
- `QetEndInstanceId`
|
|
|
- `RouteType = "Manual"`
|
|
|
|
|
|
连线对象建议挂在对应设备实例下的 `QETWires_<element_uuid>` 组里,优先跟随起点端子所属设备。
|
|
|
|
|
|
第一版连线路径保存在 `scene.FCStd`。是否把路径几何回写给 QET,后续单独扩协议,不在当前最小数据库绑定范围内。
|
|
|
|
|
|
## 6. 推荐文件结构
|
|
|
|
|
|
在 `src/Mod/FreeCADExchange` 下逐步拆分模块:
|
|
|
|
|
|
```text
|
|
|
FreeCADExchange/
|
|
|
ExchangeBootstrap.py # 启动入口,读取 JSON,调度导入流程
|
|
|
DeviceImport.py # 设备导入,已存在
|
|
|
TemplateSemantics.py # 新增:读取 FCStd LCS 或 STEP sidecar 端子槽位
|
|
|
TemplateAuthoring.py # 计划新增:把 STEP/STP/STE 制作为带端子语义的 FCStd 模板
|
|
|
TemplateAuthoringPanel.py # 新增:CAD 人员使用的端子制作任务面板
|
|
|
TerminalImport.py # 新增:根据 terminals 创建/更新端子对象
|
|
|
TerminalObjects.py # 新增:端子对象属性、查找、校验工具
|
|
|
ManualWiring.py # 新增:端子选择、折线路径创建、连线对象属性
|
|
|
ExchangeWriteBack.py # 新增:生成 3d_to_2d.json
|
|
|
InitGui.py # 后续由 UI 改造统一接入命令
|
|
|
CMakeLists.txt # 新增 .py 后必须同步加入 FreeCADExchange_Scripts
|
|
|
```
|
|
|
|
|
|
如果暂时不做 UI,可以先暴露 Python 函数和简单命令,保证功能链路可测。
|
|
|
|
|
|
推荐第一版调用链:
|
|
|
|
|
|
```text
|
|
|
ExchangeBootstrap.py
|
|
|
-> DeviceImport.import_devices_from_payload(...)
|
|
|
-> TerminalImport.import_terminals_from_payload(...)
|
|
|
-> ExchangeWriteBack.write_back_if_needed(...) 或由保存命令触发
|
|
|
|
|
|
ManualWiring.py
|
|
|
-> 只允许选择 TerminalObjects.is_terminal_object(...) 认可的端子对象
|
|
|
-> 创建 RouteType="Manual" 的连线对象
|
|
|
-> 保存到 scene.FCStd
|
|
|
```
|
|
|
|
|
|
每新增一个 Python 模块,都要加入 `FreeCADExchange\CMakeLists.txt` 的 `FreeCADExchange_Scripts`,否则 Visual Studio 构建/INSTALL 后运行目录里不会出现该脚本。
|
|
|
|
|
|
## 7. 开发步骤
|
|
|
|
|
|
### 阶段 A0:FCStd 设备模板制作
|
|
|
|
|
|
目标:
|
|
|
|
|
|
- 用户可以导入 STEP / STP / STE 几何模型。
|
|
|
- 用户可以给模型添加带电气语义的端子 LCS。
|
|
|
- 模板保存为 `.FCStd` 后,可以脱离当前工程复用。
|
|
|
|
|
|
实现建议:
|
|
|
|
|
|
- 新增 `TemplateAuthoring.py`。
|
|
|
- 提供最小命令:
|
|
|
- `QET_Template_AddTerminal`
|
|
|
- `QET_Template_SaveAsFCStd`
|
|
|
- 第一版端子位置可以通过用户选择对象/点位后的三维坐标生成。
|
|
|
- 第一版端子方向默认使用单位旋转,后续再补出线方向编辑。
|
|
|
|
|
|
模板端子属性:
|
|
|
|
|
|
- `Role = "Terminal"`
|
|
|
- `CanWire = true`
|
|
|
- `QetTemplateSlotName`
|
|
|
- `QetTerminalLabel`
|
|
|
- `QetTerminalType`
|
|
|
|
|
|
验收:
|
|
|
|
|
|
- 打开一个普通 STEP 模型。
|
|
|
- 添加 `P1`、`P2` 两个端子。
|
|
|
- 保存为 `电流互感器.FCStd`。
|
|
|
- 重新打开该 FCStd 后,端子 LCS 仍存在,属性仍存在。
|
|
|
- 在项目导入流程中引用该 FCStd,端子位置优先来自模板 LCS,而不是 bbox fallback。
|
|
|
|
|
|
### 阶段 A:本地模板导入基线
|
|
|
|
|
|
目标:
|
|
|
|
|
|
- 本地 STEP / FCStd 可以稳定导入。
|
|
|
- 正式设备资源优先使用带端子语义的 FCStd 模板。
|
|
|
- 设备组有 `QetElementUuid / QetInstanceId`。
|
|
|
- 重新打开同一个项目时,不重复创建同一设备。
|
|
|
|
|
|
改动点:
|
|
|
|
|
|
- 保持 `DeviceImport.py` 现有逻辑。
|
|
|
- 补齐设备组上的 `QetProjectUuid`。
|
|
|
- 如果 `instance_id` 为空,生成稳定的 FreeCAD 实例 ID。
|
|
|
|
|
|
验收:
|
|
|
|
|
|
- 使用本地 FCStd 模板导入设备。
|
|
|
- FreeCAD 树中可看到设备组。
|
|
|
- 关闭并重新打开,不产生重复设备组。
|
|
|
|
|
|
### 阶段 B:端子显示
|
|
|
|
|
|
目标:
|
|
|
|
|
|
- 根据 `2d_to_3d.json` 的 `terminals` 为设备创建端子对象。
|
|
|
- 每个端子都能在 FreeCAD 场景中被看到、被选中。
|
|
|
|
|
|
实现建议:
|
|
|
|
|
|
- 新增 `TerminalImport.py`。
|
|
|
- 按 `element_uuid` 或 `instance_id` 找到设备组。
|
|
|
- 为每个 `terminal_uuid` 创建 LCS。
|
|
|
- LCS 放入设备组下的 `QETTerminals` 子组。
|
|
|
|
|
|
端子位置策略:
|
|
|
|
|
|
1. 如果 FCStd 模板已有 `Role="Terminal"` 的 LCS,则优先读取模板 LCS 的槽位信息,再生成工程端子 LCS。
|
|
|
2. 如果有 sidecar JSON,则按 sidecar 坐标创建。
|
|
|
3. 如果只有 STEP 且没有 sidecar,则不生成端子,并在导入报告中提示缺少模板槽位。
|
|
|
|
|
|
第一版不再按设备包围盒猜测临时端子,避免把错误端子位置保存进工程。
|
|
|
|
|
|
验收:
|
|
|
|
|
|
- 控制台输出端子创建数量。
|
|
|
- 每个端子对象带 `QetTerminalUuid`。
|
|
|
- 选择端子时能确认它属于哪个设备实例。
|
|
|
|
|
|
### 阶段 C:端子手动连线
|
|
|
|
|
|
目标:
|
|
|
|
|
|
- 只能从端子连到端子。
|
|
|
- 普通几何点、边、面不能直接作为布线端点。
|
|
|
|
|
|
实现建议:
|
|
|
|
|
|
- 新增 `ManualWiring.py`。
|
|
|
- 提供函数:
|
|
|
- `is_terminal_object(obj)`
|
|
|
- `create_manual_wire(start_terminal, end_terminal, waypoints)`
|
|
|
- `list_manual_wires(doc)`
|
|
|
- 第一版路径点可以先使用:
|
|
|
- 起点 LCS 原点
|
|
|
- 用户手动点选的中间点
|
|
|
- 终点 LCS 原点
|
|
|
|
|
|
如果暂时没有完整 UI,可先做最小命令:
|
|
|
|
|
|
1. 用户选择两个端子对象。
|
|
|
2. 执行命令生成一条直线或折线。
|
|
|
3. 连线对象保存起止端子 UUID。
|
|
|
|
|
|
验收:
|
|
|
|
|
|
- 未选择端子时拒绝创建连线。
|
|
|
- 选择同一个端子作为起终点时拒绝创建。
|
|
|
- 创建成功后,连线对象带起点和终点 UUID。
|
|
|
|
|
|
### 阶段 D:保存与回写
|
|
|
|
|
|
目标:
|
|
|
|
|
|
- FreeCAD 保存 `scene.FCStd`。
|
|
|
- 生成 `.qet_freecad/3d_to_2d.json`。
|
|
|
|
|
|
实现建议:
|
|
|
|
|
|
- 新增 `ExchangeWriteBack.py`。
|
|
|
- 从文档中扫描:
|
|
|
- 设备组
|
|
|
- 端子对象
|
|
|
- 手动连线对象
|
|
|
- 第一版正式回写结构遵守现有协议最小集:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
"schema_version": "1.0",
|
|
|
"project_uuid": "string",
|
|
|
"generated_at": "2026-05-20T10:00:00+08:00",
|
|
|
"instances": [
|
|
|
{
|
|
|
"element_uuid": "string",
|
|
|
"instance_id": "string"
|
|
|
}
|
|
|
],
|
|
|
"terminals": [
|
|
|
{
|
|
|
"terminal_uuid": "string",
|
|
|
"instance_id": "string"
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
```
|
|
|
|
|
|
连线路径第一版保存在 `.FCStd`。如需 QET 读取线对象,建议后续扩展协议字段,不直接写入现有两张绑定表。
|
|
|
|
|
|
验收:
|
|
|
|
|
|
- 保存后存在 `3d_to_2d.json`。
|
|
|
- JSON 中每个设备有 `element_uuid / instance_id`。
|
|
|
- JSON 中每个端子有 `terminal_uuid / instance_id`。
|
|
|
- 不写入 `project_3d_scene_instance`、`project_3d_space_object`、`project_2d3d_link`。
|
|
|
|
|
|
## 8. 是否能达到图二效果
|
|
|
|
|
|
可以达到同方向效果,但需要分层理解。
|
|
|
|
|
|
图二效果包含:
|
|
|
|
|
|
- 本地模型导入
|
|
|
- 柜体和导轨等场景模型
|
|
|
- 设备装配
|
|
|
- FreeCAD 视图展示
|
|
|
- 模型树层级
|
|
|
|
|
|
本文档当前只保证:
|
|
|
|
|
|
- 本地模板能进入 FreeCAD
|
|
|
- 端子能显示
|
|
|
- 端子能手动连线
|
|
|
- FreeCAD 能保存并回写最小绑定
|
|
|
|
|
|
如果本地模板里包含机柜、导轨和设备,并且导入逻辑按组组织,就可以逐步做出图二那类 FreeCAD 场景。复杂 UI、自动排布、自动布线不属于当前个人任务第一阶段。
|
|
|
|
|
|
## 9. 首批模板建议
|
|
|
|
|
|
第一批不要铺太多设备。建议只选:
|
|
|
|
|
|
1. 机柜或安装板:提供场景参考。
|
|
|
2. DIN 导轨:提供设备摆放参考。
|
|
|
3. 一个断路器或继电器:验证设备端子。
|
|
|
4. 一个端子排:验证多端子排列和连线。
|
|
|
|
|
|
每个模板至少准备:
|
|
|
|
|
|
- 原始几何文件:`.STEP` / `.STP` / `.STE`
|
|
|
- 正式模板文件:`.FCStd`
|
|
|
- 模板内 LCS 端子:`Role="Terminal"`,带槽位名和接线资格
|
|
|
- 可选 sidecar:只作为过渡或校验,不作为正式交付优先方案
|
|
|
- 模板说明:原点、朝向、尺寸单位、端子数量
|
|
|
|
|
|
常用设备建议优先补齐 `FCStd LCS`,把端子位置从临时的 `bbox fallback` 提升为真实可用坐标。
|
|
|
|
|
|
## 10. 单人开发优先级
|
|
|
|
|
|
建议按下面顺序推进:
|
|
|
|
|
|
1. 不改 UI,先把 Python 功能函数跑通。
|
|
|
2. 不碰自动布线,先把端子对象和手动线对象持久化。
|
|
|
3. 不扩旧数据库表,只生成 `3d_to_2d.json`。
|
|
|
4. 不追求所有设备,先做一个样板设备跑通闭环。
|
|
|
5. 不让 STEP 顶点直接参与布线,只认带属性的端子 LCS。
|
|
|
|
|
|
## 11. 最小验收场景
|
|
|
|
|
|
准备一个测试项目:
|
|
|
|
|
|
- 2 个设备
|
|
|
- 每个设备至少 2 个端子
|
|
|
- 每个设备绑定一个本地 STEP 或 FCStd 模型
|
|
|
|
|
|
验收步骤:
|
|
|
|
|
|
1. 在 QET 点击打开 FreeCAD。
|
|
|
2. QET 生成 `2d_to_3d.json`。
|
|
|
3. FreeCAD 导入设备模型。
|
|
|
4. FreeCAD 为端子创建 LCS。
|
|
|
5. 用户选择两个端子创建手动连线。
|
|
|
6. 保存 FreeCAD 文档。
|
|
|
7. 生成 `3d_to_2d.json`。
|
|
|
8. 关闭 FreeCAD 再打开,设备、端子、连线仍存在。
|
|
|
|
|
|
达到以上结果,就说明“端子显示 + 端子连线 + 保存回写”第一版闭环成立。
|
|
|
|
|
|
## 12. 开发结果记录要求
|
|
|
|
|
|
每次开发完成后,都要在本文档末尾追加一条开发记录,至少包含:
|
|
|
|
|
|
- 时间
|
|
|
- 本次实现了什么
|
|
|
- 验证结果
|
|
|
- 未完成或待跟进事项
|
|
|
|
|
|
建议格式:
|
|
|
|
|
|
```text
|
|
|
- 2026-05-20:完成端子对象创建与显示逻辑,支持 FCStd LCS / sidecar JSON / bbox fallback;已验证 FreeCAD 可导入并生成端子对象。待补常用设备真实端子坐标。
|
|
|
- 2026-05-20:补上 sidecar `rotation` 解析与端子 Placement 应用,端子模板现在可以同时带位置和方向;已用单元测试验证解析和放置逻辑。
|
|
|
- 2026-05-20:补上 FCStd 模板 LCS 朝向保留,模板端子现在可以从源对象直接继承 Placement 方向;已用单元测试验证。
|
|
|
- 2026-05-20:补上手动连线对象归属到设备 `QETWires_*` 组,连线树结构现在和设备模板一致;已用单元测试验证。
|
|
|
- 2026-05-20:明确 A 方案:STEP/STP/STE 只作为原始几何输入,正式可复用设备资源统一保存为带 LCS 电气端子的 FCStd 模板;后续设计 `TemplateAuthoring.py` 做模板制作工具。
|
|
|
- 2026-05-20:新增 FCStd 设备模板制作基础能力,支持把模型上的点位创建为带 `Role="Terminal"`、`CanWire=true`、`QetTemplateSlotName` 的模板端子 LCS;已用单元测试验证端子语义写入和模板校验逻辑。
|
|
|
- 2026-05-20:补充 A 方案资产流转设计,明确 `.FCStd` 为正式设备资产;zwl/QET 只负责选择、保存、导出 `.FCStd` 路径,FreeCADExchange 负责读取 LCS 端子语义并生成工程端子。
|
|
|
- 2026-05-20:补上 `QET_Template_SaveAsFCStd` 模板保存命令,保存前会校验至少存在一个有效模板端子,并自动补 `.FCStd` 后缀;已用单元测试验证保存路径和端子校验结果。
|
|
|
- 2026-05-20:修复 `TemplateAuthoring.py` 在 `FreeCADCmd.exe` 命令行模式下导入时误注册 GUI 命令的问题;已在运行目录验证创建 `P1` 模板端子、保存 `.FCStd`、重新打开后端子语义仍可识别。
|
|
|
- 2026-05-20:确定方案 2 开发目标:新增“设备模板端子制作”任务面板,让 CAD 工作人员通过输入端子名、选择模型位置、点击按钮完成添加端子、校验端子和保存 FCStd,不再依赖 Python 控制台。
|
|
|
- 2026-05-20:新增 `TemplateAuthoringPanel.py`,提供“设备模板端子制作”任务面板和 `QET_Template_OpenAuthoringPanel` 命令;面板支持输入端子名、添加端子、校验端子、保存 FCStd,并已同步到运行目录验证模块可导入。
|
|
|
- 2026-05-25:新增 `WiringImport.py`,把 `2d_to_3d.json` 中的 `wires` 导入为 `QETWiring_01_Tasks` 下的导线任务;`ExchangeBootstrap.py` 已接入启动导入流程。`ManualWiringPanel.py` 增加任务列表、选择导线任务和删除最后折点,按任务生成导线时会把 `wire_id / net_uuid / group_uuid / wire_mark` 写入正式导线对象,并把任务状态更新为 `Routed`。已通过 35 项 `freecad_exchange*_test.py` 单元测试,并安装到 `D:\fc\run-FreeCAD-1.1.1` 运行目录验证 `WiringImport / ManualWiring / ManualWiringPanel / WiringObjects` 可导入。
|
|
|
- 2026-05-25:修复 FCStd 设备导入后模板 LCS 留在工程场景的问题;导入时会把模板槽位位置和朝向缓存到设备组 `QetTemplateSlotsJson`,随后删除模板 LCS 及其 `OriginFeatures`,工程端子仍按 `terminal_uuid` 生成到 `QETTerminals_*`。已补单元测试验证 FCStd 导入不保留模板 LCS、切回 STEP 会清空旧槽位缓存,并避免重复访问已删除对象的 `Group / InList / Name`。
|
|
|
```
|