16 KiB
16 KiB
空轨支持方案
一、需求分析
1.1 核心需求
- 新增空轨属性:在物流属性系统中增加"空轨"类型
- 空轨路径生成:
- 空轨走向固定,只需设置起点和终点
- 自动提取空轨几何体的下表面中心线作为路径
- 路径类型区分:路径需要标记为"地面路径"或"空轨路径"
- 动画运行模式:
- 地面路径:物体中心点在路径点上
- 空轨路径:物体悬挂在空轨下方运行(物体中心 = 路径点 - 物体高度/2)
- 碰撞检测:
- 统一使用3D碰撞检测
- 空轨路径需要排除空轨本身
- 限制条件:空轨暂时只支持人工路径,不支持自动路径规划
1.2 使用场景
- 地面路径:转运车在楼面、走廊、通道上运行
- 空轨路径:悬挂式输送设备在空轨上运行
1.3 已确认信息
- ✅ 空轨模型:已存在,不需要建模规范
- ✅ 空轨类型:不需要分类型,只有一个"空轨"类型
- ✅ 物体悬挂:物体悬挂在空轨下方
- ✅ 碰撞检测:需要排除空轨本身
- ✅ 数据库迁移:不需要,新字段使用默认值
- ✅ 向后兼容:不需要向后兼容性
- ✅ 碰撞检测统一:地面路径和空轨路径都使用3D碰撞检测
- ✅ 轨道几何:轨道不是水平的,需要精确计算几何体数据
二、架构影响分析
2.1 涉及的核心模块
| 模块 | 影响程度 | 改动内容 |
|---|---|---|
| 物流属性系统 | 🟢 低 | 新增"空轨"枚举值 |
| 路径数据模型 | 🟡 中 | 新增路径类型字段 |
| 路径规划系统 | 🟡 中 | 新增空轨路径生成逻辑 |
| 动画系统 | 🟡 中 | 根据路径类型调整物体位置 |
| 碰撞检测系统 | 🟢 低 | 空轨路径排除空轨本身 |
| UI界面 | 🟡 中 | 路径类型选择、空轨路径生成 |
三、详细实施方案
3.1 第一阶段:基础数据结构(1天)
3.1.1 新增空轨属性
文件:CategoryAttributeManager.cs
public enum LogisticsElementType
{
// ... 现有类型 ...
/// <summary>
/// 空轨 - 空中运输路径,物体悬挂运行,权重0.7
/// </summary>
空轨 = 9,
}
3.1.2 路径类型枚举
文件:PathPlanningModels.cs
/// <summary>
/// 路径类型
/// </summary>
public enum PathType
{
/// <summary>
/// 地面路径 - 物体在地面运行
/// </summary>
Ground = 0,
/// <summary>
/// 空轨路径 - 物体悬挂在空轨下方运行
/// </summary>
Rail = 1,
}
3.1.3 路径数据模型扩展
文件:PathRouteViewModel.cs
private PathType _pathType = PathType.Ground;
public PathType PathType
{
get => _pathType;
set => SetProperty(ref _pathType, value);
}
3.1.4 路径数据库适配
文件:PathDatabase.cs
// 保存路径时,保存路径类型
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(新建)
/// <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
/// <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)- 使用排除列表过滤
核心逻辑:
// 创建碰撞排除列表
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天)
- ✅ 新增"空轨"物流属性类型
- ✅ 新增路径类型枚举
- ✅ 扩展路径数据模型
- ✅ 适配数据库读写
第二阶段:空轨路径生成(2天)
- ✅ 在
ChannelHeightDetector中新增底部高度检测方法 - ✅ 复用现有的几何计算代码
- ✅ 实现
RailGeometryHelper(调用现有方法) - ✅ 扩展路径编辑器
- ✅ UI界面适配
- ✅ 集成测试
第三阶段:动画系统适配(1天)
- ✅ 物体位置计算适配
- ✅ 传递路径类型参数
- ✅ 动画播放测试
第四阶段:碰撞检测适配(1天)
- ✅ 实现空轨排除逻辑
- ✅ 统一使用3D碰撞检测
- ✅ 碰撞报告适配
- ✅ 集成测试
第五阶段:测试和优化(1天)
- ✅ 功能测试
- ✅ 性能测试
- ✅ 用户验收测试
总计:6天
五、风险评估
| 风险项 | 风险等级 | 缓解措施 |
|---|---|---|
| 空轨几何体提取失败 | 🟢 低 | 空轨模型已存在,直接使用 |
| 物体悬挂位置计算错误 | 🟡 中 | 充分测试,提供可视化验证 |
| 碰撞检测误报 | 🟡 中 | 排除空轨本身,调整检测参数 |
| 性能下降 | 🟢 低 | 空轨路径数量少,影响有限 |
| 几何计算性能 | 🟡 中 | 复用现有代码,优化采样策略 |
六、总结
6.1 方案优势
- ✅ 代码复用最大化:充分利用现有的几何计算代码
- ✅ 架构统一:空轨和地面路径使用相同的高度检测框架
- ✅ 改动最小化:只需新增底部检测方法,其他全部复用
- ✅ 易于维护:几何计算逻辑集中管理
- ✅ 向后兼容:不需要迁移,新字段使用默认值
- ✅ 碰撞检测统一:统一使用3D检测,简化逻辑
6.2 关键技术点
- 复用现有代码:
ChannelHeightDetector的几何计算方法 - 新增底部检测:
GetChannelBottomHeight()方法 - 物体悬挂计算:物体中心 = 空轨点 - 物体高度/2
- 碰撞检测统一:统一使用3D检测
- 排除空轨本身:通过排除列表过滤空轨模型
- 精确几何计算:支持倾斜、弯曲的轨道
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)- 传递路径类型和排除列表