From 35226d22093dacba013e7df98bced58a0439f37a Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Tue, 16 Sep 2025 10:36:22 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=AF=BB=E8=B7=AF=E7=9A=84?=
=?UTF-8?q?=E9=AB=98=E5=BA=A6=E5=A4=84=E7=90=86=EF=BC=8C=E5=A2=9E=E5=8A=A0?=
=?UTF-8?q?=E8=B7=AF=E5=BE=84=E7=82=B9=E7=9A=84=E9=80=89=E5=8F=96=E9=AB=98?=
=?UTF-8?q?=E4=BA=AE=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=88=A0=E9=99=A4=E8=B5=B7?=
=?UTF-8?q?=E7=82=B9=E5=92=8C=E7=BB=88=E7=82=B9=E7=9A=84=E4=BF=9D=E6=8A=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Core/PathPlanningManager.cs | 107 ++++++------------
src/PathPlanning/AutoPathFinder.cs | 56 ++++-----
src/UI/WPF/ViewModels/PathEditingViewModel.cs | 77 +++++++++++--
3 files changed, 129 insertions(+), 111 deletions(-)
diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs
index b4e090e..7b95aee 100644
--- a/src/Core/PathPlanningManager.cs
+++ b/src/Core/PathPlanningManager.cs
@@ -61,7 +61,7 @@ namespace NavisworksTransport
private int _editingPointIndex = -1; // 正在修改的路径点索引
private PathPoint _originalPoint = null; // 修改前的原始路径点
private PathPoint _editingPreviewPoint = null; // 修改时的预览路径点
-
+
///
/// ToolPlugin是否处于激活状态(供InputMonitor使用)
///
@@ -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);
}
}
-
+
///
/// 清理无效的对象引用
///
@@ -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);
diff --git a/src/PathPlanning/AutoPathFinder.cs b/src/PathPlanning/AutoPathFinder.cs
index e3e878b..56503e7 100644
--- a/src/PathPlanning/AutoPathFinder.cs
+++ b/src/PathPlanning/AutoPathFinder.cs
@@ -48,19 +48,6 @@ namespace NavisworksTransport.PathPlanning
///
public class AutoPathFinder
{
- ///
- /// 查找路径(传统方法,保持向后兼容)
- ///
- /// 起点(世界坐标)
- /// 终点(世界坐标)
- /// 网格地图
- /// 路径点列表(世界坐标)
- public List FindPath(Point3D start, Point3D end, GridMap gridMap)
- {
- var result = FindPath(start, end, gridMap, null, 3.0);
- return result?.PathPoints ?? new List();
- }
-
///
/// 查找路径(支持通道数据和高度约束)
///
@@ -68,7 +55,7 @@ namespace NavisworksTransport.PathPlanning
/// 终点(世界坐标)
/// 网格地图
/// 通道覆盖数据(可选,用于2.5D路径规划)
- /// 车辆高度(用于高度约束检查)
+ /// 车辆高度(模型单位,用于高度约束检查)
/// 路径查找结果
public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight)
{
@@ -83,7 +70,7 @@ namespace NavisworksTransport.PathPlanning
/// 终点(世界坐标)
/// 网格地图
/// 通道覆盖数据(可选,用于2.5D路径规划)
- /// 车辆高度(用于高度约束检查)
+ /// 车辆高度(模型单位,用于高度约束检查)
/// 路径规划策略
/// 路径查找结果
public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, PathStrategy strategy)
@@ -107,7 +94,7 @@ namespace NavisworksTransport.PathPlanning
/// 终点(世界坐标)
/// 网格地图
/// 通道覆盖数据
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 路径规划策略
/// 路径查找结果
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
///
/// 网格地图
/// 通道覆盖数据
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// A*算法网格
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
///
/// 网格地图
/// 通道覆盖数据
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 起点坐标
/// 终点坐标
/// 路径规划策略
@@ -381,7 +367,7 @@ namespace NavisworksTransport.PathPlanning
///
/// 网格地图
/// 通道覆盖数据
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 起点坐标
/// 终点坐标
/// A*网格
@@ -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
/// 检查单元格是否满足高度约束
///
/// 网格单元格
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 是否可通行
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
/// 起始网格位置
/// 方向 (1,0)=右, (0,1)=下, (-1,0)=左, (0,-1)=上
/// 网格地图
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 直线距离(网格单位)
private int CalculateStraightDistance(GridPoint2D startPos, GridPoint2D direction,
GridMap gridMap, double vehicleHeight)
@@ -598,7 +586,7 @@ namespace NavisworksTransport.PathPlanning
///
/// 网格位置
/// 网格地图
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 是否有效且可通行
private bool IsValidAndPassable(GridPoint2D pos, GridMap gridMap, double vehicleHeight)
{
@@ -1255,14 +1243,14 @@ namespace NavisworksTransport.PathPlanning
///
/// 检查点
/// 网格地图
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 是否可通行
///
/// 检查指定点在给定高度约束下是否可通行
///
/// 检查点
/// 网格地图
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 是否可通行
private bool IsPointPassableAtHeight(Point3D point, GridMap gridMap, double vehicleHeight)
{
@@ -1332,7 +1320,7 @@ namespace NavisworksTransport.PathPlanning
///
/// 原始路径
/// 网格地图
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 插值后的路径
private List InterpolatePathHeights2_5D(List path, GridMap gridMap, double vehicleHeight)
{
@@ -1378,7 +1366,7 @@ namespace NavisworksTransport.PathPlanning
///
/// 世界坐标点
/// 网格地图
- /// 车辆高度
+ /// 车辆高度(模型单位)
/// 最优高度,如果无法确定则返回null
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
///
/// 路径点列表
/// 网格地图
- /// 车辆高度
+ /// 车辆高度(模型单位)
private void ValidatePathHeightConstraints(List 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)
{
diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
index 04b383e..feda929 100644
--- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs
+++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
@@ -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("已触发路径可视化更新");