diff --git a/NavisworksTransportPlugin.csproj b/NavisworksTransportPlugin.csproj index 52aeef5..670764d 100644 --- a/NavisworksTransportPlugin.csproj +++ b/NavisworksTransportPlugin.csproj @@ -245,7 +245,7 @@ - + diff --git a/doc/design/2026/NavisworksAPI使用方法.md b/doc/design/2026/NavisworksAPI使用方法.md index 7790f3b..e5b6039 100644 --- a/doc/design/2026/NavisworksAPI使用方法.md +++ b/doc/design/2026/NavisworksAPI使用方法.md @@ -1309,7 +1309,7 @@ public class CustomPropertyManager **日志验证**: -``` +```text [FloorAttributeManager] 找到楼层属性分类,索引为: 0 [FloorAttributeManager] ✅ 成功更新现有楼层属性分类 (index=1) ``` diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs index 022a3ce..d289df0 100644 --- a/src/Core/PathPlanningManager.cs +++ b/src/Core/PathPlanningManager.cs @@ -582,16 +582,16 @@ namespace NavisworksTransport } /// - /// 清除3D路径标记 + /// 清除3D路径标记(保留网格可视化) /// public void Clear3DPathMarkers() { try { _pathPointMarkers?.Clear(); - // 通知渲染插件更新显示 - _renderPlugin?.ClearAllPaths(); - LogManager.Info("3D路径标记已清除"); + // 清除路径标记但保留网格可视化 + _renderPlugin?.ClearPathsExcept("grid_visualization_all"); + LogManager.Info("3D路径标记已清除(保留网格可视化)"); } catch (Exception ex) { @@ -854,6 +854,10 @@ namespace NavisworksTransport LogManager.Info($"网格地图生成完成: {gridMap.GetStatistics()}"); + // 可视化网格(调试用) + LogManager.Info("开始网格可视化,显示所有可通行网格单元"); + VisualizeGridCells(gridMap); + // 3. 获取通道数据用于精确高度计算 LogManager.Info("开始获取通道数据用于精确高度计算..."); var channelItems = GetChannelItemsForHeightCalculation(gridMap); @@ -3065,6 +3069,147 @@ namespace NavisworksTransport #endregion + #region 网格可视化方法 + + /// + /// 在3D视图中可视化网格中的可通行单元格 + /// 在每个可通行网格的中心绘制一个绿色小球 + /// + /// 要可视化的网格地图 + public void VisualizeGridCells(GridMap gridMap) + { + if (gridMap == null) + { + LogManager.Warning("[网格可视化] 网格地图为null,无法进行可视化"); + return; + } + + try + { + LogManager.Info($"[网格可视化] 开始可视化网格:{gridMap.Width}x{gridMap.Height}"); + + // 获取渲染插件 + var renderPlugin = PathPointRenderPlugin.Instance; + if (renderPlugin == null) + { + LogManager.Warning("[网格可视化] PathPointRenderPlugin实例为空,无法绘制网格"); + return; + } + + // 清除之前的网格可视化 + ClearGridVisualization(); + + // 创建单一的网格可视化路径 + var gridVisualizationRoute = new PathRoute("GridVisualization") + { + Id = "grid_visualization_all" + }; + + // 统计变量 + int walkableCells = 0; + int channelCells = 0; + int openSpaceCells = 0; + int visualizedCells = 0; + const int maxVisualizationPoints = 5000; // 限制最大可视化点数 + + // 遍历所有网格单元格,批量收集可通行网格点 + for (int x = 0; x < gridMap.Width && visualizedCells < maxVisualizationPoints; x++) + { + for (int y = 0; y < gridMap.Height && visualizedCells < maxVisualizationPoints; y++) + { + var cell = gridMap.Cells[x, y]; + + // 只处理可通行的单元格 + if (cell.IsWalkable) + { + walkableCells++; + + // 根据单元格类型分类统计 + if (cell.CellType == ElementType.Channel) + channelCells++; + else if (cell.CellType == ElementType.OpenSpace) + openSpaceCells++; + + // 计算网格单元格的世界中心位置 + var gridPos = new NavisworksTransport.PathPlanning.Point2D(x, y); + var worldCenter = gridMap.GridToWorld(gridPos); + + // 使用网格单元格中心的Z坐标,如果没有则使用网格边界的最大Z值 + double centerZ = cell.WorldPosition.Z != 0 ? cell.WorldPosition.Z : gridMap.Bounds.Max.Z; + var visualizationPoint = new Point3D(worldCenter.X, worldCenter.Y, centerZ); + + // 创建网格可视化点 + var gridPoint = new PathPoint + { + Position = visualizationPoint, + Name = $"网格({x},{y})", + Type = PathPointType.WayPoint, + Index = visualizedCells // 设置索引 + }; + + // 添加到统一的路径中 + gridVisualizationRoute.Points.Add(gridPoint); + visualizedCells++; + } + } + } + + // 批量渲染所有网格点 + if (gridVisualizationRoute.Points.Count > 0) + { + renderPlugin.RenderPointOnly(gridVisualizationRoute); + } + + // 输出统计信息 + LogManager.Info($"[网格可视化] 可视化完成:"); + LogManager.Info($" - 总网格单元格数:{gridMap.Width * gridMap.Height}"); + LogManager.Info($" - 可通行单元格数:{walkableCells}"); + LogManager.Info($" - 其中通道单元格:{channelCells}"); + LogManager.Info($" - 其中开放空间单元格:{openSpaceCells}"); + LogManager.Info($" - 已可视化单元格数:{visualizedCells}"); + if (visualizedCells >= maxVisualizationPoints) + { + LogManager.Info($" - 注意:可视化点数已达到上限 {maxVisualizationPoints}"); + } + + RaiseStatusChanged($"网格可视化完成:显示了 {visualizedCells} 个可通行网格单元", PathPlanningStatusType.Success); + } + catch (Exception ex) + { + LogManager.Error($"[网格可视化] 可视化失败: {ex.Message}"); + RaiseErrorOccurred($"网格可视化失败: {ex.Message}", ex); + } + } + + /// + /// 清除网格可视化 + /// + public void ClearGridVisualization() + { + try + { + LogManager.Info("[网格可视化] 开始清除网格可视化"); + + var renderPlugin = PathPointRenderPlugin.Instance; + if (renderPlugin != null) + { + // 只清除网格可视化路径 + renderPlugin.RemovePath("grid_visualization_all"); + LogManager.Info("[网格可视化] 网格可视化已清除"); + } + else + { + LogManager.Warning("[网格可视化] PathPointRenderPlugin实例为空,无法清除可视化"); + } + } + catch (Exception ex) + { + LogManager.Error($"[网格可视化] 清除可视化失败: {ex.Message}"); + } + } + + #endregion + #region 静态方法 /// diff --git a/src/Core/PathPointRenderPlugin.cs b/src/Core/PathPointRenderPlugin.cs index b84d38c..9121607 100644 --- a/src/Core/PathPointRenderPlugin.cs +++ b/src/Core/PathPointRenderPlugin.cs @@ -305,6 +305,9 @@ namespace NavisworksTransport try { + // 检查是否是网格可视化路径 + bool isGridVisualization = pathRoute.Id == "grid_visualization_all"; + var visualization = new PathVisualization { PathId = pathRoute.Id, @@ -319,7 +322,16 @@ namespace NavisworksTransport _pathVisualizations[pathRoute.Id] = visualization; } - LogManager.WriteLog($"[点标记渲染] 渲染点标记: {pathRoute.Name}, 点数: {pathRoute.Points.Count}"); + // 网格可视化只打印统计日志,不打印详细日志 + if (!isGridVisualization) + { + LogManager.WriteLog($"[点标记渲染] 渲染点标记: {pathRoute.Name}, 点数: {pathRoute.Points.Count}"); + } + else + { + LogManager.WriteLog($"[网格可视化] 渲染网格点: {pathRoute.Points.Count} 个可通行单元"); + } + RequestViewRefresh(); } catch (Exception ex) @@ -340,6 +352,9 @@ namespace NavisworksTransport var points = visualization.PathRoute.Points; if (points.Count == 0) return; + // 检查是否是网格可视化路径 + bool isGridVisualization = visualization.PathId == "grid_visualization_all"; + // 按索引排序点 var sortedPoints = points.OrderBy(p => p.Index).ToList(); @@ -351,7 +366,12 @@ namespace NavisworksTransport } visualization.LastUpdated = DateTime.Now; - LogManager.WriteLog($"[点标记构建] 已构建 {visualization.PointMarkers.Count} 个点标记,无连线"); + + // 网格可视化不打印详细构建日志,避免日志泛滥 + if (!isGridVisualization) + { + LogManager.WriteLog($"[点标记构建] 已构建 {visualization.PointMarkers.Count} 个点标记,无连线"); + } } /// @@ -401,6 +421,34 @@ namespace NavisworksTransport } } + /// + /// 清空路径,但保留指定的路径 + /// + /// 要保留的路径ID列表 + public void ClearPathsExcept(params string[] excludedPathIds) + { + lock (_lockObject) + { + var excludedSet = new HashSet(excludedPathIds); + var toRemove = _pathVisualizations.Keys.Where(id => !excludedSet.Contains(id)).ToList(); + + int removedCount = 0; + foreach (var pathId in toRemove) + { + if (_pathVisualizations.Remove(pathId)) + { + removedCount++; + } + } + + LogManager.WriteLog($"[选择性清空] 清空{removedCount}个路径,保留{excludedSet.Count}个路径"); + if (removedCount > 0) + { + RequestViewRefresh(); + } + } + } + /// /// 构建路径可视化 /// @@ -456,12 +504,15 @@ namespace NavisworksTransport /// 圆形标记 private CircleMarker CreatePointMarker(PathPoint point) { + // 检查是否是网格可视化点(通过名称判断) + bool isGridVisualization = point.Name.StartsWith("网格("); + return new CircleMarker { Center = point.Position, Normal = new Vector3D(0, 0, 1), - Radius = GetRadiusForPointType(point.Type), - Color = GetColorForPointType(point.Type), + Radius = isGridVisualization ? GetRadiusForGridVisualization() : GetRadiusForPointType(point.Type), + Color = isGridVisualization ? Color.Green : GetColorForPointType(point.Type), Alpha = 1.0, Filled = true, PointType = point.Type, @@ -470,6 +521,18 @@ namespace NavisworksTransport }; } + /// + /// 获取网格可视化小球的半径(比正常路径点小) + /// + /// 网格可视化半径 + private double GetRadiusForGridVisualization() + { + // 网格可视化小球使用0.2米的物理尺寸,比正常路径点小 + double baseRadiusInMeters = 0.2; + double metersToModelUnits = GetMetersToModelUnitsConversionFactor(); + return baseRadiusInMeters * metersToModelUnits; + } + /// /// 获取连线颜色(统一使用橙色) /// diff --git a/src/Core/Properties/CategoryAttributeManager.cs b/src/Core/Properties/CategoryAttributeManager.cs index cebd761..95d4359 100644 --- a/src/Core/Properties/CategoryAttributeManager.cs +++ b/src/Core/Properties/CategoryAttributeManager.cs @@ -281,6 +281,56 @@ namespace NavisworksTransport return string.Empty; } + /// + /// 获取指定类型的物流项目 + /// + /// 物流元素类型 + /// 文档,如果为null则使用ActiveDocument + /// 指定类型的物流项目列表 + public static List GetLogisticsItemsByType(LogisticsElementType elementType, Document document = null) + { + try + { + // 如果没有提供文档,使用ActiveDocument + if (document == null) + document = Application.ActiveDocument; + + // 检查文档有效性 + if (document?.Models == null) + { + LogManager.Warning($"[CategoryAttributeManager] 无法获取文档模型"); + return new List(); + } + + // 直接使用 Search API 搜索整个文档 + using (var search = new Search()) + { + // 搜索整个文档的根项及其所有后代 + search.Selection.SelectAll(); + search.Locations = SearchLocations.DescendantsAndSelf; + + var searchConditions = search.SearchConditions; + searchConditions.Clear(); + + // 搜索条件:必须有物流分类 + searchConditions.Add(SearchCondition.HasCategoryByDisplayName(LogisticsCategories.LOGISTICS)); + + // 搜索条件:类型属性等于指定值 + searchConditions.Add( + SearchCondition.HasPropertyByDisplayName(LogisticsCategories.LOGISTICS, LogisticsProperties.TYPE) + .EqualValue(VariantData.FromDisplayString(elementType.ToString()))); + + // 执行搜索并返回列表 + return search.FindAll(document, false).ToList(); + } + } + catch (Exception ex) + { + LogManager.Error($"[CategoryAttributeManager] 获取物流项目失败: {ex.Message}"); + return new List(); + } + } + /// /// 根据物流属性筛选模型项 /// diff --git a/src/PathPlanning/ChannelBasedGridBuilder.cs b/src/PathPlanning/ChannelBasedGridBuilder.cs index 6dec996..9efabce 100644 --- a/src/PathPlanning/ChannelBasedGridBuilder.cs +++ b/src/PathPlanning/ChannelBasedGridBuilder.cs @@ -18,9 +18,29 @@ namespace NavisworksTransport.PathPlanning /// public class ChannelBasedGridBuilder { - private CategoryAttributeManager _categoryManager; private ChannelHeightDetector _heightDetector; + /// + /// 通道几何类型 + /// + private enum ChannelGeometryType + { + /// + /// 水平通道(楼板) + /// + Horizontal, + + /// + /// 倾斜通道(楼梯、坡道) + /// + Inclined, + + /// + /// 复杂形状 + /// + Complex + } + /// /// 构造函数 /// @@ -44,8 +64,8 @@ namespace NavisworksTransport.PathPlanning LogManager.Info("[通道网格构建器] 开始构建通道覆盖网格"); // 1. 获取所有通道物品 - var allItems = document.Models.RootItemDescendantsAndSelf; - var channelItems = GetChannelItems(allItems.ToList()); + var channelItems = CategoryAttributeManager.GetLogisticsItemsByType( + CategoryAttributeManager.LogisticsElementType.通道, document); if (!channelItems.Any()) { @@ -87,177 +107,70 @@ namespace NavisworksTransport.PathPlanning }; } - /// - /// 获取所有通道物品 - /// - /// 所有模型物品 - /// 通道物品列表 - private List GetChannelItems(List allItems) - { - try - { - // 初始化CategoryAttributeManager(如果尚未初始化) - if (_categoryManager == null) - { - _categoryManager = new CategoryAttributeManager(); - } - - // 使用CategoryAttributeManager获取标记为"通道"的物品 - var document = Application.ActiveDocument; - if (document?.Models != null) - { - var allItemsCollection = new ModelItemCollection(); - foreach (ModelItem item in document.Models.RootItemDescendantsAndSelf) - { - allItemsCollection.Add(item); - } - var channelItems = CategoryAttributeManager.FilterByLogisticsType(allItemsCollection, CategoryAttributeManager.LogisticsElementType.通道).ToList(); - - if (channelItems.Any()) - { - LogManager.Info($"[通道网格构建器] 通过CategoryAttributeManager找到 {channelItems.Count} 个通道物品"); - return channelItems; - } - } - - // 如果没有用户标记的通道,直接返回空列表 - LogManager.Warning("[通道网格构建器] 未找到用户标记的通道物品,返回空列表"); - return new List(); - } - catch (Exception ex) - { - LogManager.Error($"[通道网格构建器] 获取通道物品时发生错误: {ex.Message}"); - return new List(); - } - } /// /// 将通道投影到网格 - /// 核心创新:智能投影策略 - 薄通道优先使用顶面提取,复杂通道使用射线扫描 + /// 统一投影方式:基于三角形几何的精确投影,解决楼板洞口和不规则形状问题 /// /// 通道物品 /// 目标网格地图 private void ProjectChannelToGrid(ModelItem channel, GridMap gridMap) { - var bbox = channel.BoundingBox(); - var thickness = bbox.Max.Z - bbox.Min.Z; + LogManager.Info($"[通道网格构建器] 投影通道: {channel.DisplayName}"); - LogManager.Info($"[通道网格构建器] 投影通道: {channel.DisplayName}, 厚度: {thickness:F2}m"); - - // 智能投影策略选择 - if (thickness < 1.5) // 薄通道优先使用顶面提取 - { - var triangles = GeometryExtractor.ExtractTrianglesOptimized(channel); - var topFaceCount = CountTopFaces(triangles); - var topFaceRatio = triangles.Count > 0 ? (double)topFaceCount / triangles.Count : 0; - - // 如果有足够的水平顶面(>10%),使用顶面投影 - if (topFaceRatio > 0.1) - { - ProjectUsingTopFaces(channel, gridMap, triangles); - LogManager.Info($"[通道网格构建器] 使用顶面提取投影(顶面比例: {topFaceRatio:P1})"); - return; - } - } - - // 对于复杂形状或没有明显顶面的通道,使用射线扫描 - ProjectUsingRayCasting(channel, gridMap); - LogManager.Info($"[通道网格构建器] 使用垂直射线扫描(精确投影)"); - } - - /// - /// 方法1:顶面提取投影(快速且精确) - /// - /// 模型物品 - /// 网格地图 - /// 三角形列表(可选,避免重复提取) - private void ProjectUsingTopFaces(ModelItem item, GridMap gridMap, List triangles = null) - { - if (triangles == null) - { - triangles = GeometryExtractor.ExtractTrianglesOptimized(item); - } - - int projectedTriangles = 0; - foreach (var triangle in triangles) - { - // 计算法向量 - var normal = ComputeTriangleNormal(triangle); - - // 只投影朝上的面(法向量Z分量 > 0.7,约45度) - if (normal.Z > 0.7) - { - // 光栅化三角形到网格 - RasterizeTriangleToGrid(gridMap, triangle); - projectedTriangles++; - } - } - - LogManager.Info($"[通道网格构建器] 顶面投影:{projectedTriangles}/{triangles.Count} 个三角形"); - } - - /// - /// 方法2:垂直射线扫描(最精确) - /// - /// 模型物品 - /// 网格地图 - private void ProjectUsingRayCasting(ModelItem item, GridMap gridMap) - { - var triangles = GeometryExtractor.ExtractTrianglesOptimized(item); + // 提取三角形几何 + var triangles = GeometryHelper.ExtractTrianglesOptimized(channel); if (triangles.Count == 0) { - LogManager.Warning($"[通道网格构建器] 未能从 '{item.DisplayName}' 提取到三角形"); + LogManager.Warning($"[通道网格构建器] 未能从 '{channel.DisplayName}' 提取到三角形"); return; } - - var bbox = item.BoundingBox(); - var minGrid = gridMap.WorldToGrid(new Point3D(bbox.Min.X, bbox.Min.Y, bbox.Min.Z)); - var maxGrid = gridMap.WorldToGrid(new Point3D(bbox.Max.X, bbox.Max.Y, bbox.Max.Z)); - - int hitCount = 0; - // 并行扫描网格点 - var gridPoints = new List(); - for (int x = minGrid.X; x <= maxGrid.X; x++) + // 分析通道类型 + var channelType = AnalyzeChannelType(triangles); + + // 统计三角形方向分布(用于调试) + int upFaces = 0, inclinedFaces = 0, downFaces = 0, sideFaces = 0; + foreach (var triangle in triangles) { - for (int y = minGrid.Y; y <= maxGrid.Y; y++) - { - if (gridMap.IsValidGridPosition(new Point2D(x, y))) - { - gridPoints.Add(new Point2D(x, y)); - } - } + var normal = ComputeTriangleNormal(triangle); + if (normal.Z > 0.7) + upFaces++; + else if (normal.Z > 0.2) + inclinedFaces++; + else if (normal.Z < -0.2) + downFaces++; + else + sideFaces++; } - - foreach (var gridPos in gridPoints) + + LogManager.Info($"[通道网格构建器] 通道类型: {channelType}"); + LogManager.Info($"[通道网格构建器] 三角形分布: 朝上={upFaces}, 朝上斜面={inclinedFaces}, 朝下={downFaces}, 侧面={sideFaces}, 总计={triangles.Count}"); + + // 统一投影处理 + int processedTriangles = 0; + foreach (var triangle in triangles) { - var worldPos = gridMap.GridToWorld(gridPos); - var rayOrigin = new Point3D(worldPos.X, worldPos.Y, bbox.Max.Z + 1); - var rayDirection = new Point3D(0, 0, -1); - - // 检查射线是否击中任何三角形 - foreach (var triangle in triangles) + var normal = ComputeTriangleNormal(triangle); + + // 根据法向量决定处理方式 + if (normal.Z > 0.7) // 朝上的水平面 { - if (GeometryExtractor.RayTriangleIntersect(rayOrigin, rayDirection, triangle, out double intersectionZ)) - { - if (intersectionZ >= bbox.Min.Z && intersectionZ <= bbox.Max.Z) - { - SetCellAsChannel(gridMap, gridPos, item); - hitCount++; - break; // 找到一个交点即可 - } - } + RasterizeTriangleToGrid(gridMap, triangle); + processedTriangles++; } + else if (normal.Z > 0.2) // 可行走的斜面(楼梯、坡道) + { + // 对于斜面,也进行投影,适用于楼梯等倾斜通道 + RasterizeTriangleToGrid(gridMap, triangle); + processedTriangles++; + } + // 垂直面和朝下的面不投影 } - - LogManager.Info($"[通道网格构建器] 射线投影:{hitCount} 个网格单元"); + + LogManager.Info($"[通道网格构建器] 投影完成:{processedTriangles}/{triangles.Count} 个三角形"); } - - - - - /// /// 计算三角形法向量 /// @@ -291,24 +204,6 @@ namespace NavisworksTransport.PathPlanning return normal; } - /// - /// 统计顶面数量 - /// - /// 三角形列表 - /// 顶面数量 - private int CountTopFaces(List triangles) - { - int count = 0; - foreach (var triangle in triangles) - { - var normal = ComputeTriangleNormal(triangle); - if (normal.Z > 0.7) // 朝上的面 - { - count++; - } - } - return count; - } /// /// 将三角形光栅化到网格 @@ -337,7 +232,7 @@ namespace NavisworksTransport.PathPlanning var worldPos = gridMap.GridToWorld(gridPos); // 检查点是否在三角形内部 - if (GeometryExtractor.IsPointInTriangle2D(worldPos, triangle)) + if (GeometryHelper.IsPointInTriangle2D(worldPos, triangle)) { SetCellAsChannel(gridMap, gridPos, null); } @@ -375,6 +270,50 @@ namespace NavisworksTransport.PathPlanning }; } + /// + /// 分析通道几何类型 + /// + /// 三角形列表 + /// 通道几何类型 + private ChannelGeometryType AnalyzeChannelType(List triangles) + { + if (triangles.Count == 0) + return ChannelGeometryType.Complex; + + int upwardHorizontalCount = 0; // 朝上的水平面 + int upwardInclinedCount = 0; // 朝上的斜面 + int upwardCount = 0; // 所有朝上的面 + + foreach (var triangle in triangles) + { + var normal = ComputeTriangleNormal(triangle); + + // 只统计朝上的面(与投影逻辑一致) + if (normal.Z > 0.7) + { + upwardHorizontalCount++; + upwardCount++; + } + else if (normal.Z > 0.2) // 朝上的斜面 + { + upwardInclinedCount++; + upwardCount++; + } + // 忽略朝下和侧面的三角形 + } + + // 基于朝上三角形的比例判断类型 + if (upwardCount == 0) + return ChannelGeometryType.Complex; + + if (upwardHorizontalCount > upwardCount * 0.6) + return ChannelGeometryType.Horizontal; // 主要是水平面 + else if (upwardInclinedCount > upwardCount * 0.3) + return ChannelGeometryType.Inclined; // 有较多斜面 + else + return ChannelGeometryType.Complex; + } + /// /// 格式化边界框信息用于日志 /// diff --git a/src/PathPlanning/ChannelHeightDetector.cs b/src/PathPlanning/ChannelHeightDetector.cs index bcc86df..54c9657 100644 --- a/src/PathPlanning/ChannelHeightDetector.cs +++ b/src/PathPlanning/ChannelHeightDetector.cs @@ -662,7 +662,7 @@ namespace NavisworksTransport.PathPlanning LogManager.Info($"[COM几何射线] 开始从ModelItem提取三角形几何数据: {channel.DisplayName}"); // 使用COM API提取三角形几何数据 - var triangles = GeometryExtractor.ExtractTrianglesOptimized(channel); + var triangles = GeometryHelper.ExtractTrianglesOptimized(channel); if (triangles.Count == 0) { LogManager.Warning($"[COM几何射线] 未能从ModelItem提取到三角形数据: {channel.DisplayName}"); @@ -714,7 +714,7 @@ namespace NavisworksTransport.PathPlanning int intersectionCount = 0; foreach (var triangle in triangles) { - if (GeometryExtractor.RayTriangleIntersect(rayOrigin, rayDirection, triangle, out double intersectionZ)) + if (GeometryHelper.RayTriangleIntersect(rayOrigin, rayDirection, triangle, out double intersectionZ)) { intersectionPoints.Add(intersectionZ); intersectionCount++; diff --git a/src/PathPlanning/GridMapGenerator.cs b/src/PathPlanning/GridMapGenerator.cs index 0aba662..2b4867e 100644 --- a/src/PathPlanning/GridMapGenerator.cs +++ b/src/PathPlanning/GridMapGenerator.cs @@ -238,25 +238,6 @@ namespace NavisworksTransport.PathPlanning double scanHeight = vehicleHeight + safetyMargin; // 扫描高度 = 车辆高度 + 安全间隙 ProcessObstaclesWithBoundingBox(document, channelCoverage.GridMap, channelRelatedItems, scanHeight); - // 步骤2.5: 将剩余的通道网格设置为可通行 - LogManager.Info("[包围盒2.5D模式] 步骤2.5: 设置通道网格为可通行"); - int walkableCount = 0; - for (int x = 0; x < channelCoverage.GridMap.Width; x++) - { - for (int y = 0; y < channelCoverage.GridMap.Height; y++) - { - var cell = channelCoverage.GridMap.Cells[x, y]; - if (cell.CellType == ElementType.Channel && cell.IsInChannel) - { - cell.IsWalkable = true; - cell.Cost = 1.0; - channelCoverage.GridMap.Cells[x, y] = cell; - walkableCount++; - } - } - } - LogManager.Info($"[包围盒2.5D模式] 设置了 {walkableCount} 个通道网格为可通行"); - LogManager.Info($"[阶段2完成] 障碍物处理后网格统计: {channelCoverage.GridMap.GetStatistics()}"); // 3. 应用车辆尺寸膨胀(如果需要) @@ -1222,13 +1203,7 @@ namespace NavisworksTransport.PathPlanning if (updatedCells > 0) { - Interlocked.Increment(ref obstacleItems); - - // 添加调试日志 - //LogManager.Info($"[包围盒障碍物处理] 障碍物 #{obstacleItems}: {item.DisplayName ?? "未命名"}, 类型:{item.ClassDisplayName}"); - //LogManager.Info($" 覆盖网格数: {updatedCells}"); - //LogManager.Info($" 包围盒: Min({bbox.Min.X:F2},{bbox.Min.Y:F2},{bbox.Min.Z:F2}) Max({bbox.Max.X:F2},{bbox.Max.Y:F2},{bbox.Max.Z:F2})"); - //LogManager.Info($" 包围盒尺寸: 宽{bbox.Max.X - bbox.Min.X:F2} x 长{bbox.Max.Y - bbox.Min.Y:F2} x 高{bbox.Max.Z - bbox.Min.Z:F2}"); + Interlocked.Increment(ref obstacleItems); } } catch (Exception ex) diff --git a/src/PathPlanning/VerticalScanProcessor.cs b/src/PathPlanning/VerticalScanProcessor.cs index b88c49d..b303b0c 100644 --- a/src/PathPlanning/VerticalScanProcessor.cs +++ b/src/PathPlanning/VerticalScanProcessor.cs @@ -847,7 +847,7 @@ namespace NavisworksTransport.PathPlanning return null; // 直接提取模型项的三角形几何数据 - var triangles = GeometryExtractor.ExtractTrianglesOptimized(item); + var triangles = GeometryHelper.ExtractTrianglesOptimized(item); if (triangles == null || triangles.Count == 0) { return null; @@ -909,7 +909,7 @@ namespace NavisworksTransport.PathPlanning foreach (var triangle in triangles) { - if (GeometryExtractor.RayTriangleIntersect(rayOrigin, rayDirection, triangle, out double intersectionZ)) + if (GeometryHelper.RayTriangleIntersect(rayOrigin, rayDirection, triangle, out double intersectionZ)) { // 检查相交点是否在扫描范围内 if (intersectionZ >= basePoint.Z && intersectionZ <= basePoint.Z + scanHeight) diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index d8d2d1b..9cb6551 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -152,9 +152,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels return; } - // 1. 清理所有现有的路径可视化 - PathPointRenderPlugin.Instance.ClearAllPaths(); - LogManager.WriteLog("[路径可视化] 已清理所有现有路径显示"); + // 1. 清理现有的路径可视化,但保留网格可视化 + PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all"); + LogManager.WriteLog("[路径可视化] 已清理现有路径显示(保留网格可视化)"); // 2. 如果有选中的路径,则显示该路径 if (_selectedPathRoute != null && _selectedPathRoute.Points.Count > 0) @@ -465,8 +465,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels { try { - PathPointRenderPlugin.Instance.ClearAllPaths(); - LogManager.Info("新建路径:已清除所有现有路径可视化显示"); + PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all"); + LogManager.Info("新建路径:已清除现有路径可视化显示(保留网格可视化)"); } catch (Exception ex) { @@ -733,8 +733,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels ClearTemporaryAutoPathMarkers(); if (PathPointRenderPlugin.Instance != null) { - PathPointRenderPlugin.Instance.ClearAllPaths(); // 清理所有可能的历史路径 - LogManager.WriteLog("[自动路径规划] 已清理所有历史路径对象"); + PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all"); // 清理历史路径但保留网格可视化 + LogManager.WriteLog("[自动路径规划] 已清理历史路径对象(保留网格可视化)"); } // 调用PathPlanningManager的自动路径规划功能 @@ -821,8 +821,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 确保失败后也清理所有可能的残留路径对象 if (PathPointRenderPlugin.Instance != null) { - PathPointRenderPlugin.Instance.ClearAllPaths(); - LogManager.WriteLog("[自动路径规划] 规划失败后已清理所有渲染对象"); + PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all"); + LogManager.WriteLog("[自动路径规划] 规划失败后已清理渲染对象(保留网格可视化)"); } } }, "自动路径规划"); @@ -847,9 +847,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels { try { - // 清除所有路径可视化,包括自动路径和手动路径 - PathPointRenderPlugin.Instance.ClearAllPaths(); - LogManager.Info("重置参数:已清除所有路径可视化显示"); + // 清除路径可视化,但保留网格可视化 + PathPointRenderPlugin.Instance.ClearPathsExcept("grid_visualization_all"); + LogManager.Info("重置参数:已清除路径可视化显示(保留网格可视化)"); } catch (Exception ex) { diff --git a/src/Utils/GeometryExtractor.cs b/src/Utils/GeometryHelper.cs similarity index 99% rename from src/Utils/GeometryExtractor.cs rename to src/Utils/GeometryHelper.cs index bbb6272..d40632f 100644 --- a/src/Utils/GeometryExtractor.cs +++ b/src/Utils/GeometryHelper.cs @@ -11,7 +11,7 @@ namespace NavisworksTransport /// /// 几何提取器 - 使用改进的算法和性能优化 /// - public class GeometryExtractor + public class GeometryHelper { /// /// 提取模型项的顶视图轮廓