完善寻路的高度处理,增加路径点的选取高亮,增加删除起点和终点的保护

This commit is contained in:
tian 2025-09-16 10:36:22 +08:00
parent 97b9c2beca
commit 35226d2209
3 changed files with 129 additions and 111 deletions

View File

@ -61,7 +61,7 @@ namespace NavisworksTransport
private int _editingPointIndex = -1; // 正在修改的路径点索引
private PathPoint _originalPoint = null; // 修改前的原始路径点
private PathPoint _editingPreviewPoint = null; // 修改时的预览路径点
/// <summary>
/// ToolPlugin是否处于激活状态供InputMonitor使用
/// </summary>
@ -499,7 +499,7 @@ namespace NavisworksTransport
}
}
private void RaisePathPointsListUpdated(PathRoute route, string updateReason)
public void RaisePathPointsListUpdated(PathRoute route, string updateReason)
{
try
{
@ -561,7 +561,7 @@ namespace NavisworksTransport
RaiseErrorOccurred(ex.Message, ex);
}
}
/// <summary>
/// 清理无效的对象引用
/// </summary>
@ -570,10 +570,10 @@ namespace NavisworksTransport
try
{
LogManager.Info("[PathPlanningManager] 清理无效对象引用");
// 重置编辑状态
PathEditState = PathEditState.None;
// 清空当前路径
if (_currentRoute != null)
{
@ -842,7 +842,7 @@ namespace NavisworksTransport
try
{
// 使用2.5D通道检测模式
LogManager.Info("尝试使用ChannelBased2_5D模式生成网格");
LogManager.Info("使用BoundingBoxBased2_5D模式生成网格");
gridMap = gridMapGenerator.GenerateFromBIM(
document,
bounds,
@ -904,7 +904,8 @@ namespace NavisworksTransport
}
else
{
LogManager.Info("未找到通道数据,将使用传统边界框模式进行路径规划");
LogManager.Error("未找到通道数据,无法进行路径规划");
throw new Exception("路径规划需要通道数据,请先进行通道检测");
}
// 5. 执行A*路径查找
@ -917,28 +918,11 @@ namespace NavisworksTransport
try
{
pathFinder = new AutoPathFinder();
LogManager.Info("AutoPathFinder实例创建成功");
LogManager.Info("开始调用FindPath方法...");
// 🔥 关键修复传递ChannelCoverage数据和车辆高度
if (channelCoverage != null)
{
LogManager.Info($"使用2.5D模式进行路径查找,车辆高度: {vehicleHeight}m策略: {strategy}");
pathResult = pathFinder.FindPath(startPoint.Position, endPoint.Position, gridMap, channelCoverage, vehicleHeight, strategy);
}
else
{
LogManager.Info($"使用传统边界框模式进行路径查找,策略: {strategy}");
var legacyPathPoints = pathFinder.FindPath(startPoint.Position, endPoint.Position, gridMap);
pathResult = new PathFindingResult
{
PathPoints = legacyPathPoints,
IsComplete = true,
OriginalEndPoint = endPoint.Position,
ActualEndPoint = endPoint.Position,
CompletionPercentage = 100.0
};
}
double vehicleHeightInModelUnits = vehicleHeight * UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
LogManager.Info($"使用2.5D模式进行路径查找,车辆高度: {vehicleHeight}m ({vehicleHeightInModelUnits:F2}模型单位),策略: {strategy}");
pathResult = pathFinder.FindPath(startPoint.Position, endPoint.Position, gridMap, channelCoverage, vehicleHeightInModelUnits, strategy);
LogManager.Info("FindPath方法调用完成");
}
catch (Exception ex)
@ -1003,25 +987,8 @@ namespace NavisworksTransport
// 11. 触发事件
RaiseRouteGenerated(autoRoute, RouteGenerationMethod.AutoPlanning, gridSize);
// 12. 最终确保状态正确(防御性编程)
// 使用延迟执行确保在所有事件处理完成后状态仍然正确
if (_uiStateManager != null)
{
_uiStateManager.QueueUIUpdate(() =>
{
LogManager.Info("延迟确保自动路径规划完成后状态为Viewing");
if (PathEditState != PathEditState.Viewing)
{
LogManager.Warning($"检测到状态被意外修改为 {PathEditState}强制重置为Viewing");
PathEditState = PathEditState.Viewing;
EditingRoute = null;
}
}, UIUpdatePriority.Normal, forceSync: false);
}
var statusMessage = channelCoverage != null
? $"自动路径规划完成(2.5D模式): {routeName},使用网格大小 {gridSize:F2}米"
: $"自动路径规划完成(边界框模式): {routeName},使用网格大小 {gridSize:F2}米";
var statusMessage = $"自动路径规划完成(2.5D模式): {routeName},使用网格大小 {gridSize:F2}米";
// 添加完成度信息
if (!autoRoute.IsComplete)
@ -1138,7 +1105,7 @@ namespace NavisworksTransport
_walkableAreas.AddRange(channelItems);
LogManager.Info($"[SelectChannels] 通过CategoryAttributeManager直接筛选到 {channelItems.Count} 个通道");
}
RaiseStatusChanged($"通过类别筛选到 {_walkableAreas.Count} 个通道", PathPlanningStatusType.Success);
}
@ -2373,12 +2340,12 @@ namespace NavisworksTransport
// 4. 设置为活动工具
LogManager.WriteLog("[ToolPlugin] 步骤4: 设置为活动工具");
// 先重置工具状态,清除可能的导航工具
// 这一步很重要确保从导航工具如Pan、Orbit切换回自定义工具
Application.MainDocument.Tool.Value = Tool.None;
LogManager.WriteLog("[ToolPlugin] 已重置工具状态为None");
// 然后设置自定义工具插件
Application.MainDocument.Tool.SetCustomToolPlugin(loadedPlugin);
LogManager.WriteLog("[ToolPlugin] ✓ 工具设置成功");
@ -2417,7 +2384,7 @@ namespace NavisworksTransport
{
// 检查当前状态和实际工具值
if ((PathEditState == PathEditState.Creating ||
PathEditState == PathEditState.AddingPoints ||
PathEditState == PathEditState.AddingPoints ||
PathEditState == PathEditState.EditingPoint))
{
// 检查当前工具是否为自定义工具,如果不是则需要重新激活
@ -2425,10 +2392,10 @@ namespace NavisworksTransport
if (currentTool != Tool.CustomToolPlugin)
{
LogManager.WriteLog($"[ReactivateToolPlugin] 当前工具为{currentTool}开始重新激活ToolPlugin");
// 重要先将激活标志设置为false强制执行完整的激活流程
_isToolPluginActive = false;
// 调用现有的激活方法,但不重复订阅事件
if (ActivateToolPlugin(false))
{
@ -2731,19 +2698,19 @@ namespace NavisworksTransport
try
{
LogManager.WriteLog($"[工具插件重初始化] 开始强制重新初始化ToolPlugin订阅事件: {subscribeToEvents}");
// 1. 停用当前ToolPlugin
bool deactivated = DeactivateToolPlugin();
LogManager.WriteLog($"[工具插件重初始化] 停用结果: {deactivated}");
// 2. 强制重置激活状态
_isToolPluginActive = false;
LogManager.WriteLog("[工具插件重初始化] 已重置激活状态标志");
// 3. 重新激活ToolPlugin
bool activated = ActivateToolPlugin(subscribeToEvents);
LogManager.WriteLog($"[工具插件重初始化] 激活结果(事件订阅: {subscribeToEvents}: {activated}");
if (activated)
{
LogManager.WriteLog("[工具插件重初始化] ToolPlugin重新初始化成功已获得鼠标焦点");
@ -2752,7 +2719,7 @@ namespace NavisworksTransport
{
LogManager.WriteLog("[工具插件重初始化] ToolPlugin激活失败");
}
return activated;
}
catch (Exception ex)
@ -2867,7 +2834,7 @@ namespace NavisworksTransport
channelItems.AddRange(gridMap.ChannelItems);
return channelItems;
}
// 如果用户已选择通道,优先使用用户选择的通道
if (_walkableAreas != null && _walkableAreas.Count > 0)
{
@ -3170,15 +3137,15 @@ namespace NavisworksTransport
try
{
LogManager.Info($"[网格可视化设置] 更新设置: 通行={showWalkable}, 障碍物={showObstacle}, 未知={showUnknown}, 门={showDoor}");
_showWalkableGrid = showWalkable;
_showObstacleGrid = showObstacle;
_showUnknownGrid = showUnknown;
_showDoorGrid = showDoor;
// 如果当前有网格正在显示,重新应用可视化
RefreshGridVisualization();
LogManager.Info("[网格可视化设置] 设置更新完成");
}
catch (Exception ex)
@ -3266,17 +3233,17 @@ namespace NavisworksTransport
{
Id = "grid_visualization_channel"
};
var unknownRoute = new PathRoute("GridVisualization_Unknown")
{
Id = "grid_visualization_unknown"
};
var obstacleRoute = new PathRoute("GridVisualization_Obstacle")
{
Id = "grid_visualization_obstacle"
};
var doorRoute = new PathRoute("GridVisualization_Door")
{
Id = "grid_visualization_door"
@ -3296,7 +3263,7 @@ namespace NavisworksTransport
for (int y = 0; y < gridMap.Height; y++)
{
var cell = gridMap.Cells[x, y];
// 计算网格单元格的世界中心位置
var gridPos = new NavisworksTransport.PathPlanning.GridPoint2D(x, y);
var worldCenter = gridMap.GridToWorld3D(gridPos, cell.WorldPosition.Z);
@ -3304,7 +3271,7 @@ namespace NavisworksTransport
PathRoute targetRoute = null;
string gridTypeName = "";
// 根据网格类型和用户设置确定目标路径和名称
if (cell.IsWalkable && cell.CellType == CategoryAttributeManager.LogisticsElementType.)
{
@ -3351,7 +3318,7 @@ namespace NavisworksTransport
obstacleCells++;
}
}
// 如果有对应的路径,创建并添加网格点
if (targetRoute != null)
{
@ -3376,19 +3343,19 @@ namespace NavisworksTransport
renderPlugin.RenderPointOnly(channelRoute);
LogManager.Info($"[网格可视化] 渲染通道/开放空间网格点: {channelRoute.Points.Count} 个");
}
if (doorRoute.Points.Count > 0)
{
renderPlugin.RenderPointOnly(doorRoute);
LogManager.Info($"[网格可视化] 渲染门网格点: {doorRoute.Points.Count} 个50%透明绿色)");
}
if (unknownRoute.Points.Count > 0)
{
renderPlugin.RenderPointOnly(unknownRoute);
LogManager.Info($"[网格可视化] 渲染Unknown网格点: {unknownRoute.Points.Count} 个");
}
if (obstacleRoute.Points.Count > 0)
{
renderPlugin.RenderPointOnly(obstacleRoute);

View File

@ -48,19 +48,6 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
public class AutoPathFinder
{
/// <summary>
/// 查找路径(传统方法,保持向后兼容)
/// </summary>
/// <param name="start">起点(世界坐标)</param>
/// <param name="end">终点(世界坐标)</param>
/// <param name="gridMap">网格地图</param>
/// <returns>路径点列表(世界坐标)</returns>
public List<Point3D> FindPath(Point3D start, Point3D end, GridMap gridMap)
{
var result = FindPath(start, end, gridMap, null, 3.0);
return result?.PathPoints ?? new List<Point3D>();
}
/// <summary>
/// 查找路径(支持通道数据和高度约束)
/// </summary>
@ -68,7 +55,7 @@ namespace NavisworksTransport.PathPlanning
/// <param name="end">终点(世界坐标)</param>
/// <param name="gridMap">网格地图</param>
/// <param name="channelCoverage">通道覆盖数据可选用于2.5D路径规划)</param>
/// <param name="vehicleHeight">车辆高度(用于高度约束检查)</param>
/// <param name="vehicleHeight">车辆高度(模型单位,用于高度约束检查)</param>
/// <returns>路径查找结果</returns>
public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight)
{
@ -83,7 +70,7 @@ namespace NavisworksTransport.PathPlanning
/// <param name="end">终点(世界坐标)</param>
/// <param name="gridMap">网格地图</param>
/// <param name="channelCoverage">通道覆盖数据可选用于2.5D路径规划)</param>
/// <param name="vehicleHeight">车辆高度(用于高度约束检查)</param>
/// <param name="vehicleHeight">车辆高度(模型单位,用于高度约束检查)</param>
/// <param name="strategy">路径规划策略</param>
/// <returns>路径查找结果</returns>
public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, PathStrategy strategy)
@ -107,7 +94,7 @@ namespace NavisworksTransport.PathPlanning
/// <param name="end">终点(世界坐标)</param>
/// <param name="gridMap">网格地图</param>
/// <param name="channelCoverage">通道覆盖数据</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <param name="strategy">路径规划策略</param>
/// <returns>路径查找结果</returns>
private PathFindingResult FindPath2_5D(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, PathStrategy strategy = PathStrategy.Shortest)
@ -197,7 +184,7 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
/// <param name="gridMap">网格地图</param>
/// <param name="channelCoverage">通道覆盖数据</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <returns>A*算法网格</returns>
private Grid ConvertToAStarGridWith2_5D(GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight)
{
@ -258,9 +245,8 @@ namespace NavisworksTransport.PathPlanning
{
if (cell.PassableHeights != null && cell.PassableHeights.Any())
{
// 将车辆高度从米转换为模型单位
double vehicleHeightInModelUnits = vehicleHeight * UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
bool heightOk = cell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeightInModelUnits);
// vehicleHeight已经是模型单位直接比较即可
bool heightOk = cell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeight);
if (!heightOk)
{
heightConstrainedCells++;
@ -268,7 +254,7 @@ namespace NavisworksTransport.PathPlanning
// 详细日志记录被高度约束排除的单元格仅记录前10个避免日志过多
if (heightConstrainedCells <= 10)
{
LogManager.Info($"[A*高度约束] 单元格({x},{y})被高度约束排除:车辆高度{vehicleHeight}m({vehicleHeightInModelUnits:F2}模型单位),可用区间:{string.Join(", ", cell.PassableHeights.Select(i => $"{i.MinZ:F2}-{i.MaxZ:F2}({i.GetSpan():F2})"))}");
LogManager.Info($"[A*高度约束] 单元格({x},{y})被高度约束排除:车辆高度{vehicleHeight:F2}模型单位,可用区间:{string.Join(", ", cell.PassableHeights.Select(i => $"{i.MinZ:F2}-{i.MaxZ:F2}({i.GetSpan():F2})"))}");
}
else if (heightConstrainedCells == 11)
{
@ -297,7 +283,7 @@ namespace NavisworksTransport.PathPlanning
bool rightPassable = rightCell.IsWalkable;
if (rightPassable && rightCell.PassableHeights != null && rightCell.PassableHeights.Any())
{
rightPassable = rightCell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeightInModelUnits);
rightPassable = rightCell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeight);
}
if (rightPassable)
{
@ -314,7 +300,7 @@ namespace NavisworksTransport.PathPlanning
bool bottomPassable = bottomCell.IsWalkable;
if (bottomPassable && bottomCell.PassableHeights != null && bottomCell.PassableHeights.Any())
{
bottomPassable = bottomCell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeightInModelUnits);
bottomPassable = bottomCell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeight);
}
if (bottomPassable)
{
@ -348,7 +334,7 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
/// <param name="gridMap">网格地图</param>
/// <param name="channelCoverage">通道覆盖数据</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <param name="startPos">起点坐标</param>
/// <param name="endPos">终点坐标</param>
/// <param name="strategy">路径规划策略</param>
@ -381,7 +367,7 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
/// <param name="gridMap">网格地图</param>
/// <param name="channelCoverage">通道覆盖数据</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <param name="startPos">起点坐标</param>
/// <param name="endPos">终点坐标</param>
/// <returns>A*网格</returns>
@ -429,6 +415,7 @@ namespace NavisworksTransport.PathPlanning
bool isPassable = cell.IsWalkable;
if (isPassable && cell.PassableHeights != null && cell.PassableHeights.Any())
{
// vehicleHeight已经是模型单位直接比较即可
bool heightOk = cell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeight);
if (!heightOk)
{
@ -551,7 +538,7 @@ namespace NavisworksTransport.PathPlanning
/// 检查单元格是否满足高度约束
/// </summary>
/// <param name="cell">网格单元格</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <returns>是否可通行</returns>
private bool IsPassableWithHeight(GridCell cell, double vehicleHeight)
{
@ -560,6 +547,7 @@ namespace NavisworksTransport.PathPlanning
if (cell.PassableHeights != null && cell.PassableHeights.Any())
{
// vehicleHeight已经是模型单位直接比较即可
return cell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeight);
}
@ -572,7 +560,7 @@ namespace NavisworksTransport.PathPlanning
/// <param name="startPos">起始网格位置</param>
/// <param name="direction">方向 (1,0)=右, (0,1)=下, (-1,0)=左, (0,-1)=上</param>
/// <param name="gridMap">网格地图</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <returns>直线距离(网格单位)</returns>
private int CalculateStraightDistance(GridPoint2D startPos, GridPoint2D direction,
GridMap gridMap, double vehicleHeight)
@ -598,7 +586,7 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
/// <param name="pos">网格位置</param>
/// <param name="gridMap">网格地图</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <returns>是否有效且可通行</returns>
private bool IsValidAndPassable(GridPoint2D pos, GridMap gridMap, double vehicleHeight)
{
@ -1255,14 +1243,14 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
/// <param name="point">检查点</param>
/// <param name="gridMap">网格地图</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <returns>是否可通行</returns>
/// <summary>
/// 检查指定点在给定高度约束下是否可通行
/// </summary>
/// <param name="point">检查点</param>
/// <param name="gridMap">网格地图</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <returns>是否可通行</returns>
private bool IsPointPassableAtHeight(Point3D point, GridMap gridMap, double vehicleHeight)
{
@ -1332,7 +1320,7 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
/// <param name="path">原始路径</param>
/// <param name="gridMap">网格地图</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <returns>插值后的路径</returns>
private List<Point3D> InterpolatePathHeights2_5D(List<Point3D> path, GridMap gridMap, double vehicleHeight)
{
@ -1378,7 +1366,7 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
/// <param name="point">世界坐标点</param>
/// <param name="gridMap">网格地图</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
/// <returns>最优高度如果无法确定则返回null</returns>
private double? GetOptimalHeightFromGrid(Point3D point, GridMap gridMap, double vehicleHeight)
{
@ -1401,6 +1389,7 @@ namespace NavisworksTransport.PathPlanning
if (cell.PassableHeights != null && cell.PassableHeights.Any())
{
// 查找满足车辆高度要求的最佳区间
// vehicleHeight已经是模型单位直接比较即可
var validIntervals = cell.PassableHeights
.Where(interval => interval.GetSpan() >= vehicleHeight)
.OrderBy(interval => interval.MinZ)
@ -1529,7 +1518,7 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
/// <param name="path">路径点列表</param>
/// <param name="gridMap">网格地图</param>
/// <param name="vehicleHeight">车辆高度</param>
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
private void ValidatePathHeightConstraints(List<Point3D> path, GridMap gridMap, double vehicleHeight)
{
LogManager.Info($"[路径高度验证] 开始验证 {path.Count} 个路径点的高度约束");
@ -1729,6 +1718,7 @@ namespace NavisworksTransport.PathPlanning
bool isPassable = cell.IsWalkable;
if (isPassable && cell.PassableHeights != null && cell.PassableHeights.Any())
{
// vehicleHeight已经是模型单位直接比较即可
bool heightOk = cell.PassableHeights.Any(interval => interval.GetSpan() >= vehicleHeight);
if (!heightOk)
{

View File

@ -155,6 +155,37 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
// 更新修改路径点按钮的启用状态
OnPropertyChanged(nameof(CanExecuteModifyPoint));
// 路径点选中可视化:将选中的路径点显示为预览样式
try
{
if (value != null)
{
// 从PathPointViewModel创建PathPoint对象
var pathPoint = new PathPoint(
new Point3D(value.X, value.Y, value.Z),
value.Name,
value.Type
)
{
Id = value.Id
};
// 将选中的路径点设为预览样式
PathPointRenderPlugin.Instance.RenderPreviewPoint(pathPoint);
LogManager.Info($"路径点已设为预览样式: {value.Name}");
}
else
{
// 清除预览样式
PathPointRenderPlugin.Instance.ClearPreviewPoint();
LogManager.Info("已清除路径点预览样式");
}
}
catch (Exception ex)
{
LogManager.Error($"路径点选中可视化失败: {ex.Message}");
}
}
}
}
@ -1264,7 +1295,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels
return;
}
// 2. 在Core路径中查找对应的点通过位置和名称匹配
// 2. 路径完整性验证检查删除后是否至少还有2个点
if (coreRoute.Points.Count <= 2)
{
LogManager.Warning($"路径点不足,无法删除。当前路径只有{coreRoute.Points.Count}个点至少需要保留2个点起点和终点");
UpdateMainStatus($"❌ 无法删除路径点路径至少需要保留2个点起点和终点当前只有{coreRoute.Points.Count}个点");
return;
}
// 3. 在Core路径中查找对应的点通过位置和名称匹配
var corePoint = coreRoute.Points.FirstOrDefault(p =>
p.Name == point.Name &&
Math.Abs(p.Position.X - point.X) < 0.001 &&
@ -1279,27 +1318,49 @@ namespace NavisworksTransport.UI.WPF.ViewModels
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// 3. 同时删除UI和Core数据
SelectedPathRoute.Points.Remove(point);
LogManager.Info($"已从UI删除路径点: {point.Name}");
// 4. 起点和终点的特殊处理逻辑
if (corePoint != null)
{
int pointIndex = coreRoute.Points.IndexOf(corePoint);
if (corePoint.Type == PathPointType.StartPoint && coreRoute.Points.Count > 1)
{
// 删除起点:下一个点变为起点
var nextPoint = coreRoute.Points[pointIndex + 1];
nextPoint.Type = PathPointType.StartPoint;
LogManager.Info($"起点被删除,下一个路径点 {nextPoint.Name} 已设为新的起点");
}
else if (corePoint.Type == PathPointType.EndPoint && coreRoute.Points.Count > 1)
{
// 删除终点:上一个点变为终点
var prevPoint = coreRoute.Points[pointIndex - 1];
prevPoint.Type = PathPointType.EndPoint;
LogManager.Info($"终点被删除,上一个路径点 {prevPoint.Name} 已设为新的终点");
}
// 删除Core数据
coreRoute.Points.Remove(corePoint);
LogManager.Info($"已从Core数据删除路径点: {corePoint.Name}");
// 调用PathPlanningManager的3D删除方法
_pathPlanningManager.RemovePathPointFrom3D(corePoint);
// 触发UI同步更新事件
_pathPlanningManager.RaisePathPointsListUpdated(coreRoute, "删除路径点并重新分配类型");
LogManager.Info("已触发PathPointsListUpdated事件UI将自动同步");
}
// 4. 更新UI状态
UpdateMainStatus($"已删除路径点: {point.Name}");
// 5. 删除UI数据事件驱动会自动处理这里只作为备份
SelectedPathRoute.Points.Remove(point);
LogManager.Info($"已从UI删除路径点: {point.Name}");
// 6. 更新UI状态
UpdateMainStatus($"✅ 已删除路径点: {point.Name}");
LogManager.Info($"路径点删除完成当前UI点数: {SelectedPathRoute.Points.Count}, Core点数: {coreRoute?.Points.Count ?? 0}");
});
// 5. 刷新3D可视化显示
// 7. 刷新3D可视化显示路径变更会自动更新可视化
UpdatePathVisualization();
LogManager.Info("已触发路径可视化更新");