Files
test_demo/MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/Process/DieTransfer/Planning/Code
Shi.Ji e31d3560bb 添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
2026-05-18 11:43:09 +08:00

386 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MainShell/Process/DieTransfer/Planning 说明与代码审阅
## 1. 范围
本次说明覆盖 `MainShell/Process/DieTransfer/Planning` 目录下的规划相关实现,包含以下文件:
- `DieTransferPathGenerator.cs`
- `DieTransferPlanningContext.cs`
- `DieTransferPathRequest.cs`
- `DieTransferPathPlan.cs`
- `DieTransferPathRegionPlan.cs`
- `DieTransferPathStep.cs`
- `DieTransferRegion.cs`
- `DieTransferRow.cs`
- `PadTransferRow.cs`
- `DieTransferRowDirection.cs`
- `SubstrateRowDirectionStrategy.cs`
- `IDieTransferPathGenerator.cs`
## 2. 模块定位
该模块是 Die Transfer 的“规划层”,职责不是执行运动,而是把候选 Die 集合和候选 Pad 集合转换成一份可执行的路径计划。
输入侧负责提供:
- 候选 Die 集合
- 候选 Pad 集合
- Die 区域
- Substrate 区域
- 路径生成策略
- 是否跳过 NG Die
- 基板行方向策略
输出侧负责提供:
- 已生成的配对步骤 `Steps`
- 过滤后的可用 Die / Pad 数量
- 剩余未配对的 Die / Pad
- 剩余区域的行结构和区域边界
整体设计是合理的:规划逻辑与运动执行解耦,后续无论手动模式还是自动流程,都可以复用同一套路径生成器。
## 3. 核心对象职责
### 3.1 `DieTransferPathRequest`
路径规划输入对象。
关键字段:
- `DieCandidates`:候选 Die 集合
- `PadCandidates`:候选 Pad 集合
- `DieRegion`Die 过滤区域
- `SubstrateRegion`Pad 过滤区域
- `TransPathType`:路径生成模式
- `SubstrateRowDirectionStrategy`Pad 行遍历方向
- `SkipNgDie`:是否跳过 NG Die
默认值设置比较合理:
- 默认模式是 `Sequence`
- 默认 Pad 行方向是 `AllPositive`
- 默认跳过 NG Die
### 3.2 `DieTransferPlanningContext`
这是当前模块最核心的中间对象。它的作用不是对外暴露,而是把 request 预处理成“可直接生成路径”的内部上下文。
它主要做三件事:
1. 把 `RegionModel` 转成内部使用的 `DieTransferRegion`
2. 把原始候选点整理成按行分组的 `DieTransferRow` / `PadTransferRow`
3. 根据行方向规则,把每一行的点组织成确定顺序
换句话说,真正的“排序、过滤、按行组织”都不在 generator 本体里,而是在 context 创建阶段完成。
### 3.3 `DieTransferPathGenerator`
路径生成入口。
对外现有四个方法:
- `Generate()`:返回 `DieTransferPathPlan`
- `GenerateByRegion()`:返回 `DieTransferPathRegionPlan`
- `GenerateByCandidates()`:根据传入的 Pad 集合和 Die 集合生成 `DieTransferPathRegionPlan`
- `GenerateByRows()`:根据传入的 `PadTransferRow` / `DieTransferRow` 直接生成 `DieTransferPathRegionPlan`
其中 `Generate()` 实际只是转调 `GenerateByRegion()`,只是把返回类型收窄成基类。因此:
- 如果调用方只关心步骤列表和统计信息,用 `Generate()` 即可
- 如果调用方还关心剩余 Die / Pad 和剩余区域,应该使用 `GenerateByRegion()`
两个新增入口的定位如下:
- `GenerateByCandidates()`:适合调用方手里只有原始候选点集合,但不想自己组装 `DieTransferPathRequest` 的场景。该方法内部仍会走现有的 request/context 预处理逻辑,生成的路径统一从返回结果的 `Steps` 中获取。
- `GenerateByRows()`适合调用方已经完成按行分组、方向整理、NG 过滤策略配置的场景。该方法不会重新构建 planning context而是直接把传入行展开为有序 Die / Pad再生成步骤和剩余区域。
### 3.4 `DieTransferPathPlan` / `DieTransferPathRegionPlan`
`DieTransferPathPlan` 表示基础规划结果,包含:
- `TransPathType`
- `Steps`
- `AvailableDieCount`
- `AvailablePadCount`
- `GeneratedStepCount`
`DieTransferPathRegionPlan` 在此基础上扩展了剩余信息:
- `RemainingDies`
- `RemainingPads`
- `RemainingDieRows`
- `RemainingPadRows`
- `RemainingDieRegion`
- `RemainingSubstrateRegion`
这意味着该模块不仅能生成一次路径,还能给下一轮继续规划留下上下文。
### 3.5 `DieTransferPathStep`
单步配对结果对象,记录:
- 步序号 `StepIndex`
- Die 行列和坐标
- Pad 行列和坐标
- 当前路径类型
这个对象设计得比较直接,后续 UI 或执行层都容易消费。
## 4. 生成方法总流程
路径生成的主流程如下:
1. 调用方构造 `DieTransferPathRequest`
2. `DieTransferPathGenerator.GenerateByRegion()` 校验 request 非空
3. `DieTransferPlanningContext.Create(request)` 生成规划上下文
4. 从 context 中取出有序的 Die 列表和 Pad 列表
5. 按 `TransPathType` 选择生成策略
6. 生成 `DieTransferPathStep` 列表
7. 计算未参与配对的剩余 Die / Pad
8. 计算剩余行结构和剩余区域
9. 组装 `DieTransferPathRegionPlan` 返回
可以把它理解为两段式流程:
- 第一段:预处理输入,得到稳定顺序
- 第二段:按策略做 Die 与 Pad 的一一配对
新增的两个入口,本质上只是改变“输入落点”,不改变“路径生成算法”:
- `GenerateByCandidates()`:从候选集合进入,再复用 `GenerateByRegion()` 的完整流程
- `GenerateByRows()`:跳过 request/context 构建,直接从行对象展开为有序点集合后进入配对阶段
## 5. 预处理阶段讲解
### 5.1 区域过滤
`DieTransferPlanningContext.Create()` 首先把 `request.DieRegion` 和 `request.SubstrateRegion` 转成 `DieTransferRegion`。
`DieTransferRegion.Contains(row, column)` 负责判断点是否落在区域内。
当前语义如下:
- 区域不为空:按区域过滤
- 区域为空:视为不过滤,所有候选点均可参与规划
这一点在实现上是清晰的,但最好在文档或接口注释中明确说明,因为这是一个业务约定。
### 5.2 按行分组
Pad 和 Die 都不是直接整体排序,而是先按 `Row` 分组,再在每一行内部决定遍历方向。
Pad 通过 `CreatePadRows()` 生成 `PadTransferRow`
- 先过滤空对象和区域外点
- 按 `Row` 分组
- 每组按 `Column` 升序保存原始集合
- 再根据策略决定当前行最终读取方向
Die 通过 `CreateDieRows()` 生成 `DieTransferRow`
- 先过滤空对象和区域外点
- 按 `Row` 分组
- 每组按 `Column` 升序保存
- 行方向固定按蛇形方式决定
- `SkipNgDie` 在行对象中生效
### 5.3 行方向规则
Pad 的行方向由 `SubstrateRowDirectionStrategy` 决定:
- `AllPositive`:所有行都从小列到大列
- `AllNegative`:所有行都从大列到小列
- `Serpentine`:奇数行正向,偶数行反向
Die 的行方向当前固定采用蛇形规则,因为 `CreateDieRows()` 被调用时 `useSerpentineDirection` 固定传入 `true`
- 奇数行正向
- 偶数行反向
这意味着当前设计里Die 的遍历顺序比 Pad 更“强约束”,调用方无法在 request 中单独配置 Die 行方向。
### 5.4 可用点提取
在分组完成后context 通过以下方法展平成最终有序列表:
- `GetOrderedPads()`
- `GetOrderedDies()`
这两个方法都会按 `RowIndex` 升序遍历各行,再拼接每行的可用点序列。
其中 Die 侧的“可用”还额外受 `SkipNgDie` 影响:
- `SkipNgDie = true` 时,`DieStatus.Ng` 会被排除
- `SkipNgDie = false` 时,所有 Die 都会参与规划
因此,后续真正参与生成的并不是 request 里的原始候选集合而是“经过区域过滤、方向排序、NG 过滤后的线性序列”。
## 6. 两种生成方法讲解
### 6.1 顺序生成 `BuildSequenceSteps`
这是最直接的策略。
处理方式:
1. 先得到 `orderedDies` 和 `orderedPads`
2. 取 `Math.Min(dies.Count, pads.Count)` 作为可生成步数
3. 第 `i` 个 Die 与第 `i` 个 Pad 直接配对
4. 调用 `CreateStep()` 生成步骤对象
伪代码如下:
```text
stepCount = min(orderedDies.Count, orderedPads.Count)
for i in [0 .. stepCount - 1]
step = CreateStep(i + 1, orderedDies[i], orderedPads[i])
steps.Add(step)
```
该策略的特点是:
- 完全依赖预处理后的顺序
- 算法简单,复杂度低
- 结果稳定,便于追溯
- 不考虑实际几何距离,只考虑排好序后的对应关系
适用场景:
- 生产节拍更看重顺序一致性
- 上游已经保证 Die / Pad 序列一一对应
- 希望路径可预测、容易校验和复现
### 6.2 最近生成 `BuildNearestSteps`
这是更偏几何优化的策略。
处理方式:
1. 先复制一份 `remainingDies`
2. 按 Pad 的既定顺序逐个处理每个 Pad
3. 在当前剩余 Die 中,找出距离该 Pad 最近的 Die
4. 生成一步配对后,把该 Die 从 `remainingDies` 中移除
5. 继续处理下一个 Pad直到 Die 用完或 Pad 遍历完毕
伪代码如下:
```text
remainingDies = orderedDies
for each pad in orderedPads
if remainingDies is empty
break
die = SelectNearestDie(pad, remainingDies)
steps.Add(CreateStep(stepIndex, die, pad))
remainingDies.Remove(die)
stepIndex++
```
这个策略不是全局最优匹配,而是“按 Pad 顺序逐个贪心选择最近 Die”。
它的优点是:
- 实现简单
- 对局部移动距离有优化作用
- 比完全顺序配对更贴近空间位置
它的限制也很明确:
- 它不是匈牙利算法一类的全局最优解
- 前面 Pad 的选择会影响后面 Pad 的可选 Die
- 最终总路程不一定最短
因此,这个“最近策略”更准确的表述应该是:
- 按 Pad 顺序执行的局部贪心最近匹配
### 6.3 最近 Die 的选取规则 `SelectNearestDie`
`SelectNearestDie()` 遍历当前所有剩余 Die并选择距离最小的那个。
当前距离计算公式为:
```text
(die.X - pad.X)^2 + (die.Y - pad.Y)^2
```
这里返回的是平方距离,而不是开方后的欧氏距离。对于“比较谁更近”这个问题,平方距离是等价的,且计算更省。
需要注意两点:
1. `CalculateDistance()` 这个命名不够精确,实际更像 `CalculateSquaredDistance()`
2. 当距离相等时,当前代码按“先遍历到谁就保留谁”处理
第二点尤其需要讲清楚:
- 当前 tie-break 不是直接按 `Row`、`Column` 比较
- 它依赖 `remainingDies` 的当前顺序
- 而 `remainingDies` 的顺序,又来自 Die 行的蛇形组织结果
也就是说,当两个 Die 与同一个 Pad 等距时最终胜出者本质上由“Die 预处理后的线性顺序”决定。
## 7. 剩余结果的生成方式
路径步骤生成完成后,`GenerateByRegion()` 还会继续做一层“剩余状态提取”。
对新增入口来说,剩余结果生成规则分别是:
- `GenerateByCandidates()`:与 `GenerateByRegion()` 完全一致,因为内部就是组装 request 后复用区域入口
- `GenerateByRows()`:保留调用方传入行对象中的 `RowIndex`、`Direction`、`SkipNgDie` 等行级配置,只过滤掉本轮已使用点位,再构造 `RemainingPadRows` / `RemainingDieRows`
### 7.1 剩余 Die / Pad 计算
通过 `CreateRemainingPads()` 和 `CreateRemainingDies()`
- 从步骤列表中提取已经使用过的 `(row, column)` 键
- 对原有有序集合做差集
- 得到未参与本轮规划的点
这里使用 `(row, column)` 作为唯一键,说明当前模块默认一个点位由行列唯一标识。
### 7.2 剩余行结构重建
剩余 Pad / Die 并不只是简单返回列表,还会重新生成:
- `RemainingPadRows`
- `RemainingDieRows`
这非常有价值,因为后续如果要做二次规划,不需要重新整理全部数据结构。
### 7.3 剩余区域重建
`CreateRegionFromPads()` 和 `CreateRegionFromDies()` 会根据剩余点重新计算最小包围区域:
- 最小行
- 最小列
- 最大行
- 最大列
如果没有剩余点,则返回 `null`。
这个设计能让调用方快速判断:
- 当前是否已全部规划完成
- 还剩下哪一片区域未处理
## 8. 代码审阅结论
### 8.1 优点
该模块的优点比较明确:
- 职责单一,专注于规划而非执行
- request / context / result 三层结构清楚
- 顺序策略和最近策略边界明确
- 剩余区域输出增强了复用性
- 代码整体可读性较好,扩展入口也比较清晰
### 8.2 需要注意的点
当前实现没有明显功能性缺陷,但有几个维护层面的注意点:
1. `CalculateDistance()` 实际是平方距离,建议改名或补注释
2. 最近策略是局部贪心,不是全局最优匹配,建议在文档中明确
3. 等距时的选择规则依赖 Die 预处理顺序,建议明确写入说明
4. `AvailableDieCount` / `AvailablePadCount` 表示过滤后的可用数量,不是原始候选数
5. 区域为 `null` 时表示不过滤,这属于隐式约定,建议补充说明
6. `Generate()` 返回基类,但实际内部生成的是区域计划对象,调用方需明确自己是否需要剩余区域信息
### 8.3 可改进但不必立即重构的点
以下问题存在,但不建议为此做大改:
- 结果对象是可写模型,存在被外部修改的可能
- `DieTransferPathGenerator` 中保留了未被使用的 `OrderDies()` / `OrderPads()` 私有方法,可在后续清理
- 命名空间仍统一使用 `MainShell.Process`,与目录层次不是完全一一对应,但符合当前仓库惯例
## 9. 总结
Planning 模块的核心思路可以概括为一句话:
先把候选 Die / Pad 依据区域、行方向、NG 过滤整理成稳定顺序,再按“顺序配对”或“局部贪心最近配对”生成 `DieTransferPathStep` 列表,最后补充剩余点和剩余区域信息。
如果从可维护性看,这套实现已经具备较好的基础。当前更需要的是把策略语义讲清楚,而不是立即做结构性重构。尤其是以下三点,建议作为后续文档或注释的固定说明:
- 最近模式是局部贪心,不是全局最优
- 距离比较使用平方距离
- 等距时遵循 Die 预处理后的先后顺序