通道网格用几何三角形精确计算,增加通行网格可视化

This commit is contained in:
tian 2025-09-06 16:26:39 +08:00
parent 2955bfd38b
commit e73cd2113e
11 changed files with 396 additions and 224 deletions

View File

@ -245,7 +245,7 @@
<Compile Include="src\Utils\CoordinateConverter.cs" />
<Compile Include="src\Utils\FloorDetector.cs" />
<Compile Include="src\Utils\ModelItemAnalysisHelper.cs" />
<Compile Include="src\Utils\GeometryExtractor.cs" />
<Compile Include="src\Utils\GeometryHelper.cs" />
<Compile Include="src\Utils\LogManager.cs" />
<Compile Include="src\Utils\NavisworksApiHelper.cs" />
<Compile Include="src\Utils\NavisworksSelectionHelper.cs" />

View File

@ -1309,7 +1309,7 @@ public class CustomPropertyManager
**日志验证**
```
```text
[FloorAttributeManager] 找到楼层属性分类,索引为: 0
[FloorAttributeManager] ✅ 成功更新现有楼层属性分类 (index=1)
```

View File

@ -582,16 +582,16 @@ namespace NavisworksTransport
}
/// <summary>
/// 清除3D路径标记
/// 清除3D路径标记(保留网格可视化)
/// </summary>
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
/// <summary>
/// 在3D视图中可视化网格中的可通行单元格
/// 在每个可通行网格的中心绘制一个绿色小球
/// </summary>
/// <param name="gridMap">要可视化的网格地图</param>
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);
}
}
/// <summary>
/// 清除网格可视化
/// </summary>
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
/// <summary>

View File

@ -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} 个点标记,无连线");
}
}
/// <summary>
@ -401,6 +421,34 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 清空路径,但保留指定的路径
/// </summary>
/// <param name="excludedPathIds">要保留的路径ID列表</param>
public void ClearPathsExcept(params string[] excludedPathIds)
{
lock (_lockObject)
{
var excludedSet = new HashSet<string>(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();
}
}
}
/// <summary>
/// 构建路径可视化
/// </summary>
@ -456,12 +504,15 @@ namespace NavisworksTransport
/// <returns>圆形标记</returns>
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
};
}
/// <summary>
/// 获取网格可视化小球的半径(比正常路径点小)
/// </summary>
/// <returns>网格可视化半径</returns>
private double GetRadiusForGridVisualization()
{
// 网格可视化小球使用0.2米的物理尺寸,比正常路径点小
double baseRadiusInMeters = 0.2;
double metersToModelUnits = GetMetersToModelUnitsConversionFactor();
return baseRadiusInMeters * metersToModelUnits;
}
/// <summary>
/// 获取连线颜色(统一使用橙色)
/// </summary>

View File

@ -281,6 +281,56 @@ namespace NavisworksTransport
return string.Empty;
}
/// <summary>
/// 获取指定类型的物流项目
/// </summary>
/// <param name="elementType">物流元素类型</param>
/// <param name="document">文档如果为null则使用ActiveDocument</param>
/// <returns>指定类型的物流项目列表</returns>
public static List<ModelItem> GetLogisticsItemsByType(LogisticsElementType elementType, Document document = null)
{
try
{
// 如果没有提供文档使用ActiveDocument
if (document == null)
document = Application.ActiveDocument;
// 检查文档有效性
if (document?.Models == null)
{
LogManager.Warning($"[CategoryAttributeManager] 无法获取文档模型");
return new List<ModelItem>();
}
// 直接使用 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<ModelItem>();
}
}
/// <summary>
/// 根据物流属性筛选模型项
/// </summary>

View File

@ -18,9 +18,29 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
public class ChannelBasedGridBuilder
{
private CategoryAttributeManager _categoryManager;
private ChannelHeightDetector _heightDetector;
/// <summary>
/// 通道几何类型
/// </summary>
private enum ChannelGeometryType
{
/// <summary>
/// 水平通道(楼板)
/// </summary>
Horizontal,
/// <summary>
/// 倾斜通道(楼梯、坡道)
/// </summary>
Inclined,
/// <summary>
/// 复杂形状
/// </summary>
Complex
}
/// <summary>
/// 构造函数
/// </summary>
@ -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
};
}
/// <summary>
/// 获取所有通道物品
/// </summary>
/// <param name="allItems">所有模型物品</param>
/// <returns>通道物品列表</returns>
private List<ModelItem> GetChannelItems(List<ModelItem> 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<ModelItem>();
}
catch (Exception ex)
{
LogManager.Error($"[通道网格构建器] 获取通道物品时发生错误: {ex.Message}");
return new List<ModelItem>();
}
}
/// <summary>
/// 将通道投影到网格
/// 核心创新:智能投影策略 - 薄通道优先使用顶面提取,复杂通道使用射线扫描
/// 统一投影方式:基于三角形几何的精确投影,解决楼板洞口和不规则形状问题
/// </summary>
/// <param name="channel">通道物品</param>
/// <param name="gridMap">目标网格地图</param>
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($"[通道网格构建器] 使用垂直射线扫描(精确投影)");
}
/// <summary>
/// 方法1顶面提取投影快速且精确
/// </summary>
/// <param name="item">模型物品</param>
/// <param name="gridMap">网格地图</param>
/// <param name="triangles">三角形列表(可选,避免重复提取)</param>
private void ProjectUsingTopFaces(ModelItem item, GridMap gridMap, List<Triangle3D> 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} 个三角形");
}
/// <summary>
/// 方法2垂直射线扫描最精确
/// </summary>
/// <param name="item">模型物品</param>
/// <param name="gridMap">网格地图</param>
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<Point2D>();
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} 个三角形");
}
/// <summary>
/// 计算三角形法向量
/// </summary>
@ -291,24 +204,6 @@ namespace NavisworksTransport.PathPlanning
return normal;
}
/// <summary>
/// 统计顶面数量
/// </summary>
/// <param name="triangles">三角形列表</param>
/// <returns>顶面数量</returns>
private int CountTopFaces(List<Triangle3D> triangles)
{
int count = 0;
foreach (var triangle in triangles)
{
var normal = ComputeTriangleNormal(triangle);
if (normal.Z > 0.7) // 朝上的面
{
count++;
}
}
return count;
}
/// <summary>
/// 将三角形光栅化到网格
@ -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
};
}
/// <summary>
/// 分析通道几何类型
/// </summary>
/// <param name="triangles">三角形列表</param>
/// <returns>通道几何类型</returns>
private ChannelGeometryType AnalyzeChannelType(List<Triangle3D> 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;
}
/// <summary>
/// 格式化边界框信息用于日志
/// </summary>

View File

@ -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++;

View File

@ -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)

View File

@ -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)

View File

@ -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)
{

View File

@ -11,7 +11,7 @@ namespace NavisworksTransport
/// <summary>
/// 几何提取器 - 使用改进的算法和性能优化
/// </summary>
public class GeometryExtractor
public class GeometryHelper
{
/// <summary>
/// 提取模型项的顶视图轮廓