完善寻路的高度处理,增加路径点的选取高亮,增加删除起点和终点的保护
This commit is contained in:
parent
97b9c2beca
commit
35226d2209
@ -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);
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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("已触发路径可视化更新");
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user