|
|
# FreeCAD 3D 自动布线设计方案
|
|
|
|
|
|
本文档描述 QET / LightWork3D 与 FreeCAD 协同中的 3D 自动布线设计。
|
|
|
|
|
|
当前版本目标不是完整复刻 EPLAN Pro Panel 或 SOLIDWORKS Electrical,而是先完成一个可用的最小闭环:
|
|
|
|
|
|
```text
|
|
|
工程端子
|
|
|
-> 路由路径网络
|
|
|
-> 自动求路
|
|
|
-> 生成 3D 折线导线
|
|
|
-> 可保存到 FreeCAD 文档
|
|
|
```
|
|
|
|
|
|
## 1. 设计边界
|
|
|
|
|
|
### 1.1 当前版本目标
|
|
|
|
|
|
当前版本只要求完成“能够自动布线”:
|
|
|
|
|
|
1. 能识别 FreeCAD 文档中的工程端子。
|
|
|
2. 能从用户指定的线槽、草图、面域创建路由网络。
|
|
|
3. 能在两个端子之间自动生成 3D 折线导线。
|
|
|
4. 能批量处理 QET 导入的导线任务。
|
|
|
5. 能绕开或至少发现明显障碍碰撞。
|
|
|
6. 默认禁止长距离悬空线。
|
|
|
|
|
|
### 1.2 当前版本不做
|
|
|
|
|
|
当前版本不做以下工程级能力:
|
|
|
|
|
|
1. 不修改 FreeCAD C++ 源码。
|
|
|
2. 不写入或依赖旧 3D 场景数据库表。
|
|
|
3. 不把 3D 位姿、3D 路径点写入数据库。
|
|
|
4. 不做完整线槽容量计算。
|
|
|
5. 不做线径、弯曲半径、线束层叠排列。
|
|
|
6. 不做强弱电隔离、EMC、屏蔽线等电气规则。
|
|
|
7. 不保证达到 EPLAN / SOLIDWORKS Electrical 的完整工程级自动布线效果。
|
|
|
|
|
|
### 1.3 数据库约束
|
|
|
|
|
|
第一版严格遵守 `docs/数据库设计.md`:
|
|
|
|
|
|
1. 设备绑定只依赖:
|
|
|
|
|
|
```text
|
|
|
project_2d3d_symbol_binding:
|
|
|
project_uuid
|
|
|
element_uuid
|
|
|
instance_id
|
|
|
```
|
|
|
|
|
|
2. 端子绑定只依赖:
|
|
|
|
|
|
```text
|
|
|
project_2d3d_terminal_binding:
|
|
|
project_uuid
|
|
|
terminal_uuid
|
|
|
instance_id
|
|
|
```
|
|
|
|
|
|
3. 3D 端子绑定唯一依据是:
|
|
|
|
|
|
```text
|
|
|
terminal_uuid
|
|
|
```
|
|
|
|
|
|
4. 3D 位姿、装配关系、布线几何以 FreeCAD 文档为准。
|
|
|
|
|
|
## 2. 总体方案
|
|
|
|
|
|
自动布线不直接在任意 3D 空间里找线,也不会把所有端子任意两两连接。它参考 EPLAN / SOLIDWORKS 的思路,先建立“可走路径网络”,再按 QET 导线任务中的起点端子和终点端子逐条求路。
|
|
|
|
|
|
```text
|
|
|
端子出线段
|
|
|
-> 进入最近路由节点
|
|
|
-> 在线槽/路由路径网络中求最短路
|
|
|
-> 从路由网络出来
|
|
|
-> 进入目标端子
|
|
|
```
|
|
|
|
|
|
路由网络由 `carrier` 组成。一个 carrier 表示一段可走线中心线或辅助路由区域中的一条网格线。
|
|
|
|
|
|
### 2.1 路由优先级
|
|
|
|
|
|
当前版本按下面优先级处理:
|
|
|
|
|
|
1. `WireDuct`:线槽中心路径,最高优先级。
|
|
|
2. `RoutingPath`:用户画的草图线、Draft Wire、明确选中的路由边。
|
|
|
3. `AuxiliaryPath`:辅助路径,后续扩展使用。
|
|
|
4. `RoutingRange`:选中面生成的辅助路由区域,成本较高,只用于过渡或没有线槽时兜底。
|
|
|
|
|
|
普通机柜、设备外壳、实体边默认不是路由路径。
|
|
|
|
|
|
## 3. FreeCAD 对象语义
|
|
|
|
|
|
### 3.1 工程端子
|
|
|
|
|
|
工程端子是可布线起点和终点,必须满足:
|
|
|
|
|
|
```text
|
|
|
Role = "Terminal"
|
|
|
CanWire = true
|
|
|
QetTerminalUuid = <2D terminal_uuid>
|
|
|
QetInstanceId = <3D instance_id>
|
|
|
QetProjectUuid = <project_uuid>
|
|
|
```
|
|
|
|
|
|
端子空间位置来自 FreeCAD 文档。自动布线使用端子的全局坐标和方向。
|
|
|
|
|
|
### 3.2 路由路径 Carrier
|
|
|
|
|
|
路由路径对象使用以下语义属性:
|
|
|
|
|
|
```text
|
|
|
QetRoutingRole = "RoutingCarrier"
|
|
|
QetRouteCarrierKind = "WireDuct" | "RoutingPath" | "AuxiliaryPath" | "RoutingRange"
|
|
|
CanRouteWire = true
|
|
|
QetProjectUuid = <project_uuid>
|
|
|
Points = [Vector, Vector, ...]
|
|
|
```
|
|
|
|
|
|
carrier 统一放在:
|
|
|
|
|
|
```text
|
|
|
QETWiring
|
|
|
02_Carriers
|
|
|
```
|
|
|
|
|
|
### 3.3 自动导线
|
|
|
|
|
|
自动生成的导线放在:
|
|
|
|
|
|
```text
|
|
|
QETWiring
|
|
|
04_Routed
|
|
|
```
|
|
|
|
|
|
自动导线语义:
|
|
|
|
|
|
```text
|
|
|
RouteType = "AutoSuggested"
|
|
|
RouteMode = "Auto"
|
|
|
RouteStatus = "Routed" | "CollisionWarning"
|
|
|
QetStartTerminalUuid
|
|
|
QetEndTerminalUuid
|
|
|
QetAutoRouteAlgorithm
|
|
|
QetAutoRouteDiagnosticsJson
|
|
|
```
|
|
|
|
|
|
### 3.4 线槽实体
|
|
|
|
|
|
当用户选择线槽实体并执行“从线槽实体生成中心路径”后:
|
|
|
|
|
|
1. 系统按包围盒长轴生成 `WireDuct` 中心路径。
|
|
|
2. 原线槽实体标记为可穿线路由源。
|
|
|
3. 碰撞检测跳过该线槽实体本身,避免“线在槽内却撞到线槽外壳”的误报。
|
|
|
|
|
|
线槽实体属性:
|
|
|
|
|
|
```text
|
|
|
QetRoutingSourceKind = "WireDuct"
|
|
|
QetRoutingObstacleMode = "PassThrough"
|
|
|
QetRouteCarrierName = <generated carrier name>
|
|
|
```
|
|
|
|
|
|
## 4. 算法设计
|
|
|
|
|
|
### 4.1 路由网络构建
|
|
|
|
|
|
模块:
|
|
|
|
|
|
```text
|
|
|
src/Mod/FreeCADExchange/RoutingNetwork.py
|
|
|
```
|
|
|
|
|
|
构建步骤:
|
|
|
|
|
|
1. 收集所有 `QetRoutingRole = RoutingCarrier` 的对象。
|
|
|
2. 读取 carrier 的 `Points`。
|
|
|
3. 将相同或接近坐标的点合并为图节点。
|
|
|
4. 将相邻点之间的线段建立为图边。
|
|
|
5. 每条边记录所属 carrier,用于计算路径成本。
|
|
|
|
|
|
### 4.2 最短路算法
|
|
|
|
|
|
当前使用:
|
|
|
|
|
|
```text
|
|
|
Dijkstra + bend_penalty
|
|
|
```
|
|
|
|
|
|
路径成本:
|
|
|
|
|
|
```text
|
|
|
edge_cost = segment_length * carrier_kind_factor + bend_penalty
|
|
|
```
|
|
|
|
|
|
其中:
|
|
|
|
|
|
```text
|
|
|
WireDuct = 1.0
|
|
|
RoutingPath = 1.0
|
|
|
AuxiliaryPath = 2.0
|
|
|
RoutingRange = 8.0
|
|
|
```
|
|
|
|
|
|
这使算法优先走线槽和明确路由路径,尽量少走辅助面域。
|
|
|
|
|
|
### 4.3 端子接入
|
|
|
|
|
|
模块:
|
|
|
|
|
|
```text
|
|
|
src/Mod/FreeCADExchange/AutoRouting.py
|
|
|
```
|
|
|
|
|
|
流程:
|
|
|
|
|
|
1. 读取起点端子和终点端子的全局坐标。
|
|
|
2. 按端子方向生成短出线段。
|
|
|
3. 找到距离起点出线点最近的路由节点。
|
|
|
4. 找到距离终点出线点最近的路由节点。
|
|
|
5. 在路由网络中执行 Dijkstra。
|
|
|
6. 将端子出线段、网络路径、终点入线段拼成最终折线。
|
|
|
|
|
|
当前算法名:
|
|
|
|
|
|
```text
|
|
|
network-dijkstra-v1
|
|
|
```
|
|
|
|
|
|
### 4.4 悬空线策略
|
|
|
|
|
|
当前版本默认:
|
|
|
|
|
|
```text
|
|
|
allow_floating_fallback = false
|
|
|
```
|
|
|
|
|
|
也就是说,如果没有可用路由网络,系统不会生成长距离悬空线,而是提示用户先创建线槽路径、草图路径或辅助路由区域。
|
|
|
|
|
|
调试时可以显式启用 fallback,但正式使用不建议开启。
|
|
|
|
|
|
### 4.5 障碍物处理
|
|
|
|
|
|
当前版本使用 AABB 包围盒做碰撞诊断:
|
|
|
|
|
|
1. 收集 FreeCAD 文档中的几何对象。
|
|
|
2. 排除端子、carrier、已布线导线、原点辅助对象。
|
|
|
3. 排除标记为 `QetRoutingObstacleMode = PassThrough` 的线槽实体。
|
|
|
4. 检查导线线段是否与障碍包围盒相交。
|
|
|
5. 如果有碰撞,导线状态设为:
|
|
|
|
|
|
```text
|
|
|
RouteStatus = "CollisionWarning"
|
|
|
```
|
|
|
|
|
|
当前版本是“碰撞诊断”,不是完整自由空间避障。
|
|
|
|
|
|
## 5. 当前已完成
|
|
|
|
|
|
### 5.1 Python 模块
|
|
|
|
|
|
已实现:
|
|
|
|
|
|
```text
|
|
|
src/Mod/FreeCADExchange/RoutingNetwork.py
|
|
|
src/Mod/FreeCADExchange/AutoRouting.py
|
|
|
src/Mod/FreeCADExchange/AutoRoutingPanel.py
|
|
|
```
|
|
|
|
|
|
并已加入:
|
|
|
|
|
|
```text
|
|
|
src/Mod/FreeCADExchange/CMakeLists.txt
|
|
|
src/Mod/FreeCADExchange/InitGui.py
|
|
|
```
|
|
|
|
|
|
### 5.2 路由网络功能
|
|
|
|
|
|
已完成:
|
|
|
|
|
|
1. 从选中草图线、Draft Wire、明确选中的边创建 `RoutingPath`。
|
|
|
2. 从选中线槽实体生成 `WireDuct` 中心路径。
|
|
|
3. 从选中面生成 `RoutingRange` 辅助路由区域。
|
|
|
4. 清除已生成路由路径。
|
|
|
5. 扫描并统计路由网络。
|
|
|
|
|
|
### 5.3 自动布线功能
|
|
|
|
|
|
已完成:
|
|
|
|
|
|
1. 两个选中端子之间自动布线。
|
|
|
2. 根据导线任务批量自动布线。
|
|
|
3. 使用 Dijkstra 求路。
|
|
|
4. 支持转弯惩罚。
|
|
|
5. 支持 carrier 类型成本。
|
|
|
6. 默认禁止长距离悬空线。
|
|
|
7. 碰撞检测和 `CollisionWarning` 状态。
|
|
|
8. 自动导线可见显示并保存到 FreeCAD 文档。
|
|
|
|
|
|
### 5.4 FreeCAD 面板
|
|
|
|
|
|
面板入口:
|
|
|
|
|
|
```text
|
|
|
QET模板 -> 3D自动布线
|
|
|
```
|
|
|
|
|
|
当前按钮:
|
|
|
|
|
|
```text
|
|
|
扫描端子/网络
|
|
|
从线槽实体生成中心路径
|
|
|
从线槽/草图创建路由路径
|
|
|
从选中面创建辅助路由区域
|
|
|
测试布线选中两个端子
|
|
|
按导线任务自动布线全部
|
|
|
清除自动布线
|
|
|
清除走线路径
|
|
|
保存
|
|
|
```
|
|
|
|
|
|
### 5.5 测试
|
|
|
|
|
|
已完成单元测试:
|
|
|
|
|
|
```text
|
|
|
tests/python/freecad_exchange_auto_routing_test.py
|
|
|
```
|
|
|
|
|
|
覆盖:
|
|
|
|
|
|
1. 无路由网络时默认拒绝悬空线。
|
|
|
2. 显式调试 fallback 时生成正交路径。
|
|
|
3. 优先使用用户路由网络。
|
|
|
4. 优先使用 `WireDuct`,降低 `RoutingRange` 优先级。
|
|
|
5. 从选中面生成辅助路由区域。
|
|
|
6. 选中整个实体不会把所有外壳边转成路径。
|
|
|
7. 从线槽实体生成中心路径。
|
|
|
8. 线槽实体不作为自身路径碰撞障碍。
|
|
|
9. 碰撞状态标记。
|
|
|
10. 批量导线任务缺端子时跳过。
|
|
|
11. 清除路由路径不删除已布线导线。
|
|
|
|
|
|
已完成 FreeCAD smoke:
|
|
|
|
|
|
```text
|
|
|
tests/manual/freecad_auto_routing_smoke.py
|
|
|
```
|
|
|
|
|
|
## 6. 当前使用流程
|
|
|
|
|
|
### 6.1 单条导线自动布线
|
|
|
|
|
|
```text
|
|
|
1. 打开 FreeCAD 工程 scene.FCStd
|
|
|
2. 进入 QET模板 -> 3D自动布线
|
|
|
3. 清除走线路径
|
|
|
4. 选中线槽实体
|
|
|
5. 点击“从线槽实体生成中心路径”
|
|
|
6. 必要时选草图线或 Draft Wire,点击“从线槽/草图创建路由路径”
|
|
|
7. 必要时选背板/门板面,点击“从选中面创建辅助路由区域”
|
|
|
8. 选中两个工程端子
|
|
|
9. 点击“测试布线选中两个端子”
|
|
|
```
|
|
|
|
|
|
### 6.2 批量导线自动布线
|
|
|
|
|
|
前提:
|
|
|
|
|
|
1. QET 导出的 `2d_to_3d.json` 中包含 `wires[]`。
|
|
|
2. 每条导线包含:
|
|
|
|
|
|
```text
|
|
|
start_terminal_uuid
|
|
|
end_terminal_uuid
|
|
|
```
|
|
|
|
|
|
3. FreeCAD 文档中存在对应 `QetTerminalUuid` 的工程端子。
|
|
|
|
|
|
操作:
|
|
|
|
|
|
```text
|
|
|
1. 创建线槽/路由网络
|
|
|
2. 点击“按导线任务自动布线全部”
|
|
|
```
|
|
|
|
|
|
注意:批量自动布线的依据是导线任务,不是“所有端子自动互连”。如果文档中只有端子而没有 `wires[]` 或 `QETWiring_01_Tasks`,系统不能判断哪些端子应该连接。
|
|
|
|
|
|
## 7. 当前限制
|
|
|
|
|
|
当前版本可完成自动布线原型,但仍有以下限制:
|
|
|
|
|
|
1. 线槽实体中心线生成基于包围盒长轴,不理解真实线槽开口、盖板和内部空间。
|
|
|
2. 多根线会沿同一路径生成,暂未做并行错位排列。
|
|
|
3. 未计算线槽填充率和容量。
|
|
|
4. 未考虑线径、最小弯曲半径。
|
|
|
5. 未做强弱电分槽、线缆类型隔离。
|
|
|
6. 障碍检测基于 AABB,存在误报和漏报。
|
|
|
7. 辅助路由区域是网格近似,不等于专业软件的完整布线区域建模。
|
|
|
8. 端子出线方向依赖端子 LCS 方向;如果模板端子方向不准,自动布线会受影响。
|
|
|
9. 导线几何当前保存在 FreeCAD 文档,不作为第一版数据库字段回写。
|
|
|
|
|
|
## 8. 后续需要完成
|
|
|
|
|
|
### 8.1 近期优先级
|
|
|
|
|
|
1. 线槽语义库
|
|
|
|
|
|
```text
|
|
|
WireDuct:
|
|
|
centerline
|
|
|
width
|
|
|
height
|
|
|
inlet/outlet
|
|
|
usable_area
|
|
|
cover_state
|
|
|
```
|
|
|
|
|
|
2. 多根线错位排列
|
|
|
|
|
|
```text
|
|
|
同一路径上的多根导线按 lane_offset 排列
|
|
|
避免完全重叠
|
|
|
```
|
|
|
|
|
|
3. 线槽容量和填充率
|
|
|
|
|
|
```text
|
|
|
按线径估算截面积
|
|
|
计算 duct fill ratio
|
|
|
超过阈值给出警告
|
|
|
```
|
|
|
|
|
|
4. 端子出线规则
|
|
|
|
|
|
```text
|
|
|
根据端子 LCS 方向、设备安装面、接线孔方向生成更合理的短出线段
|
|
|
```
|
|
|
|
|
|
### 8.2 中期能力
|
|
|
|
|
|
1. 真实几何碰撞检测
|
|
|
|
|
|
从 AABB 升级到更精确的 Shape / BRep 碰撞检测,降低误报。
|
|
|
|
|
|
2. 弯曲半径约束
|
|
|
|
|
|
根据线缆类型和线径控制转弯半径。
|
|
|
|
|
|
3. 线束对象
|
|
|
|
|
|
把多根同路导线抽象成 bundle,并支持展开显示。
|
|
|
|
|
|
4. 规则约束
|
|
|
|
|
|
支持:
|
|
|
|
|
|
```text
|
|
|
强电 / 弱电隔离
|
|
|
PE 线优先路径
|
|
|
屏蔽线规则
|
|
|
不同电压等级分槽
|
|
|
禁布区域
|
|
|
```
|
|
|
|
|
|
5. 更智能的线槽识别
|
|
|
|
|
|
根据对象名称、尺寸比例、设备库语义自动识别线槽,而不完全依赖用户选择。
|
|
|
|
|
|
### 8.3 长期能力
|
|
|
|
|
|
1. 接近 EPLAN / SOLIDWORKS 的工程级路由器。
|
|
|
2. 完整导线长度统计。
|
|
|
3. 自动生成线束报表。
|
|
|
4. 2D / 3D 导线一致性校验。
|
|
|
5. 自动推荐线槽路径和线槽容量。
|
|
|
6. 多柜体、多门板、多安装板之间的跨区域路由。
|
|
|
7. 可视化布线诊断面板。
|
|
|
|
|
|
## 9. 验收标准
|
|
|
|
|
|
当前版本验收只看“能否自动布线”:
|
|
|
|
|
|
1. 文档中有至少两个工程端子。
|
|
|
2. 文档中有至少一条 `WireDuct` 或 `RoutingPath` carrier。
|
|
|
3. 选择两个端子后执行单线测试布线,能生成 `AutoSuggested` 导线。
|
|
|
4. 存在导线任务时执行“按导线任务自动布线全部”,能批量生成 `AutoSuggested` 导线。
|
|
|
5. 生成导线在 `QETWiring_04_Routed` 下可见。
|
|
|
6. 没有路由网络时不生成长距离悬空线。
|
|
|
7. 没有导线任务时,批量布线明确提示缺少连接关系。
|
|
|
8. 明显碰撞时状态为 `CollisionWarning`。
|
|
|
9. 保存 FreeCAD 文档后,自动导线和路由网络仍保留。
|
|
|
|
|
|
## 10. 开发验证命令
|
|
|
|
|
|
单元测试:
|
|
|
|
|
|
```powershell
|
|
|
D:\FreeCAD-1.1.1\bin\python.exe -m unittest discover -s tests\python -p "freecad_exchange*_test.py"
|
|
|
```
|
|
|
|
|
|
真实 FreeCAD smoke:
|
|
|
|
|
|
```powershell
|
|
|
D:\FreeCAD-1.1.1\bin\python.exe tests\manual\freecad_auto_routing_smoke.py
|
|
|
```
|
|
|
|
|
|
语法检查:
|
|
|
|
|
|
```powershell
|
|
|
D:\FreeCAD-1.1.1\bin\python.exe -m py_compile src\Mod\FreeCADExchange\AutoRouting.py src\Mod\FreeCADExchange\RoutingNetwork.py src\Mod\FreeCADExchange\AutoRoutingPanel.py
|
|
|
```
|