522 lines
16 KiB
Markdown
522 lines
16 KiB
Markdown
# 空轨支持方案
|
||
|
||
## 一、需求分析
|
||
|
||
### 1.1 核心需求
|
||
|
||
1. **新增空轨属性**:在物流属性系统中增加"空轨"类型
|
||
2. **空轨路径生成**:
|
||
- 空轨走向固定,只需设置起点和终点
|
||
- 自动提取空轨几何体的下表面中心线作为路径
|
||
3. **路径类型区分**:路径需要标记为"地面路径"或"空轨路径"
|
||
4. **动画运行模式**:
|
||
- 地面路径:物体中心点在路径点上
|
||
- 空轨路径:物体悬挂在空轨下方运行(物体中心 = 路径点 - 物体高度/2)
|
||
5. **碰撞检测**:
|
||
- 统一使用3D碰撞检测
|
||
- 空轨路径需要排除空轨本身
|
||
6. **限制条件**:空轨暂时只支持人工路径,不支持自动路径规划
|
||
|
||
### 1.2 使用场景
|
||
|
||
- **地面路径**:转运车在楼面、走廊、通道上运行
|
||
- **空轨路径**:悬挂式输送设备在空轨上运行
|
||
|
||
### 1.3 已确认信息
|
||
|
||
1. ✅ **空轨模型**:已存在,不需要建模规范
|
||
2. ✅ **空轨类型**:不需要分类型,只有一个"空轨"类型
|
||
3. ✅ **物体悬挂**:物体悬挂在空轨下方
|
||
4. ✅ **碰撞检测**:需要排除空轨本身
|
||
5. ✅ **数据库迁移**:不需要,新字段使用默认值
|
||
6. ✅ **向后兼容**:不需要向后兼容性
|
||
7. ✅ **碰撞检测统一**:地面路径和空轨路径都使用3D碰撞检测
|
||
8. ✅ **轨道几何**:轨道不是水平的,需要精确计算几何体数据
|
||
|
||
---
|
||
|
||
## 二、架构影响分析
|
||
|
||
### 2.1 涉及的核心模块
|
||
|
||
| 模块 | 影响程度 | 改动内容 |
|
||
|------|---------|---------|
|
||
| **物流属性系统** | 🟢 低 | 新增"空轨"枚举值 |
|
||
| **路径数据模型** | 🟡 中 | 新增路径类型字段 |
|
||
| **路径规划系统** | 🟡 中 | 新增空轨路径生成逻辑 |
|
||
| **动画系统** | 🟡 中 | 根据路径类型调整物体位置 |
|
||
| **碰撞检测系统** | 🟢 低 | 空轨路径排除空轨本身 |
|
||
| **UI界面** | 🟡 中 | 路径类型选择、空轨路径生成 |
|
||
|
||
---
|
||
|
||
## 三、详细实施方案
|
||
|
||
### 3.1 第一阶段:基础数据结构(1天)
|
||
|
||
#### 3.1.1 新增空轨属性
|
||
|
||
**文件**:`CategoryAttributeManager.cs`
|
||
|
||
```csharp
|
||
public enum LogisticsElementType
|
||
{
|
||
// ... 现有类型 ...
|
||
|
||
/// <summary>
|
||
/// 空轨 - 空中运输路径,物体悬挂运行,权重0.7
|
||
/// </summary>
|
||
空轨 = 9,
|
||
}
|
||
```
|
||
|
||
#### 3.1.2 路径类型枚举
|
||
|
||
**文件**:`PathPlanningModels.cs`
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 路径类型
|
||
/// </summary>
|
||
public enum PathType
|
||
{
|
||
/// <summary>
|
||
/// 地面路径 - 物体在地面运行
|
||
/// </summary>
|
||
Ground = 0,
|
||
|
||
/// <summary>
|
||
/// 空轨路径 - 物体悬挂在空轨下方运行
|
||
/// </summary>
|
||
Rail = 1,
|
||
}
|
||
```
|
||
|
||
#### 3.1.3 路径数据模型扩展
|
||
|
||
**文件**:`PathRouteViewModel.cs`
|
||
|
||
```csharp
|
||
private PathType _pathType = PathType.Ground;
|
||
|
||
public PathType PathType
|
||
{
|
||
get => _pathType;
|
||
set => SetProperty(ref _pathType, value);
|
||
}
|
||
```
|
||
|
||
#### 3.1.4 路径数据库适配
|
||
|
||
**文件**:`PathDatabase.cs`
|
||
|
||
```csharp
|
||
// 保存路径时,保存路径类型
|
||
public void SavePath(PathRouteViewModel path)
|
||
{
|
||
// ... 现有逻辑 ...
|
||
// 新增:保存路径类型
|
||
}
|
||
|
||
// 加载路径时,读取路径类型
|
||
public PathRouteViewModel LoadPath(string pathId)
|
||
{
|
||
// ... 现有逻辑 ...
|
||
// 新增:读取路径类型
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.2 第二阶段:空轨路径生成(2天)
|
||
|
||
#### 3.2.1 复用现有几何计算
|
||
|
||
**现有代码复用**:
|
||
|
||
- `ChannelHeightDetector.AnalyzeChannelGeometry()` - 分析通道几何
|
||
- `ChannelHeightDetector.CalculatePreciseHeightAtPosition()` - 计算精确高度
|
||
- `GeometryHelper.ExtractTriangles()` - 提取三角形
|
||
- `GeometryHelper.RayTriangleIntersect()` - 射线-三角形交点检测
|
||
|
||
#### 3.2.2 新增底部高度检测方法
|
||
|
||
**文件**:`ChannelHeightDetector.cs`
|
||
|
||
新增方法:
|
||
|
||
- `GetChannelBottomHeight(Point3D position, IEnumerable<ModelItem> channelItems)` - 获取通道底面高度
|
||
- `CalculateBottomPreciseHeightAtPosition(Point3D position, ChannelHeightInfo heightInfo, ModelItem channel)` - 计算底面精确高度
|
||
- `TryRaycastFromBelow(Point3D position, ModelItem channel, double floorHeight, out double height)` - 从下方射线投射
|
||
- `PerformRayTriangleIntersectionFromBelow(Point3D position, List<Triangle3D> triangles)` - 从下往上射线-三角形交点检测
|
||
- `TryGetGeometricBottomHeight(Point3D position, ModelItem channel, out double height)` - View API获取底面高度
|
||
- `AnalyzeBottomSurfaceHeightAtPosition(Point3D position, ModelItem channel, double floorHeight, double ceilingHeight)` - 分析底面表面高度
|
||
- `TryMultiPointBottomSampling(Point3D position, ModelItem channel)` - 多点采样获取底面高度
|
||
|
||
#### 3.2.3 空轨中心线提取工具
|
||
|
||
**文件**:`RailGeometryHelper.cs`(新建)
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 空轨几何体辅助工具
|
||
/// 负责提取空轨的下表面中心线
|
||
/// </summary>
|
||
public static class RailGeometryHelper
|
||
{
|
||
/// <summary>
|
||
/// 从空轨几何体提取下表面中心线
|
||
/// </summary>
|
||
/// <param name="railModel">空轨模型项</param>
|
||
/// <param name="startPoint">起点(2D坐标)</param>
|
||
/// <param name="endPoint">终点(2D坐标)</param>
|
||
/// <returns>路径点列表(包含精确的Z坐标)</returns>
|
||
public static List<Point3D> ExtractRailCenterLine(
|
||
ModelItem railModel,
|
||
Point3D startPoint,
|
||
Point3D endPoint)
|
||
{
|
||
var pathPoints = new List<Point3D>();
|
||
|
||
try
|
||
{
|
||
LogManager.Debug($"[空轨] 开始提取空轨中心线: {railModel.DisplayName}");
|
||
|
||
// 1. 创建高度检测器实例
|
||
var heightDetector = new ChannelHeightDetector();
|
||
var railItems = new List<ModelItem> { railModel };
|
||
|
||
// 2. 计算起点和终点在X-Y平面上的投影距离
|
||
double distance2D = Math.Sqrt(
|
||
Math.Pow(endPoint.X - startPoint.X, 2) +
|
||
Math.Pow(endPoint.Y - startPoint.Y, 2)
|
||
);
|
||
|
||
if (distance2D < 0.01)
|
||
{
|
||
LogManager.Warning("[空轨] 起点和终点重合");
|
||
return pathPoints;
|
||
}
|
||
|
||
// 3. 在起点和终点之间采样,计算每个采样点的精确Z坐标
|
||
int sampleCount = Math.Max(2, (int)Math.Ceiling(distance2D / 0.5)); // 每0.5米一个采样点
|
||
|
||
for (int i = 0; i < sampleCount; i++)
|
||
{
|
||
double t = (double)i / (sampleCount - 1);
|
||
|
||
// 线性插值计算X、Y坐标
|
||
double x = startPoint.X + t * (endPoint.X - startPoint.X);
|
||
double y = startPoint.Y + t * (endPoint.Y - startPoint.Y);
|
||
double z = startPoint.Z; // 初始Z坐标
|
||
|
||
// 调用现有的GetChannelBottomHeight方法获取精确底面高度
|
||
var samplePoint = new Point3D(x, y, z); // Z坐标会被方法更新
|
||
var bottomHeight = heightDetector.GetChannelBottomHeight(samplePoint, railItems);
|
||
|
||
pathPoints.Add(new Point3D(x, y, bottomHeight));
|
||
}
|
||
|
||
LogManager.Debug($"[空轨] 生成 {pathPoints.Count} 个路径点,总长度: {distance2D:F2}m");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[空轨] 提取空轨中心线失败: {ex.Message}");
|
||
}
|
||
|
||
return pathPoints;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3.2.4 路径编辑器扩展
|
||
|
||
**文件**:`PathEditingViewModel.cs`
|
||
|
||
新增方法:
|
||
|
||
- `GeneratePathFromRail(ModelItem railModel, Point3D startPoint, Point3D endPoint)` - 从空轨生成路径
|
||
- `SelectRailModelCommand` - 选择空轨命令
|
||
- `SetPathStartPointCommand` - 设置起点命令
|
||
- `SetPathEndPointCommand` - 设置终点命令
|
||
- `GeneratePathFromRailCommand` - 生成路径命令
|
||
|
||
新增属性:
|
||
|
||
- `SelectedPathType` - 选中的路径类型
|
||
- `PathTypes` - 路径类型数组
|
||
- `IsRailPathType` - 是否为空轨路径类型
|
||
- `SelectedRailModel` - 选中的空轨模型
|
||
- `SelectedRailModelName` - 选中的空轨模型名称
|
||
- `PathStartPoint` - 路径起点
|
||
- `PathStartPointDisplay` - 路径起点显示
|
||
- `PathEndPoint` - 路径终点
|
||
- `PathEndPointDisplay` - 路径终点显示
|
||
|
||
---
|
||
|
||
### 3.3 第三阶段:动画系统适配(1天)
|
||
|
||
#### 3.3.1 物体位置计算
|
||
|
||
**文件**:`PathAnimationManager.cs`
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 计算物体在路径点上的位置
|
||
/// </summary>
|
||
private Point3D CalculateObjectPosition(Point3D pathPoint, PathType pathType)
|
||
{
|
||
if (pathType == PathType.Rail)
|
||
{
|
||
// 空轨路径:物体悬挂在空轨下方
|
||
// 物体中心点 = 空轨点 - 物体高度的一半
|
||
double objectCenterZ = pathPoint.Z - _virtualObjectHeight / 2;
|
||
return new Point3D(pathPoint.X, pathPoint.Y, objectCenterZ);
|
||
}
|
||
else
|
||
{
|
||
// 地面路径:物体中心点在路径点上
|
||
return pathPoint;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3.3.2 传递路径类型
|
||
|
||
**文件**:`PathAnimationManager.cs`
|
||
|
||
修改方法:
|
||
|
||
- `GenerateAnimationFrames(List<Point3D> pathPoints, PathType pathType)` - 传递路径类型参数
|
||
- `PrecomputeCollisions(List<Point3D> pathPoints, PathType pathType, List<ModelItem> railModels)` - 传递路径类型和空轨模型列表
|
||
- `DetectFrameCollisions(AnimationFrame frame, PathType pathType, List<ModelItem> collisionExclusions)` - 传递路径类型和排除列表
|
||
|
||
---
|
||
|
||
### 3.4 第四阶段:碰撞检测适配(1天)
|
||
|
||
#### 3.4.1 空轨排除逻辑
|
||
|
||
**文件**:`PathAnimationManager.cs`
|
||
|
||
修改方法:
|
||
|
||
- `PrecomputeCollisions(List<Point3D> pathPoints, PathType pathType, List<ModelItem> railModels)` - 新增空轨排除列表
|
||
- `DetectFrameCollisions(AnimationFrame frame, PathType pathType, List<ModelItem> collisionExclusions)` - 使用排除列表过滤
|
||
|
||
**核心逻辑**:
|
||
|
||
```csharp
|
||
// 创建碰撞排除列表
|
||
var collisionExclusions = new List<ModelItem>();
|
||
|
||
// 如果是空轨路径,将空轨模型加入排除列表
|
||
if (pathType == PathType.Rail && railModels != null)
|
||
{
|
||
collisionExclusions.AddRange(railModels);
|
||
LogManager.Info($"[碰撞检测] 已排除 {railModels.Count} 个空轨模型");
|
||
}
|
||
|
||
// 在碰撞检测循环中跳过排除列表中的项目
|
||
foreach (var modelItem in allModelItems)
|
||
{
|
||
// 跳过排除列表中的项目(包括空轨本身)
|
||
if (collisionExclusions.Contains(modelItem))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// 统一使用3D碰撞检测
|
||
double distance = BoundingBoxGeometryUtils.CalculateDistance(objectBoundingBox, modelBoundingBox);
|
||
|
||
if (distance <= 0) // 相交或接触
|
||
{
|
||
collisions.Add(new CollisionResult
|
||
{
|
||
Item1 = _animatedObject,
|
||
Item2 = modelItem,
|
||
Distance = distance
|
||
});
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.5 第五阶段:UI界面适配(1天)
|
||
|
||
#### 3.5.1 路径类型选择
|
||
|
||
**文件**:`PathEditingViewModel.cs`
|
||
|
||
新增属性:
|
||
|
||
- `PathTypes` - 路径类型数组
|
||
- `SelectedPathType` - 选中的路径类型
|
||
- `IsRailPathType` - 是否为空轨路径类型
|
||
|
||
#### 3.5.2 命令
|
||
|
||
**文件**:`PathEditingViewModel.cs`
|
||
|
||
新增命令:
|
||
|
||
- `GeneratePathFromRailCommand` - 从空轨生成路径命令
|
||
- `SelectRailModelCommand` - 选择空轨命令
|
||
- `SetPathStartPointCommand` - 设置起点命令
|
||
- `SetPathEndPointCommand` - 设置终点命令
|
||
|
||
#### 3.5.3 UI布局
|
||
|
||
**文件**:`LogisticsControlPanel.xaml`
|
||
|
||
新增控件:
|
||
|
||
- 路径类型选择 ComboBox
|
||
- 空轨选择 StackPanel(仅在选择空轨类型时显示)
|
||
- 选择空轨按钮
|
||
- 设置起点按钮
|
||
- 设置终点按钮
|
||
- 生成路径按钮
|
||
|
||
---
|
||
|
||
## 四、实施步骤
|
||
|
||
### 第一阶段:基础数据结构(1天)
|
||
|
||
1. ✅ 新增"空轨"物流属性类型
|
||
2. ✅ 新增路径类型枚举
|
||
3. ✅ 扩展路径数据模型
|
||
4. ✅ 适配数据库读写
|
||
|
||
### 第二阶段:空轨路径生成(2天)
|
||
|
||
1. ✅ 在 `ChannelHeightDetector` 中新增底部高度检测方法
|
||
2. ✅ 复用现有的几何计算代码
|
||
3. ✅ 实现 `RailGeometryHelper`(调用现有方法)
|
||
4. ✅ 扩展路径编辑器
|
||
5. ✅ UI界面适配
|
||
6. ✅ 集成测试
|
||
|
||
### 第三阶段:动画系统适配(1天)
|
||
|
||
1. ✅ 物体位置计算适配
|
||
2. ✅ 传递路径类型参数
|
||
3. ✅ 动画播放测试
|
||
|
||
### 第四阶段:碰撞检测适配(1天)
|
||
|
||
1. ✅ 实现空轨排除逻辑
|
||
2. ✅ 统一使用3D碰撞检测
|
||
3. ✅ 碰撞报告适配
|
||
4. ✅ 集成测试
|
||
|
||
### 第五阶段:测试和优化(1天)
|
||
|
||
1. ✅ 功能测试
|
||
2. ✅ 性能测试
|
||
3. ✅ 用户验收测试
|
||
|
||
**总计**:6天
|
||
|
||
---
|
||
|
||
## 五、风险评估
|
||
|
||
| 风险项 | 风险等级 | 缓解措施 |
|
||
|--------|---------|---------|
|
||
| 空轨几何体提取失败 | 🟢 低 | 空轨模型已存在,直接使用 |
|
||
| 物体悬挂位置计算错误 | 🟡 中 | 充分测试,提供可视化验证 |
|
||
| 碰撞检测误报 | 🟡 中 | 排除空轨本身,调整检测参数 |
|
||
| 性能下降 | 🟢 低 | 空轨路径数量少,影响有限 |
|
||
| 几何计算性能 | 🟡 中 | 复用现有代码,优化采样策略 |
|
||
|
||
---
|
||
|
||
## 六、总结
|
||
|
||
### 6.1 方案优势
|
||
|
||
- ✅ **代码复用最大化**:充分利用现有的几何计算代码
|
||
- ✅ **架构统一**:空轨和地面路径使用相同的高度检测框架
|
||
- ✅ **改动最小化**:只需新增底部检测方法,其他全部复用
|
||
- ✅ **易于维护**:几何计算逻辑集中管理
|
||
- ✅ **向后兼容**:不需要迁移,新字段使用默认值
|
||
- ✅ **碰撞检测统一**:统一使用3D检测,简化逻辑
|
||
|
||
### 6.2 关键技术点
|
||
|
||
1. **复用现有代码**:`ChannelHeightDetector` 的几何计算方法
|
||
2. **新增底部检测**:`GetChannelBottomHeight()` 方法
|
||
3. **物体悬挂计算**:物体中心 = 空轨点 - 物体高度/2
|
||
4. **碰撞检测统一**:统一使用3D检测
|
||
5. **排除空轨本身**:通过排除列表过滤空轨模型
|
||
6. **精确几何计算**:支持倾斜、弯曲的轨道
|
||
|
||
### 6.3 技术难点
|
||
|
||
- 需要处理大量三角形面片(性能优化)
|
||
- 需要处理重叠三角形(选择最高点)
|
||
- 需要处理采样点不在任何三角形内的情况(使用默认值)
|
||
|
||
### 6.4 预期成果
|
||
|
||
- ✅ 支持空轨路径生成
|
||
- ✅ 支持物体悬挂运行
|
||
- ✅ 支持空轨碰撞检测(排除空轨本身)
|
||
- ✅ 保持与现有地面路径功能的兼容性
|
||
|
||
---
|
||
|
||
## 七、附录
|
||
|
||
### 7.1 文件清单
|
||
|
||
#### 新增文件
|
||
|
||
- `RailGeometryHelper.cs` - 空轨几何体辅助工具
|
||
|
||
#### 修改文件
|
||
|
||
- `CategoryAttributeManager.cs` - 新增空轨枚举
|
||
- `PathPlanningModels.cs` - 新增路径类型枚举
|
||
- `PathRouteViewModel.cs` - 新增路径类型字段
|
||
- `PathDatabase.cs` - 适配路径类型读写
|
||
- `ChannelHeightDetector.cs` - 新增底部高度检测方法
|
||
- `PathEditingViewModel.cs` - 扩展路径编辑功能
|
||
- `PathAnimationManager.cs` - 适配物体位置和碰撞检测
|
||
- `LogisticsControlPanel.xaml` - UI界面适配
|
||
|
||
### 7.2 方法清单
|
||
|
||
#### 新增方法(ChannelHeightDetector.cs)
|
||
|
||
- `GetChannelBottomHeight(Point3D position, IEnumerable<ModelItem> channelItems)` - 获取通道底面高度
|
||
- `CalculateBottomPreciseHeightAtPosition(Point3D position, ChannelHeightInfo heightInfo, ModelItem channel)` - 计算底面精确高度
|
||
- `TryRaycastFromBelow(Point3D position, ModelItem channel, double floorHeight, out double height)` - 从下方射线投射
|
||
- `PerformRayTriangleIntersectionFromBelow(Point3D position, List<Triangle3D> triangles)` - 从下往上射线-三角形交点检测
|
||
- `TryGetGeometricBottomHeight(Point3D position, ModelItem channel, out double height)` - View API获取底面高度
|
||
- `AnalyzeBottomSurfaceHeightAtPosition(Point3D position, ModelItem channel, double floorHeight, double ceilingHeight)` - 分析底面表面高度
|
||
- `TryMultiPointBottomSampling(Point3D position, ModelItem channel)` - 多点采样获取底面高度
|
||
|
||
#### 新增方法(RailGeometryHelper.cs)
|
||
|
||
- `ExtractRailCenterLine(ModelItem railModel, Point3D startPoint, Point3D endPoint)` - 提取空轨中心线
|
||
|
||
#### 新增方法(PathEditingViewModel.cs)
|
||
|
||
- `GeneratePathFromRail(ModelItem railModel, Point3D startPoint, Point3D endPoint)` - 从空轨生成路径
|
||
|
||
#### 新增方法(PathAnimationManager.cs)
|
||
|
||
- `CalculateObjectPosition(Point3D pathPoint, PathType pathType)` - 计算物体位置
|
||
|
||
#### 修改方法(PathAnimationManager.cs)
|
||
|
||
- `GenerateAnimationFrames(List<Point3D> pathPoints, PathType pathType)` - 传递路径类型参数
|
||
- `PrecomputeCollisions(List<Point3D> pathPoints, PathType pathType, List<ModelItem> railModels)` - 传递路径类型和空轨模型列表
|
||
- `DetectFrameCollisions(AnimationFrame frame, PathType pathType, List<ModelItem> collisionExclusions)` - 传递路径类型和排除列表
|
||
|
||
--- |