diff --git a/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl b/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl index 2be3597..dbec33f 100644 Binary files a/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl and b/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl differ diff --git a/src/Core/PathPointRenderPlugin.cs b/src/Core/PathPointRenderPlugin.cs index 3f7bcd5..9710654 100644 --- a/src/Core/PathPointRenderPlugin.cs +++ b/src/Core/PathPointRenderPlugin.cs @@ -209,13 +209,11 @@ namespace NavisworksTransport graphics.Sphere(pointMarker.Center, pointMarker.Radius); } - // 渲染所有连线 - LogManager.WriteLog($"[渲染连线] 路径 {visualization.PathId} 有 {visualization.LineMarkers.Count} 条连线"); + // 渲染所有连线(删除频繁的调试日志以避免日志泛滥) foreach (var lineMarker in visualization.LineMarkers) { graphics.Color(lineMarker.Color, 1.0); graphics.Cylinder(lineMarker.StartPoint, lineMarker.EndPoint, lineMarker.Radius); - LogManager.WriteLog($"[渲染连线] 绘制连线 {lineMarker.FromIndex}->{lineMarker.ToIndex}, 半径={lineMarker.Radius:F3}"); } } } diff --git a/src/PathPlanning/GridMap.cs b/src/PathPlanning/GridMap.cs index cb172a8..7c82177 100644 --- a/src/PathPlanning/GridMap.cs +++ b/src/PathPlanning/GridMap.cs @@ -84,12 +84,10 @@ namespace NavisworksTransport.PathPlanning /// 网格单元格大小 public GridMap(BoundingBox3D bounds, double cellSize) { - if (bounds == null) - throw new ArgumentNullException(nameof(bounds)); if (cellSize <= 0) throw new ArgumentException("网格单元格大小必须大于0", nameof(cellSize)); - Bounds = bounds; + Bounds = bounds ?? throw new ArgumentNullException(nameof(bounds)); CellSize = cellSize; // 计算网格尺寸 diff --git a/src/PathPlanning/GridMapGenerator.cs b/src/PathPlanning/GridMapGenerator.cs index 1fbafa6..9725736 100644 --- a/src/PathPlanning/GridMapGenerator.cs +++ b/src/PathPlanning/GridMapGenerator.cs @@ -77,24 +77,34 @@ namespace NavisworksTransport.PathPlanning LogManager.Info($"调整后网格尺寸: {gridWidth}x{gridHeight} = {totalCells}个单元格"); } - // 步骤1:先进行楼层过滤,获取目标楼层的所有模型项 - LogManager.Info("[步骤1] 开始楼层过滤..."); - var floorFilteredItems = GetFloorFilteredModelItems(document, planningStartPoint, planningEndPoint); - LogManager.Info($"[步骤1] 楼层过滤完成,共 {floorFilteredItems.Count} 个模型项"); + // 步骤1: 获取所有模型项(暂时注释楼层过滤功能) + LogManager.Info("[步骤1] 获取所有模型项(楼层过滤已暂时禁用)..."); + var allModelItems = new List(); + foreach (var model in document.Models) + { + if (model.RootItem != null) + { + CollectAllItemsRecursively(model.RootItem, allModelItems); + } + } + LogManager.Info($"[步骤1] 获取到 {allModelItems.Count} 个模型项"); - // 步骤2:基于楼层过滤结果重新计算工作区域边界 + // TODO: 楼层过滤功能已暂时注释,需要时可重新启用 + // var floorFilteredItems = GetFloorFilteredModelItems(document, planningStartPoint, planningEndPoint); + var modelItems = allModelItems; // 直接使用所有模型项,不进行楼层过滤 + + // 步骤2: 基于工作区域重新计算边界(使用所有模型项) LogManager.Info("[步骤2] 重新计算路径规划工作区域..."); - var workingBounds = CalculateWorkingBounds(floorFilteredItems, bounds, planningStartPoint, planningEndPoint); + var workingBounds = CalculateWorkingBounds(modelItems, bounds, planningStartPoint, planningEndPoint); LogManager.Info($"[步骤2] 工作区域边界: {workingBounds}"); - // 步骤3:基于工作区域创建网格地图 + // 步骤3: 基于工作区域创建网格地图 LogManager.Info("[步骤3] 创建网格地图..."); var gridMap = new GridMap(workingBounds, cellSizeInModelUnits); LogManager.Info($"[步骤3] 创建网格地图: {gridMap.Width}x{gridMap.Height} = {gridMap.Width * gridMap.Height}个单元格"); - // 步骤4:只使用楼层过滤后的模型项(所有项目都已经在楼层内) - var modelItems = floorFilteredItems; - LogManager.Info($"[步骤4] 使用楼层过滤后的 {modelItems.Count} 个模型项进行网格化"); + // 步骤4: 使用所有模型项进行网格化(楼层过滤已禁用) + LogManager.Info($"[步骤4] 使用 {modelItems.Count} 个模型项进行网格化(楼层过滤已禁用)"); // 识别障碍物 LogManager.Info("开始识别障碍物..."); @@ -283,11 +293,29 @@ namespace NavisworksTransport.PathPlanning { try { + // 1. 检查当前项是否有物流属性 + bool hasLogisticsProperty = HasLogisticsProperty(item); + + if (hasLogisticsProperty) + { + // 如果当前项有物流属性,将其作为一个整体处理 + if (item.HasGeometry) + { + result.Add(item); + LogManager.WriteLog($"[组合模型过滤] 发现有物流属性的模型: {item.DisplayName},作为整体处理,跳过其子项"); + } + // 重要:不再递归处理其子项,避免父子属性冲突 + // 这样通道的子模型就不会被单独判断为障碍了 + return; + } + + // 2. 如果当前项没有物流属性,检查其几何体 if (item.HasGeometry) { result.Add(item); } + // 3. 递归处理子项(只有在父项没有物流属性时才递归) foreach (var child in item.Children) { CollectAllItemsRecursively(child, result); diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index 3b88599..4881794 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -53,6 +53,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels private double _vehicleHeight = 2.0; // 车辆高度(米) private double _safetyMargin = 0.5; // 安全间隙(米) + // 网格大小参数 + private bool _isGridSizeManuallyEnabled = false; // 是否启用手动网格大小设置 + private double _gridSize = 1.0; // 网格大小(米) + // 路径文件管理 private string _pathFileStatus = "未保存"; @@ -156,6 +160,30 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + public bool IsGridSizeManuallyEnabled + { + get => _isGridSizeManuallyEnabled; + set + { + if (SetProperty(ref _isGridSizeManuallyEnabled, value)) + { + OnPropertyChanged(nameof(CanExecuteAutoPlanPath)); + } + } + } + + public double GridSize + { + get => _gridSize; + set + { + if (SetProperty(ref _gridSize, value)) + { + OnPropertyChanged(nameof(CanExecuteAutoPlanPath)); + } + } + } + public bool IsSelectingStartPoint { get => _isSelectingStartPoint; @@ -559,6 +587,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels _pathPlanningManager.StopClickTool(); } + // 清理所有临时路径,确保干净的起始状态 + LogManager.WriteLog("[自动路径规划] 清理所有临时路径和历史渲染对象"); + ClearTemporaryAutoPathMarkers(); + if (PathPointRenderPlugin.Instance != null) + { + PathPointRenderPlugin.Instance.ClearAllPaths(); // 清理所有可能的历史路径 + LogManager.WriteLog("[自动路径规划] 已清理所有历史路径对象"); + } + // 调用PathPlanningManager的自动路径规划功能 var startPathPoint = new PathPoint { @@ -576,11 +613,19 @@ namespace NavisworksTransport.UI.WPF.ViewModels LogManager.Info($"起点: ({_startPoint3D.X:F2}, {_startPoint3D.Y:F2}, {_startPoint3D.Z:F2})"); LogManager.Info($"终点: ({_endPoint3D.X:F2}, {_endPoint3D.Y:F2}, {_endPoint3D.Z:F2})"); - // 使用三个车辆尺寸参数的最大值作为vehicleSize,以及安全间隙 - var vehicleSize = Math.Max(Math.Max(VehicleLength, VehicleWidth), VehicleHeight); + // 计算车辆半径:基于长度和宽度的较大值的一半,高度暂时不参与半径计算 + var vehicleRadius = Math.Max(VehicleLength, VehicleWidth) / 2.0; + + LogManager.Info($"车辆参数: 长{VehicleLength:F1}m × 宽{VehicleWidth:F1}m × 高{VehicleHeight:F1}m"); + LogManager.Info($"计算得出车辆半径: {vehicleRadius:F2}m (基于长宽较大值的一半)"); + + // 确定网格大小:如果启用手动设置则使用用户设置的值,否则使用-1(自动选择) + var gridSize = IsGridSizeManuallyEnabled ? GridSize : -1; + + LogManager.Info($"网格大小设置: {(IsGridSizeManuallyEnabled ? $"手动设置 {GridSize:F1}米" : "自动选择")}"); // 在STA线程中执行Navisworks API调用 - var pathRoute = await _pathPlanningManager?.AutoPlanPath(startPathPoint, endPathPoint, vehicleSize, SafetyMargin); + var pathRoute = await _pathPlanningManager?.AutoPlanPath(startPathPoint, endPathPoint, vehicleRadius, SafetyMargin, gridSize); if (pathRoute != null && pathRoute.Points.Count > 0) { @@ -619,6 +664,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels } // 失败情况下也要清理事件订阅和临时标记 + LogManager.WriteLog("[自动路径规划] 规划失败后清理所有状态"); CleanupAutoPathEventSubscriptions(); if (_pathPlanningManager != null) { @@ -627,6 +673,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 清理临时的起点和终点标记 ClearTemporaryAutoPathMarkers(); + + // 确保失败后也清理所有可能的残留路径对象 + if (PathPointRenderPlugin.Instance != null) + { + PathPointRenderPlugin.Instance.ClearAllPaths(); + LogManager.WriteLog("[自动路径规划] 规划失败后已清理所有渲染对象"); + } } }, "自动路径规划"); } diff --git a/src/UI/WPF/Views/PathEditingView.xaml b/src/UI/WPF/Views/PathEditingView.xaml index 2ea4cd4..fb6dbec 100644 --- a/src/UI/WPF/Views/PathEditingView.xaml +++ b/src/UI/WPF/Views/PathEditingView.xaml @@ -26,6 +26,12 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管 + + + @@ -112,6 +118,58 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管