From a938afd94630e6606aa86199e25cfdd1d9278e97 Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Sat, 11 Oct 2025 17:36:33 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E9=BD=90=E9=85=8D=E7=BD=AE=E5=8F=82?=
=?UTF-8?q?=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
NavisworksTransportPlugin.csproj | 1 -
TestConfigManager.cs | 56 -
config.toml.example | 85 +-
src/Commands/SetLogisticsAttributeCommand.cs | 4 +-
src/Core/Animation/PathAnimationManager.cs | 4 +-
.../Collision/ClashDetectiveIntegration.cs | 3 -
src/Core/Config/ConfigManager.cs | 156 +--
src/Core/Config/SystemConfig.cs | 159 +--
src/Core/PathPointRenderPlugin.cs | 73 +-
.../Properties/CategoryAttributeManager.cs | 37 +-
src/PathPlanning/AutoPathFinder.cs | 15 +-
src/PathPlanning/GridMapGenerator.cs | 18 +-
src/PathPlanning/VerticalScanProcessor.cs | 1059 -----------------
.../ViewModels/AnimationControlViewModel.cs | 21 +-
src/UI/WPF/ViewModels/PathEditingViewModel.cs | 77 +-
src/UI/WPF/Views/LogisticsControlPanel.xaml | 2 +-
.../WPF/Views/LogisticsControlPanel.xaml.cs | 25 +-
src/UI/WPF/Views/PathEditingView.xaml.cs | 13 +-
src/Utils/CoordinateConverter.cs | 38 +-
src/Utils/FloorDetector.cs | 25 +-
20 files changed, 302 insertions(+), 1569 deletions(-)
delete mode 100644 TestConfigManager.cs
delete mode 100644 src/PathPlanning/VerticalScanProcessor.cs
diff --git a/NavisworksTransportPlugin.csproj b/NavisworksTransportPlugin.csproj
index 2dbc9e5..d3807ca 100644
--- a/NavisworksTransportPlugin.csproj
+++ b/NavisworksTransportPlugin.csproj
@@ -180,7 +180,6 @@
-
diff --git a/TestConfigManager.cs b/TestConfigManager.cs
deleted file mode 100644
index ea7645a..0000000
--- a/TestConfigManager.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System;
-using NavisworksTransport.Core.Config;
-
-namespace NavisworksTransport.Tests
-{
- ///
- /// 配置管理器测试程序
- /// 使用方法:在 MainPlugin 的 Execute 方法中临时调用 TestConfigManager.RunTests()
- ///
- public class TestConfigManager
- {
- public static void RunTests()
- {
- Console.WriteLine("=== 开始测试配置管理器 ===");
- Console.WriteLine();
-
- // 测试 1:加载或创建默认配置
- Console.WriteLine("测试 1: 加载或创建默认配置");
- var config = ConfigManager.Instance.Current;
- Console.WriteLine($"配置文件路径: {ConfigManager.ConfigFilePath}");
- Console.WriteLine($"网格尺寸: {config.GridGeneration.CellSizeMeters} 米");
- Console.WriteLine($"车辆半径: {config.GridGeneration.VehicleRadiusMeters} 米");
- Console.WriteLine($"路径策略: {config.PathPlanning.DefaultPathStrategy}");
- Console.WriteLine();
-
- // 测试 2:修改配置并保存
- Console.WriteLine("测试 2: 修改配置并保存");
- config.GridGeneration.CellSizeMeters = 0.6;
- config.PathPlanning.DefaultPathStrategy = "SafetyFirst";
- config.Visualization.EnableGridVisualization = true;
- ConfigManager.Instance.SaveConfig(config);
- Console.WriteLine("配置已保存");
- Console.WriteLine();
-
- // 测试 3:重新加载配置
- Console.WriteLine("测试 3: 重新加载配置");
- ConfigManager.Instance.Reload();
- var reloadedConfig = ConfigManager.Instance.Current;
- Console.WriteLine($"重载后网格尺寸: {reloadedConfig.GridGeneration.CellSizeMeters} 米");
- Console.WriteLine($"重载后路径策略: {reloadedConfig.PathPlanning.DefaultPathStrategy}");
- Console.WriteLine($"重载后网格可视化: {reloadedConfig.Visualization.EnableGridVisualization}");
- Console.WriteLine();
-
- // 测试 4:重置为默认配置
- Console.WriteLine("测试 4: 重置为默认配置");
- ConfigManager.Instance.ResetToDefault();
- var defaultConfig = ConfigManager.Instance.Current;
- Console.WriteLine($"重置后网格尺寸: {defaultConfig.GridGeneration.CellSizeMeters} 米");
- Console.WriteLine($"重置后路径策略: {defaultConfig.PathPlanning.DefaultPathStrategy}");
- Console.WriteLine();
-
- Console.WriteLine("=== 测试完成 ===");
- Console.WriteLine($"请检查配置文件: {ConfigManager.ConfigFilePath}");
- }
- }
-}
diff --git a/config.toml.example b/config.toml.example
index f5d7f77..3538812 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -1,76 +1,51 @@
# NavisworksTransport 系统配置文件
-# 单位说明:长度单位均为米(m),时间单位为秒(s)
-# 自动生成时间: 2025-10-11 10:50:00
+# 单位说明:长度单位均为米(m)
-[grid_generation]
-# 网格单元大小(米)- 推荐值:0.3-0.8
+[path_editing]
+# 网格单元大小(米)- 推荐值:0.3-1.0
cell_size_meters = 0.5
-# 车辆半径(米)- 用于障碍物膨胀计算
-vehicle_radius_meters = 0.3
-
-# 安全间隙(米)- 额外的安全距离
-safety_margin_meters = 0.2
-
-# 膨胀半径(网格单元数)
-inflation_radius_cells = 2
-
-# 扫描高度(米)
-scan_height_meters = 0.1
-
-[path_planning]
# 最大高度差(米)- 楼梯、坡道可接受的高度阈值
max_height_diff_meters = 0.35
-# 车辆尺寸(米)
+# 车辆长度(米)
+vehicle_length_meters = 1.0
+
+# 车辆宽度(米)
+vehicle_width_meters = 1.0
+
+# 车辆高度(米)
vehicle_height_meters = 2.0
-vehicle_length_meters = 2.5
-vehicle_width_meters = 1.8
-# 默认路径策略:"Shortest" | "Straightest" | "SafetyFirst"
-default_path_strategy = "Straightest"
-
-# 启用路径优化(减少转弯点)
-enable_path_optimization = true
+# 安全间隙(米)
+safety_margin_meters = 0.05
[visualization]
-# 网格点大小(像素)
-grid_point_size = 5.0
-
-# 路径线宽(像素)
-path_line_width = 2.0
-
-# 路径点大小(模型单位)
-path_point_size = 50.0
-
-# 启用网格可视化
-enable_grid_visualization = false
-
-# 启用多层网格可视化
-enable_multi_layer_visualization = true
+# 地图边距比例(0-1之间)
+margin_ratio = 0.1
[animation]
-# 默认动画速度(米/秒)
-default_speed_meters_per_second = 1.5
-
# 动画帧率(帧/秒)
frame_rate = 30
-# 步进间隔(毫秒)
-step_interval_ms = 100
+# 动画持续时间(秒)
+duration_seconds = 10.0
-# 启用平滑插值
-enable_smooth_interpolation = true
+# 检测间隙(米)
+detection_gap_meters = 0.05
-[collision]
-# 碰撞检测步长(米)
-detection_step_meters = 0.1
+[logistics]
+# 可通行性(默认值:true)
+traversable = true
-# 碰撞容差(米)
-collision_tolerance_meters = 0.01
+# 优先级(默认值:5,范围:1-5)
+priority = 5
-# 启用实时碰撞检测
-enable_realtime_detection = true
+# 高度限制(默认值:3.0米)
+height_limit_meters = 3.0
-# 自动生成碰撞报告
-auto_generate_report = true
+# 速度限制(默认值:0.8米/秒)
+speed_limit_meters_per_second = 0.8
+
+# 宽度限制(默认值:3.0米)
+width_limit_meters = 3.0
diff --git a/src/Commands/SetLogisticsAttributeCommand.cs b/src/Commands/SetLogisticsAttributeCommand.cs
index ec362ec..d0fbfe4 100644
--- a/src/Commands/SetLogisticsAttributeCommand.cs
+++ b/src/Commands/SetLogisticsAttributeCommand.cs
@@ -277,10 +277,10 @@ namespace NavisworksTransport.Commands
item
};
+ // 使用配置的默认值添加物流属性
int affectedCount = CategoryAttributeManager.AddLogisticsAttributes(
itemCollection,
- _parameters.ElementType,
- _parameters.IsTraversable ?? true);
+ _parameters.ElementType);
bool success = affectedCount > 0;
diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs
index 0fed9d2..ee5e535 100644
--- a/src/Core/Animation/PathAnimationManager.cs
+++ b/src/Core/Animation/PathAnimationManager.cs
@@ -95,7 +95,7 @@ namespace NavisworksTransport.Core.Animation
// === 预计算动画系统 ===
private List _animationFrames; // 所有帧数据
private int _currentFrameIndex = 0; // 当前帧索引
- private HashSet _currentHighlightedItems; // 当前高亮的对象
+
private List _allCollisionResults; // 所有碰撞结果(不去重)
private bool _lastHighlightState = false; // 上一帧的高亮状态
@@ -158,7 +158,6 @@ namespace NavisworksTransport.Core.Animation
{
_pathPoints = new List();
_animationFrames = new List();
- _currentHighlightedItems = new HashSet();
_allCollisionResults = new List();
// 初始化动画模式
@@ -363,7 +362,6 @@ namespace NavisworksTransport.Core.Animation
// 初始化帧列表
_animationFrames = new List();
- _currentHighlightedItems = new HashSet();
_allCollisionResults = new List();
_currentFrameIndex = 0;
diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs
index 690612d..a87664f 100644
--- a/src/Core/Collision/ClashDetectiveIntegration.cs
+++ b/src/Core/Collision/ClashDetectiveIntegration.cs
@@ -138,9 +138,6 @@ namespace NavisworksTransport
}
}
- private DateTime _lastCollisionTestTime = DateTime.MinValue;
- private readonly TimeSpan _minTestInterval = TimeSpan.FromMilliseconds(500); // 最小间隔500ms
-
///
/// 缓存碰撞结果(动画过程中使用)- 现在包含位置信息用于恢复测试
/// 使用精确的碰撞检测算法替代简化检测
diff --git a/src/Core/Config/ConfigManager.cs b/src/Core/Config/ConfigManager.cs
index ab82acb..873c3f8 100644
--- a/src/Core/Config/ConfigManager.cs
+++ b/src/Core/Config/ConfigManager.cs
@@ -119,32 +119,18 @@ namespace NavisworksTransport.Core.Config
var model = Toml.ToModel(tomlContent);
var config = new SystemConfig();
- // 加载网格生成配置
- if (model.ContainsKey("grid_generation"))
+ // 加载路径编辑配置
+ if (model.ContainsKey("path_editing"))
{
- var gridGen = model["grid_generation"] as TomlTable;
- if (gridGen != null)
+ var pathEdit = model["path_editing"] as TomlTable;
+ if (pathEdit != null)
{
- config.GridGeneration.CellSizeMeters = GetDouble(gridGen, "cell_size_meters", 0.5);
- config.GridGeneration.VehicleRadiusMeters = GetDouble(gridGen, "vehicle_radius_meters", 0.3);
- config.GridGeneration.SafetyMarginMeters = GetDouble(gridGen, "safety_margin_meters", 0.2);
- config.GridGeneration.InflationRadiusCells = GetInt(gridGen, "inflation_radius_cells", 2);
- config.GridGeneration.ScanHeightMeters = GetDouble(gridGen, "scan_height_meters", 0.1);
- }
- }
-
- // 加载路径规划配置
- if (model.ContainsKey("path_planning"))
- {
- var pathPlan = model["path_planning"] as TomlTable;
- if (pathPlan != null)
- {
- config.PathPlanning.MaxHeightDiffMeters = GetDouble(pathPlan, "max_height_diff_meters", 0.35);
- config.PathPlanning.VehicleHeightMeters = GetDouble(pathPlan, "vehicle_height_meters", 2.0);
- config.PathPlanning.VehicleLengthMeters = GetDouble(pathPlan, "vehicle_length_meters", 2.5);
- config.PathPlanning.VehicleWidthMeters = GetDouble(pathPlan, "vehicle_width_meters", 1.8);
- config.PathPlanning.DefaultPathStrategy = GetString(pathPlan, "default_path_strategy", "Straightest");
- config.PathPlanning.EnablePathOptimization = GetBool(pathPlan, "enable_path_optimization", true);
+ config.PathEditing.CellSizeMeters = GetDouble(pathEdit, "cell_size_meters", 0.5);
+ config.PathEditing.MaxHeightDiffMeters = GetDouble(pathEdit, "max_height_diff_meters", 0.35);
+ config.PathEditing.VehicleLengthMeters = GetDouble(pathEdit, "vehicle_length_meters", 1.0);
+ config.PathEditing.VehicleWidthMeters = GetDouble(pathEdit, "vehicle_width_meters", 1.0);
+ config.PathEditing.VehicleHeightMeters = GetDouble(pathEdit, "vehicle_height_meters", 2.0);
+ config.PathEditing.SafetyMarginMeters = GetDouble(pathEdit, "safety_margin_meters", 0.05);
}
}
@@ -154,11 +140,7 @@ namespace NavisworksTransport.Core.Config
var visual = model["visualization"] as TomlTable;
if (visual != null)
{
- config.Visualization.GridPointSize = GetDouble(visual, "grid_point_size", 5.0);
- config.Visualization.PathLineWidth = GetDouble(visual, "path_line_width", 2.0);
- config.Visualization.PathPointSize = GetDouble(visual, "path_point_size", 50.0);
- config.Visualization.EnableGridVisualization = GetBool(visual, "enable_grid_visualization", false);
- config.Visualization.EnableMultiLayerVisualization = GetBool(visual, "enable_multi_layer_visualization", true);
+ config.Visualization.MarginRatio = GetDouble(visual, "margin_ratio", 0.1);
}
}
@@ -168,23 +150,23 @@ namespace NavisworksTransport.Core.Config
var anim = model["animation"] as TomlTable;
if (anim != null)
{
- config.Animation.DefaultSpeedMetersPerSecond = GetDouble(anim, "default_speed_meters_per_second", 1.5);
config.Animation.FrameRate = GetInt(anim, "frame_rate", 30);
- config.Animation.StepIntervalMs = GetInt(anim, "step_interval_ms", 100);
- config.Animation.EnableSmoothInterpolation = GetBool(anim, "enable_smooth_interpolation", true);
+ config.Animation.DurationSeconds = GetDouble(anim, "duration_seconds", 10.0);
+ config.Animation.DetectionGapMeters = GetDouble(anim, "detection_gap_meters", 0.05);
}
}
- // 加载碰撞检测配置
- if (model.ContainsKey("collision"))
+ // 加载物流属性配置
+ if (model.ContainsKey("logistics"))
{
- var collision = model["collision"] as TomlTable;
- if (collision != null)
+ var logistics = model["logistics"] as TomlTable;
+ if (logistics != null)
{
- config.Collision.DetectionStepMeters = GetDouble(collision, "detection_step_meters", 0.1);
- config.Collision.CollisionToleranceMeters = GetDouble(collision, "collision_tolerance_meters", 0.01);
- config.Collision.EnableRealtimeDetection = GetBool(collision, "enable_realtime_detection", true);
- config.Collision.AutoGenerateReport = GetBool(collision, "auto_generate_report", true);
+ config.Logistics.Traversable = GetBool(logistics, "traversable", true);
+ config.Logistics.Priority = GetInt(logistics, "priority", 5);
+ config.Logistics.HeightLimitMeters = GetDouble(logistics, "height_limit_meters", 3.0);
+ config.Logistics.SpeedLimitMetersPerSecond = GetDouble(logistics, "speed_limit_meters_per_second", 0.8);
+ config.Logistics.WidthLimitMeters = GetDouble(logistics, "width_limit_meters", 3.0);
}
}
@@ -224,91 +206,65 @@ namespace NavisworksTransport.Core.Config
// 添加文件头注释
sb.AppendLine("# NavisworksTransport 系统配置文件");
- sb.AppendLine("# 单位说明:长度单位均为米(m),时间单位为秒(s)");
+ sb.AppendLine("# 单位说明:长度单位均为米(m)");
sb.AppendLine("# 自动生成时间: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
sb.AppendLine();
- // 网格生成配置
- sb.AppendLine("[grid_generation]");
- sb.AppendLine("# 网格单元大小(米)- 推荐值:0.3-0.8");
- sb.AppendLine($"cell_size_meters = {config.GridGeneration.CellSizeMeters}");
+ // 路径编辑配置
+ sb.AppendLine("[path_editing]");
+ sb.AppendLine("# 网格单元大小(米)- 推荐值:0.3-1.0");
+ sb.AppendLine($"cell_size_meters = {config.PathEditing.CellSizeMeters}");
sb.AppendLine();
- sb.AppendLine("# 车辆半径(米)- 用于障碍物膨胀计算");
- sb.AppendLine($"vehicle_radius_meters = {config.GridGeneration.VehicleRadiusMeters}");
- sb.AppendLine();
- sb.AppendLine("# 安全间隙(米)- 额外的安全距离");
- sb.AppendLine($"safety_margin_meters = {config.GridGeneration.SafetyMarginMeters}");
- sb.AppendLine();
- sb.AppendLine("# 膨胀半径(网格单元数)");
- sb.AppendLine($"inflation_radius_cells = {config.GridGeneration.InflationRadiusCells}");
- sb.AppendLine();
- sb.AppendLine("# 扫描高度(米)");
- sb.AppendLine($"scan_height_meters = {config.GridGeneration.ScanHeightMeters}");
- sb.AppendLine();
-
- // 路径规划配置
- sb.AppendLine("[path_planning]");
sb.AppendLine("# 最大高度差(米)- 楼梯、坡道可接受的高度阈值");
- sb.AppendLine($"max_height_diff_meters = {config.PathPlanning.MaxHeightDiffMeters}");
+ sb.AppendLine($"max_height_diff_meters = {config.PathEditing.MaxHeightDiffMeters}");
sb.AppendLine();
- sb.AppendLine("# 车辆尺寸(米)");
- sb.AppendLine($"vehicle_height_meters = {config.PathPlanning.VehicleHeightMeters}");
- sb.AppendLine($"vehicle_length_meters = {config.PathPlanning.VehicleLengthMeters}");
- sb.AppendLine($"vehicle_width_meters = {config.PathPlanning.VehicleWidthMeters}");
+ sb.AppendLine("# 车辆长度(米)");
+ sb.AppendLine($"vehicle_length_meters = {config.PathEditing.VehicleLengthMeters}");
sb.AppendLine();
- sb.AppendLine("# 默认路径策略:\"Shortest\" | \"Straightest\" | \"SafetyFirst\"");
- sb.AppendLine($"default_path_strategy = \"{config.PathPlanning.DefaultPathStrategy}\"");
+ sb.AppendLine("# 车辆宽度(米)");
+ sb.AppendLine($"vehicle_width_meters = {config.PathEditing.VehicleWidthMeters}");
sb.AppendLine();
- sb.AppendLine("# 启用路径优化(减少转弯点)");
- sb.AppendLine($"enable_path_optimization = {config.PathPlanning.EnablePathOptimization.ToString().ToLower()}");
+ sb.AppendLine("# 车辆高度(米)");
+ sb.AppendLine($"vehicle_height_meters = {config.PathEditing.VehicleHeightMeters}");
+ sb.AppendLine();
+ sb.AppendLine("# 安全间隙(米)");
+ sb.AppendLine($"safety_margin_meters = {config.PathEditing.SafetyMarginMeters}");
sb.AppendLine();
// 可视化配置
sb.AppendLine("[visualization]");
- sb.AppendLine("# 网格点大小(像素)");
- sb.AppendLine($"grid_point_size = {config.Visualization.GridPointSize}");
- sb.AppendLine();
- sb.AppendLine("# 路径线宽(像素)");
- sb.AppendLine($"path_line_width = {config.Visualization.PathLineWidth}");
- sb.AppendLine();
- sb.AppendLine("# 路径点大小(模型单位)");
- sb.AppendLine($"path_point_size = {config.Visualization.PathPointSize}");
- sb.AppendLine();
- sb.AppendLine("# 启用网格可视化");
- sb.AppendLine($"enable_grid_visualization = {config.Visualization.EnableGridVisualization.ToString().ToLower()}");
- sb.AppendLine();
- sb.AppendLine("# 启用多层网格可视化");
- sb.AppendLine($"enable_multi_layer_visualization = {config.Visualization.EnableMultiLayerVisualization.ToString().ToLower()}");
+ sb.AppendLine("# 地图边距比例(0-1之间)");
+ sb.AppendLine($"margin_ratio = {config.Visualization.MarginRatio}");
sb.AppendLine();
// 动画配置
sb.AppendLine("[animation]");
- sb.AppendLine("# 默认动画速度(米/秒)");
- sb.AppendLine($"default_speed_meters_per_second = {config.Animation.DefaultSpeedMetersPerSecond}");
- sb.AppendLine();
sb.AppendLine("# 动画帧率(帧/秒)");
sb.AppendLine($"frame_rate = {config.Animation.FrameRate}");
sb.AppendLine();
- sb.AppendLine("# 步进间隔(毫秒)");
- sb.AppendLine($"step_interval_ms = {config.Animation.StepIntervalMs}");
+ sb.AppendLine("# 动画持续时间(秒)");
+ sb.AppendLine($"duration_seconds = {config.Animation.DurationSeconds}");
sb.AppendLine();
- sb.AppendLine("# 启用平滑插值");
- sb.AppendLine($"enable_smooth_interpolation = {config.Animation.EnableSmoothInterpolation.ToString().ToLower()}");
+ sb.AppendLine("# 检测间隙(米)");
+ sb.AppendLine($"detection_gap_meters = {config.Animation.DetectionGapMeters}");
sb.AppendLine();
- // 碰撞检测配置
- sb.AppendLine("[collision]");
- sb.AppendLine("# 碰撞检测步长(米)");
- sb.AppendLine($"detection_step_meters = {config.Collision.DetectionStepMeters}");
+ // 物流属性配置
+ sb.AppendLine("[logistics]");
+ sb.AppendLine("# 可通行性(默认值:true)");
+ sb.AppendLine($"traversable = {config.Logistics.Traversable.ToString().ToLower()}");
sb.AppendLine();
- sb.AppendLine("# 碰撞容差(米)");
- sb.AppendLine($"collision_tolerance_meters = {config.Collision.CollisionToleranceMeters}");
+ sb.AppendLine("# 优先级(默认值:5,范围:1-5)");
+ sb.AppendLine($"priority = {config.Logistics.Priority}");
sb.AppendLine();
- sb.AppendLine("# 启用实时碰撞检测");
- sb.AppendLine($"enable_realtime_detection = {config.Collision.EnableRealtimeDetection.ToString().ToLower()}");
+ sb.AppendLine("# 高度限制(默认值:3.0米)");
+ sb.AppendLine($"height_limit_meters = {config.Logistics.HeightLimitMeters}");
sb.AppendLine();
- sb.AppendLine("# 自动生成碰撞报告");
- sb.AppendLine($"auto_generate_report = {config.Collision.AutoGenerateReport.ToString().ToLower()}");
+ sb.AppendLine("# 速度限制(默认值:0.8米/秒)");
+ sb.AppendLine($"speed_limit_meters_per_second = {config.Logistics.SpeedLimitMetersPerSecond}");
+ sb.AppendLine();
+ sb.AppendLine("# 宽度限制(默认值:3.0米)");
+ sb.AppendLine($"width_limit_meters = {config.Logistics.WidthLimitMeters}");
return sb.ToString();
}
diff --git a/src/Core/Config/SystemConfig.cs b/src/Core/Config/SystemConfig.cs
index 62f6d78..19721e5 100644
--- a/src/Core/Config/SystemConfig.cs
+++ b/src/Core/Config/SystemConfig.cs
@@ -17,6 +17,11 @@ namespace NavisworksTransport.Core.Config
///
public PathPlanningConfig PathPlanning { get; set; } = new PathPlanningConfig();
+ ///
+ /// 路径编辑配置
+ ///
+ public PathEditingConfig PathEditing { get; set; } = new PathEditingConfig();
+
///
/// 可视化配置
///
@@ -28,9 +33,9 @@ namespace NavisworksTransport.Core.Config
public AnimationConfig Animation { get; set; } = new AnimationConfig();
///
- /// 碰撞检测配置
+ /// 物流属性配置
///
- public CollisionConfig Collision { get; set; } = new CollisionConfig();
+ public LogisticsConfig Logistics { get; set; } = new LogisticsConfig();
}
///
@@ -38,35 +43,6 @@ namespace NavisworksTransport.Core.Config
///
public class GridGenerationConfig
{
- ///
- /// 网格单元大小(米)
- /// 推荐值:0.3-0.8
- ///
- public double CellSizeMeters { get; set; } = 0.5;
-
- ///
- /// 车辆半径(米)
- /// 用于障碍物膨胀计算
- ///
- public double VehicleRadiusMeters { get; set; } = 0.3;
-
- ///
- /// 安全间隙(米)
- /// 额外的安全距离
- ///
- public double SafetyMarginMeters { get; set; } = 0.2;
-
- ///
- /// 膨胀半径(网格单元数)
- /// 障碍物膨胀的单元格数量
- ///
- public int InflationRadiusCells { get; set; } = 2;
-
- ///
- /// 扫描高度(米)
- /// 障碍物扫描的垂直步进高度
- ///
- public double ScanHeightMeters { get; set; } = 0.1;
}
///
@@ -74,43 +50,44 @@ namespace NavisworksTransport.Core.Config
///
public class PathPlanningConfig
{
+ }
+
+ ///
+ /// 路径编辑配置
+ ///
+ public class PathEditingConfig
+ {
+ ///
+ /// 网格单元大小(米)
+ /// 推荐值:0.3-1.0
+ ///
+ public double CellSizeMeters { get; set; } = 0.5;
+
///
/// 最大高度差(米)
/// 楼梯、坡道可接受的高度阈值
///
public double MaxHeightDiffMeters { get; set; } = 0.35;
+ ///
+ /// 车辆长度(米)
+ ///
+ public double VehicleLengthMeters { get; set; } = 1.0;
+
+ ///
+ /// 车辆宽度(米)
+ ///
+ public double VehicleWidthMeters { get; set; } = 1.0;
+
///
/// 车辆高度(米)
- /// 用于通行性判断
///
public double VehicleHeightMeters { get; set; } = 2.0;
///
- /// 车辆长度(米)
- /// 用于转弯半径计算
+ /// 安全间隙(米)
///
- public double VehicleLengthMeters { get; set; } = 2.5;
-
- ///
- /// 车辆宽度(米)
- /// 用于通道宽度判断
- ///
- public double VehicleWidthMeters { get; set; } = 1.8;
-
- ///
- /// 默认路径策略
- /// "Shortest" - 最短路径优先
- /// "Straightest" - 直线优先
- /// "SafetyFirst" - 安全优先
- ///
- public string DefaultPathStrategy { get; set; } = "Straightest";
-
- ///
- /// 路径优化启用
- /// 是否启用路径点优化(减少转弯点)
- ///
- public bool EnablePathOptimization { get; set; } = true;
+ public double SafetyMarginMeters { get; set; } = 0.05;
}
///
@@ -119,31 +96,10 @@ namespace NavisworksTransport.Core.Config
public class VisualizationConfig
{
///
- /// 网格点大小(像素)
+ /// 地图边距比例
+ /// 地图显示时的边距占比(0-1之间)
///
- public double GridPointSize { get; set; } = 5.0;
-
- ///
- /// 路径线宽(像素)
- ///
- public double PathLineWidth { get; set; } = 2.0;
-
- ///
- /// 路径点大小(模型单位)
- ///
- public double PathPointSize { get; set; } = 50.0;
-
- ///
- /// 启用网格可视化
- /// 是否默认显示网格地图
- ///
- public bool EnableGridVisualization { get; set; } = false;
-
- ///
- /// 启用多层网格可视化
- /// 是否显示多个高度层的网格
- ///
- public bool EnableMultiLayerVisualization { get; set; } = true;
+ public double MarginRatio { get; set; } = 0.1;
}
///
@@ -151,57 +107,50 @@ namespace NavisworksTransport.Core.Config
///
public class AnimationConfig
{
- ///
- /// 动画速度(米/秒)
- /// 默认车辆移动速度
- ///
- public double DefaultSpeedMetersPerSecond { get; set; } = 1.5;
-
///
/// 动画帧率(帧/秒)
///
public int FrameRate { get; set; } = 30;
///
- /// 步进间隔(毫秒)
- /// 步进模式下每步的时间间隔
+ /// 动画持续时间(秒)
///
- public int StepIntervalMs { get; set; } = 100;
+ public double DurationSeconds { get; set; } = 10.0;
///
- /// 启用平滑插值
- /// 是否在路径点之间使用平滑插值
+ /// 检测间隙(米)
///
- public bool EnableSmoothInterpolation { get; set; } = true;
+ public double DetectionGapMeters { get; set; } = 0.05;
}
///
- /// 碰撞检测配置
+ /// 物流属性配置
///
- public class CollisionConfig
+ public class LogisticsConfig
{
///
- /// 碰撞检测步长(米)
- /// 动画过程中每次检测的移动距离
+ /// 可通行性(默认值:true)
///
- public double DetectionStepMeters { get; set; } = 0.1;
+ public bool Traversable { get; set; } = true;
///
- /// 碰撞容差(米)
- /// 判定为碰撞的最小距离
+ /// 优先级(默认值:5,范围:1-5)
///
- public double CollisionToleranceMeters { get; set; } = 0.01;
+ public int Priority { get; set; } = 5;
///
- /// 启用实时碰撞检测
- /// 动画播放时是否实时检测碰撞
+ /// 高度限制(默认值:3.0米)
///
- public bool EnableRealtimeDetection { get; set; } = true;
+ public double HeightLimitMeters { get; set; } = 3.0;
///
- /// 自动生成碰撞报告
- /// 动画结束后是否自动生成报告
+ /// 速度限制(默认值:0.8米/秒)
///
- public bool AutoGenerateReport { get; set; } = true;
+ public double SpeedLimitMetersPerSecond { get; set; } = 0.8;
+
+ ///
+ /// 宽度限制(默认值:3.0米)
+ ///
+ public double WidthLimitMeters { get; set; } = 3.0;
}
}
diff --git a/src/Core/PathPointRenderPlugin.cs b/src/Core/PathPointRenderPlugin.cs
index a802623..0ff964b 100644
--- a/src/Core/PathPointRenderPlugin.cs
+++ b/src/Core/PathPointRenderPlugin.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Plugins;
-using NavisworksTransport.Core;
+using NavisworksTransport.Utils;
namespace NavisworksTransport
{
@@ -776,7 +776,7 @@ namespace NavisworksTransport
private VehicleSpaceMarker CreateVehicleSpaceMarker(PathPoint fromPoint, PathPoint toPoint)
{
// 获取单位转换系数
- double metersToModelUnits = GetMetersToModelUnitsConversionFactor();
+ double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
// 计算车辆通行空间宽度(米)
double vehicleInflationWidthInMeters = Math.Max(_vehicleLength, _vehicleWidth) + 2 * _safetyMargin;
@@ -848,7 +848,7 @@ namespace NavisworksTransport
{
Center = point.Position,
Normal = new Vector3D(0, 0, 1),
- Radius = isGridVisualization ? GetRadiusForGridVisualization(_currentGridSizeInMeters) : GetRadiusForPointType(point.Type),
+ Radius = isGridVisualization ? GetRadiusForGridVisualization() : GetRadiusForPointType(point.Type),
Color = isGridVisualization ? gridStyle.Color : GetColorForPointType(point.Type),
Alpha = isGridVisualization ? gridStyle.Alpha : 1.0,
Filled = true,
@@ -862,13 +862,13 @@ namespace NavisworksTransport
/// 获取网格可视化小球的半径(比正常路径点小)
///
/// 网格可视化半径
- private double GetRadiusForGridVisualization(double gridSizeInMeters = 0.5)
+ private double GetRadiusForGridVisualization()
{
// 使用标准尺寸的1/5作为网格点尺寸
double standardRadiusInMeters = GetStandardRadiusInMeters();
double radiusInMeters = standardRadiusInMeters / 5.0;
-
- double metersToModelUnits = GetMetersToModelUnitsConversionFactor();
+
+ double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
return radiusInMeters * metersToModelUnits;
}
@@ -972,11 +972,11 @@ namespace NavisworksTransport
{
// 获取标准尺寸(起点尺寸)
double standardRadiusInMeters = GetStandardRadiusInMeters();
-
+
// 连线半径为标准尺寸的40%
double lineRadiusInMeters = standardRadiusInMeters * 0.4;
-
- return lineRadiusInMeters * GetMetersToModelUnitsConversionFactor();
+
+ return lineRadiusInMeters * UnitsConverter.GetMetersToUnitsConversionFactor();
}
///
@@ -1411,7 +1411,7 @@ namespace NavisworksTransport
{
// 获取标准尺寸(起点尺寸)
double standardRadiusInMeters = GetStandardRadiusInMeters();
-
+
// 根据点类型应用比例系数
double baseRadiusInMeters;
if (pointType == PathPointType.WayPoint)
@@ -1424,59 +1424,14 @@ namespace NavisworksTransport
// 起点/终点使用标准尺寸(100%)
baseRadiusInMeters = standardRadiusInMeters * 1.0;
}
-
+
// 获取真实文档单位转换系数
- double metersToModelUnits = GetMetersToModelUnitsConversionFactor();
-
+ double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
+
// 转换为模型单位
double radiusInModelUnits = baseRadiusInMeters * metersToModelUnits;
-
- return radiusInModelUnits;
- }
- ///
- /// 获取米转换为文档单位的转换系数
- /// 使用Navisworks API直接获取真实文档单位,而不是猜测
- ///
- private double GetMetersToModelUnitsConversionFactor()
- {
- try
- {
- var units = Application.ActiveDocument.Units;
-
- switch (units)
- {
- case Units.Millimeters:
- return 1000.0; // 1米 = 1000毫米
- case Units.Centimeters:
- return 100.0; // 1米 = 100厘米
- case Units.Meters:
- return 1.0; // 1米 = 1米
- case Units.Inches:
- return 39.37; // 1米 = 39.37英寸
- case Units.Feet:
- return 3.281; // 1米 = 3.281英尺
- case Units.Kilometers:
- return 0.001; // 1米 = 0.001公里
- case Units.Micrometers:
- return 1000000.0; // 1米 = 1000000微米
- case Units.Microinches:
- return 39370078.74; // 1米 = 39370078.74微英寸
- case Units.Mils:
- return 39370.08; // 1米 = 39370.08密尔
- case Units.Yards:
- return 1.094; // 1米 = 1.094码
- case Units.Miles:
- return 0.000621; // 1米 = 0.000621英里
- default:
- return 1.0;
- }
- }
- catch (Exception ex)
- {
- LogManager.Error($"[单位检测] API调用失败: {ex.Message}");
- return 1.0;
- }
+ return radiusInModelUnits;
}
///
diff --git a/src/Core/Properties/CategoryAttributeManager.cs b/src/Core/Properties/CategoryAttributeManager.cs
index 04e3577..c85e276 100644
--- a/src/Core/Properties/CategoryAttributeManager.cs
+++ b/src/Core/Properties/CategoryAttributeManager.cs
@@ -95,7 +95,28 @@ namespace NavisworksTransport
}
///
- /// 为选定的模型项添加物流属性
+ /// 为选定的模型项添加物流属性(使用配置默认值)
+ ///
+ /// 要处理的模型项集合
+ /// 物流元素类型
+ /// 成功处理的项目数量
+ public static int AddLogisticsAttributes(
+ ModelItemCollection items,
+ LogisticsElementType elementType)
+ {
+ var logistics = NavisworksTransport.Core.Config.ConfigManager.Instance.Current.Logistics;
+ return AddLogisticsAttributes(
+ items,
+ elementType,
+ logistics.Traversable,
+ logistics.Priority,
+ logistics.HeightLimitMeters,
+ logistics.SpeedLimitMetersPerSecond,
+ logistics.WidthLimitMeters);
+ }
+
+ ///
+ /// 为选定的模型项添加物流属性(指定所有参数)
///
/// 要处理的模型项集合
/// 物流元素类型
@@ -108,11 +129,11 @@ namespace NavisworksTransport
public static int AddLogisticsAttributes(
ModelItemCollection items,
LogisticsElementType elementType,
- bool isTraversable = true,
- int priority = 5,
- double heightLimit = 3.0,
- double speedLimit = 10.0,
- double widthLimit = 3.0)
+ bool isTraversable,
+ int priority,
+ double heightLimit,
+ double speedLimit,
+ double widthLimit)
{
if (items == null || items.Count == 0)
{
@@ -142,8 +163,8 @@ namespace NavisworksTransport
};
int successCount = NavisworksComPropertyManager.SetUserDefinedProperties(
- items,
- LogisticsCategories.LOGISTICS,
+ items,
+ LogisticsCategories.LOGISTICS,
LogisticsCategories.CATEGORY_INTERNAL_NAME,
properties,
propertyInternalNames);
diff --git a/src/PathPlanning/AutoPathFinder.cs b/src/PathPlanning/AutoPathFinder.cs
index 8404cb5..1a60271 100644
--- a/src/PathPlanning/AutoPathFinder.cs
+++ b/src/PathPlanning/AutoPathFinder.cs
@@ -6,6 +6,7 @@ using Roy_T.AStar.Grids;
using Roy_T.AStar.Primitives;
using Roy_T.AStar.Paths;
using NavisworksTransport.Utils;
+using NavisworksTransport.Core.Config;
namespace NavisworksTransport.PathPlanning
{
@@ -48,11 +49,14 @@ namespace NavisworksTransport.PathPlanning
public class AutoPathFinder
{
///
- /// 水平边连接允许的最大高度差(米)
- /// 足以支持台阶连接(约0.15米)和地面到楼梯底部的连接(约0.3米)
+ /// 获取水平边连接允许的最大高度差(米)
+ /// 从配置文件读取,足以支持台阶连接(约0.15米)和地面到楼梯底部的连接(约0.3米)
/// 使用时需转换为模型单位
///
- private const double MAX_HEIGHT_DIFF_METERS = 0.35;
+ private double GetMaxHeightDiffMeters()
+ {
+ return ConfigManager.Instance.Current.PathEditing.MaxHeightDiffMeters;
+ }
///
/// 3D节点信息(存储每个A*节点对应的3D坐标和类型)
@@ -143,8 +147,9 @@ namespace NavisworksTransport.PathPlanning
float maxSpeed = (float)baseSpeed;
// 将米转换为模型单位
- double maxHeightDiffInModelUnits = MAX_HEIGHT_DIFF_METERS * UnitsConverter.GetMetersToUnitsConversionFactor();
- LogManager.Info($"[3D图构建] 高度差阈值: {MAX_HEIGHT_DIFF_METERS}米 = {maxHeightDiffInModelUnits:F2}模型单位");
+ double maxHeightDiffMeters = GetMaxHeightDiffMeters();
+ double maxHeightDiffInModelUnits = maxHeightDiffMeters * UnitsConverter.GetMetersToUnitsConversionFactor();
+ LogManager.Info($"[3D图构建] 高度差阈值: {maxHeightDiffMeters}米 = {maxHeightDiffInModelUnits:F2}模型单位");
// === 阶段1:创建所有3D节点 ===
int totalNodesCreated = 0;
diff --git a/src/PathPlanning/GridMapGenerator.cs b/src/PathPlanning/GridMapGenerator.cs
index bd1cb54..5310f13 100644
--- a/src/PathPlanning/GridMapGenerator.cs
+++ b/src/PathPlanning/GridMapGenerator.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
+using NavisworksTransport.Core.Config;
namespace NavisworksTransport.PathPlanning
{
@@ -30,11 +31,14 @@ namespace NavisworksTransport.PathPlanning
public class GridMapGenerator
{
///
- /// 边界检测的最大高度差(米)
- /// 与AutoPathFinder中的MAX_HEIGHT_DIFF_METERS保持一致
+ /// 获取边界检测的最大高度差(米)
+ /// 从配置文件读取,与AutoPathFinder保持一致
/// 用于判断层间是否构成边界(超过此阈值则标记为边界)
///
- private const double MAX_HEIGHT_DIFF_METERS = 0.35;
+ private double GetMaxHeightDiffMeters()
+ {
+ return ConfigManager.Instance.Current.PathEditing.MaxHeightDiffMeters;
+ }
private readonly CategoryAttributeManager _categoryManager;
private readonly ChannelBasedGridBuilder _channelBuilder;
@@ -153,8 +157,9 @@ namespace NavisworksTransport.PathPlanning
// 2.7. 标记边界层(用于膨胀计算)
LogManager.Info("【生成网格地图】步骤2.7: 标记边界层");
- double maxHeightDiffInModelUnits = MAX_HEIGHT_DIFF_METERS * metersToModelUnitsConversionFactor;
- LogManager.Info($"【生成网格地图】边界高度差阈值: {MAX_HEIGHT_DIFF_METERS}米 = {maxHeightDiffInModelUnits:F2}模型单位");
+ double maxHeightDiffMeters = GetMaxHeightDiffMeters();
+ double maxHeightDiffInModelUnits = maxHeightDiffMeters * metersToModelUnitsConversionFactor;
+ LogManager.Info($"【生成网格地图】边界高度差阈值: {maxHeightDiffMeters}米 = {maxHeightDiffInModelUnits:F2}模型单位");
MarkBoundaryLayers(channelCoverage.GridMap, maxHeightDiffInModelUnits);
LogManager.Info($"【阶段2.7完成】边界层标记后网格统计: {channelCoverage.GridMap.GetStatistics()}");
@@ -849,7 +854,8 @@ namespace NavisworksTransport.PathPlanning
// 计算高度差阈值(用于楼梯口保护)
double metersToModelUnitsConversionFactor = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
- double maxHeightDiffInModelUnits = MAX_HEIGHT_DIFF_METERS * metersToModelUnitsConversionFactor;
+ double maxHeightDiffMeters = GetMaxHeightDiffMeters();
+ double maxHeightDiffInModelUnits = maxHeightDiffMeters * metersToModelUnitsConversionFactor;
// 统计每个层索引的处理情况
var layerStats = new Dictionary();
diff --git a/src/PathPlanning/VerticalScanProcessor.cs b/src/PathPlanning/VerticalScanProcessor.cs
deleted file mode 100644
index aa1549b..0000000
--- a/src/PathPlanning/VerticalScanProcessor.cs
+++ /dev/null
@@ -1,1059 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Collections.Concurrent;
-using Autodesk.Navisworks.Api;
-
-namespace NavisworksTransport.PathPlanning
-{
- ///
- /// 垂直扫描处理器
- /// 实现多级筛选优化的障碍物检测和2.5D高度区间计算
- /// 预期实现10,000-40,000倍性能提升
- ///
- public class VerticalScanProcessor
- {
- #region 私有字段
-
- ///
- /// 空间哈希表,用于快速查找邻域内的模型项
- ///
- private readonly Dictionary> _spatialHashMap;
-
- ///
- /// 空间哈希的网格大小(米)
- ///
- private readonly double _spatialHashSize;
-
- ///
- /// 并行处理的任务数量
- ///
- private readonly int _parallelDegree;
-
- ///
- /// 候选项缓存,基于空间哈希桶坐标(线程安全)
- ///
- private readonly ConcurrentDictionary> _candidateCache;
-
- ///
- /// 缓存大小限制
- ///
- private int _maxCacheSize;
-
- ///
- /// 缓存命中统计
- ///
- private int _cacheHits;
-
- ///
- /// 缓存未命中统计
- ///
- private int _cacheMisses;
-
- ///
- /// 高度筛选的容差值(米)
- ///
- private const double HEIGHT_TOLERANCE = 0.1;
-
- ///
- /// 默认人行高度(米)- 用于未检测到通道时的默认高度
- ///
- private const double DEFAULT_WALKING_HEIGHT = 2.5;
-
- ///
- /// 最小通行高度(米)
- ///
- private const double MIN_PASSABLE_HEIGHT = 1.8;
-
- #endregion
-
- #region 构造函数
-
- ///
- /// 构造函数
- ///
- /// 空间哈希网格大小(米)或实际网格大小。
- /// 并行度,默认为CPU核心数的一半,避免过度并行导致崩溃
- public VerticalScanProcessor(double spatialHashSize, int parallelDegree = 0)
- {
- _spatialHashSize = spatialHashSize;
-
- // 限制并行度,避免过度并行导致崩溃,最大为CPU核心数的一半
- int maxParallelism = Math.Max(1, Environment.ProcessorCount / 2);
- _parallelDegree = parallelDegree > 0 ? Math.Min(parallelDegree, maxParallelism) : maxParallelism;
- _spatialHashMap = new Dictionary>();
-
- // 初始化线程安全的缓存
- _candidateCache = new ConcurrentDictionary>();
- _maxCacheSize = 1000; // 默认值,将在BuildSpatialHashIndex中动态调整
- _cacheHits = 0;
- _cacheMisses = 0;
-
- // 确定查询策略
- string queryStrategy;
- int bucketCount;
- // 只用单桶模式测试
- queryStrategy = "单桶模式";
- bucketCount = 1;
- // if (_spatialHashSize < 1.5)
- // {
- // queryStrategy = "单桶模式";
- // bucketCount = 1;
- // }
- // else if (_spatialHashSize < 3.0)
- // {
- // queryStrategy = "十字形模式";
- // bucketCount = 5;
- // }
- // else
- // {
- // queryStrategy = "3x3模式";
- // bucketCount = 9;
- // }
-
- LogManager.Info($"[垂直扫描处理器] 初始化完成,空间哈希大小: {_spatialHashSize}m, 查询策略: {queryStrategy}({bucketCount}桶), 并行度: {_parallelDegree}");
- }
-
- #endregion
-
- #region 公共方法
-
- ///
- /// 构建空间哈希索引
- /// 第一级筛选:邻域筛选
- ///
- /// 所有模型项
- /// 扫描边界
- /// 已确定的通道元素列表(将被排除)
- public void BuildSpatialHashIndex(IEnumerable modelItems, BoundingBox3D bounds, IEnumerable channelItems = null)
- {
- LogManager.Info("【垂直扫描处理器】 开始构建空间哈希索引");
- var startTime = DateTime.Now;
-
- _spatialHashMap.Clear();
-
- // 创建通道元素的HashSet以便快速查找
- var channelItemsSet = new HashSet(channelItems ?? new List());
-
- // 统计变量
- var totalItems = modelItems?.Count() ?? 0;
-
- LogManager.Info($"【垂直扫描处理器】 输入统计 - 总模型项: {totalItems}, 将排除通道元素: {channelItemsSet.Count}");
- LogManager.Info($"【垂直扫描处理器】 扫描边界: [{bounds.Min.X:F1},{bounds.Min.Y:F1},{bounds.Min.Z:F1}] - [{bounds.Max.X:F1},{bounds.Max.Y:F1},{bounds.Max.Z:F1}]");
-
- var itemsWithBounds = new ConcurrentBag<(ModelItem item, BoundingBox3D bbox)>();
-
- // 统计计数器(线程安全)
- var geometryCounter = 0;
- var channelExcludedCounter = 0;
- var noBoundsCounter = 0;
- var outOfBoundsCounter = 0;
-
- try
- {
- // 并行计算所有模型项的边界框,使用ConcurrentBag避免锁竞争
- Parallel.ForEach(modelItems, new ParallelOptions { MaxDegreeOfParallelism = _parallelDegree }, item =>
- {
- try
- {
- // 🔥 关键修复:检查是否需要排除通道元素(包括容器节点和子节点)
- if (channelItemsSet.Contains(item) || IsChildOfChannelItems(item, channelItemsSet))
- {
- Interlocked.Increment(ref channelExcludedCounter);
- return; // 跳过通道元素及其子节点
- }
-
- // 然后检查是否有几何体,只对有几何体的元素进行空间哈希处理
- if (item?.HasGeometry == true)
- {
- Interlocked.Increment(ref geometryCounter);
-
- var bbox = item.BoundingBox();
- if (bbox == null)
- {
- Interlocked.Increment(ref noBoundsCounter);
- return;
- }
-
- if (IsWithinBounds(bbox, bounds))
- {
- itemsWithBounds.Add((item, bbox));
- }
- else
- {
- Interlocked.Increment(ref outOfBoundsCounter);
- }
- }
- }
- catch (Exception ex)
- {
- LogManager.Debug($"【垂直扫描处理器】 获取边界框失败: {item?.DisplayName ?? "NULL"}, {ex.Message}");
- }
- });
- }
- catch (Exception ex)
- {
- LogManager.Error($"【垂直扫描处理器】 并行计算边界框时发生严重错误: {ex.Message}");
- return; // 提前退出,避免进一步崩溃
- }
-
- // 输出详细统计信息
- LogManager.Info($"【垂直扫描处理器】 元素筛选统计:");
- LogManager.Info($" - 有几何体的元素: {geometryCounter}");
- LogManager.Info($" - 被排除的通道元素: {channelExcludedCounter}");
- LogManager.Info($" - 无边界框的元素: {noBoundsCounter}");
- LogManager.Info($" - 超出扫描边界的元素: {outOfBoundsCounter}");
- LogManager.Info($" - 符合条件并添加到空间哈希的元素: {itemsWithBounds.Count}");
-
- // 记录待索引元素数量
- LogManager.Info($"【垂直扫描处理器】 待索引元素数量: {itemsWithBounds.Count()}");
-
- // 构建空间哈希
- var totalHashEntries = 0;
- var hashKeyDistribution = new Dictionary();
-
- foreach (var (item, bbox) in itemsWithBounds)
- {
- var hashKeys = GetSpatialHashKeys(bbox);
- foreach (var key in hashKeys)
- {
- if (!_spatialHashMap.ContainsKey(key))
- {
- _spatialHashMap[key] = new List();
- }
- _spatialHashMap[key].Add(item);
- totalHashEntries++;
-
- // 统计哈希键分布 - 修复 .NET Framework 4.8 兼容性
- if (hashKeyDistribution.ContainsKey(key))
- {
- hashKeyDistribution[key]++;
- }
- else
- {
- hashKeyDistribution[key] = 1;
- }
- }
- }
-
- // 统计哈希桶信息(简化版)
- var bucketSizes = _spatialHashMap.Values.Select(list => list.Count).ToList();
- LogManager.Info($"【垂直扫描处理器】 空间哈希构建完成 - 哈希桶数量: {_spatialHashMap.Count}, 平均桶大小: {bucketSizes.DefaultIfEmpty(0).Average():F1}");
-
- // 空间哈希索引构建完成
-
- // 🔥 关键新增:动态计算缓存容量
- double rangeX = bounds.Max.X - bounds.Min.X;
- double rangeY = bounds.Max.Y - bounds.Min.Y;
- int bucketsX = (int)(rangeX / _spatialHashSize + 1);
- int bucketsY = (int)(rangeY / _spatialHashSize + 1);
- int estimatedBuckets = bucketsX * bucketsY;
-
- if (estimatedBuckets > 50000) // 大量哈希桶,需要更大缓存
- {
- _maxCacheSize = Math.Min(200000, estimatedBuckets); // 直接匹配桶数量
- }
- else if (estimatedBuckets > 20000)
- {
- _maxCacheSize = Math.Min(100000, estimatedBuckets);
- }
- else
- {
- _maxCacheSize = Math.Min(20000, estimatedBuckets * 2);
- }
- LogManager.Info($"【垂直扫描处理器】 空间哈希大小: {_spatialHashSize}m");
- LogManager.Info($"【垂直扫描处理器】 范围: X={rangeX:F1}m, Y={rangeY:F1}m");
- LogManager.Info($"【垂直扫描处理器】 桶数: X={bucketsX}, Y={bucketsY}, 总计={estimatedBuckets}");
- LogManager.Info($"【垂直扫描处理器】 动态设置缓存容量: {_maxCacheSize} (预计哈希桶: {estimatedBuckets}, 实际哈希桶: {_spatialHashMap.Count})");
-
- var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
- LogManager.Info($"【垂直扫描处理器】 空间哈希索引构建完成,耗时: {elapsed:F1}ms");
- LogManager.Info($"【垂直扫描处理器】 最终统计 - 参与元素: {itemsWithBounds.Count}, 哈希桶: {_spatialHashMap.Count}, 总哈希条目: {totalHashEntries}");
- }
-
-
- ///
- /// 并行扫描网格点的2.5D高度区间
- ///
- /// 网格点列表
- /// 扫描高度(从地面向上的距离)
- /// 车辆高度(用于通行检查)
- /// 每个网格点的高度区间
- public Dictionary ParallelScanHeightIntervals(
- IEnumerable gridPoints,
- double scanHeight = 20.0,
- double vehicleHeight = 3.0)
- {
- LogManager.Info($"[垂直扫描处理器] 开始并行扫描高度区间,扫描高度: {scanHeight}m, 车辆高度: {vehicleHeight}m");
- var startTime = DateTime.Now;
-
- var results = new ConcurrentDictionary();
- var pointsList = gridPoints?.ToList() ?? new List();
-
- LogManager.Info($"[垂直扫描处理器] 准备处理{pointsList.Count}个点");
-
- try
- {
- // 并行处理每个网格点,添加更严格的异常处理
- Parallel.ForEach(pointsList, new ParallelOptions
- {
- MaxDegreeOfParallelism = _parallelDegree,
- CancellationToken = System.Threading.CancellationToken.None
- }, gridPoint =>
- {
- try
- {
- if (gridPoint != null)
- {
- var interval = ScanVerticalLine(gridPoint, scanHeight, vehicleHeight);
- results[gridPoint] = interval;
- }
- }
- catch (OutOfMemoryException)
- {
- LogManager.Error($"[垂直扫描处理器] 内存不足,跳过点 {gridPoint}");
- if (gridPoint != null)
- {
- results[gridPoint] = new HeightInterval();
- }
- throw; // 内存不足需要重新抛出
- }
- catch (Exception ex)
- {
- LogManager.Error($"[垂直扫描处理器] 扫描点 {gridPoint} 失败: {ex.Message}");
- if (gridPoint != null)
- {
- results[gridPoint] = new HeightInterval();
- }
- }
- });
- }
- catch (Exception ex)
- {
- LogManager.Error($"[垂直扫描处理器] 并行扫描过程中发生严重错误: {ex.Message}");
- // 如果并行处理失败,尝试串行处理作为备选方案
- LogManager.Info("[垂直扫描处理器] 尝试串行处理作为备选方案");
-
- foreach (var gridPoint in pointsList)
- {
- try
- {
- if (gridPoint != null && !results.ContainsKey(gridPoint))
- {
- var interval = ScanVerticalLine(gridPoint, scanHeight, vehicleHeight);
- results[gridPoint] = interval;
- }
- }
- catch (Exception serialEx)
- {
- LogManager.Error($"[垂直扫描处理器] 串行扫描点 {gridPoint} 也失败: {serialEx.Message}");
- if (gridPoint != null)
- {
- results[gridPoint] = new HeightInterval();
- }
- }
- }
- }
-
- var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
- var validIntervals = results.Values.Count(interval => interval.MaxZ > interval.MinZ);
-
- // 输出缓存统计信息
- if (_cacheHits + _cacheMisses > 0)
- {
- double hitRate = (double)_cacheHits / (_cacheHits + _cacheMisses) * 100;
- LogManager.Info($"[垂直扫描处理器] 缓存统计 - 命中: {_cacheHits}, 未命中: {_cacheMisses}, 命中率: {hitRate:F1}%, 缓存大小: {_candidateCache.Count}");
- }
-
- LogManager.Info($"[垂直扫描处理器] 并行扫描完成,耗时: {elapsed:F1}ms, 扫描点: {pointsList.Count}, 有效区间: {validIntervals}");
-
- // 清理缓存,为下次扫描做准备
- _candidateCache.Clear();
- _cacheHits = 0;
- _cacheMisses = 0;
-
- return new Dictionary(results);
- }
-
- ///
- /// 扫描单个垂直线上的通行区间
- ///
- /// 基础点(X,Y坐标)
- /// 扫描高度
- /// 车辆高度
- /// 可通行的高度区间
- public HeightInterval ScanVerticalLine(Point3D basePoint, double scanHeight, double vehicleHeight)
- {
- // 第一级筛选:邻域筛选 - 获取空间哈希邻域内的候选项
- var candidateItems = GetCandidateItemsFromSpatialHash(basePoint);
-
- // 第二级筛选:高度筛选 - 只保留在扫描高度范围内的项目
- var heightFilteredItems = HeightFiltering(candidateItems, basePoint.Z, basePoint.Z + scanHeight);
-
- // 第三级筛选:空间哈希 - 精确的几何相交测试
- var intersectionResults = PerformIntersectionTests(heightFilteredItems, basePoint, scanHeight);
-
- // 计算可通行区间
- var passableInterval = CalculatePassableInterval(intersectionResults, basePoint.Z, scanHeight, vehicleHeight);
-
- return passableInterval;
- }
-
-
- #endregion
-
- #region 私有方法 - 多级筛选实现
-
- ///
- /// 第一级筛选:从空间哈希中获取候选模型项(邻域筛选)
- ///
- /// 查询点
- /// 候选模型项列表
- private IEnumerable GetCandidateItemsFromSpatialHash(Point3D point)
- {
- try
- {
- // 🔥 关键修复:检查坐标值的有效性
- if (double.IsNaN(point.X) || double.IsNaN(point.Y) ||
- double.IsInfinity(point.X) || double.IsInfinity(point.Y))
- {
- LogManager.Warning($"[垂直扫描处理器] 无效的坐标点: ({point.X}, {point.Y}, {point.Z})");
- return new HashSet(); // 返回空集合
- }
-
- // 使用粗粒度的缓存键(基于空间哈希桶坐标)
- int gridX = (int)Math.Floor(point.X / _spatialHashSize);
- int gridY = (int)Math.Floor(point.Y / _spatialHashSize);
- string cacheKey = $"{gridX},{gridY}";
-
- // 🔥 关键修复:使用ConcurrentDictionary的GetOrAdd原子操作
- var candidates = _candidateCache.GetOrAdd(cacheKey, key =>
- {
- // 这个函数只在缓存未命中时执行
- Interlocked.Increment(ref _cacheMisses);
-
- // 构建候选集合
- var items = new HashSet();
- var hashKeys = GetSpatialHashKeysForPoint(point);
-
- foreach (var hkey in hashKeys)
- {
- if (_spatialHashMap.TryGetValue(hkey, out var bucketItems))
- {
- items.UnionWith(bucketItems);
- }
- }
-
- // 检查缓存大小,如果超限则清空整个缓存
- if (_candidateCache.Count > _maxCacheSize)
- {
- _candidateCache.Clear();
- LogManager.Info($"[垂直扫描处理器] 缓存已满({_candidateCache.Count}>{_maxCacheSize}),清空缓存重新开始");
- }
-
- return items;
- });
-
- // 如果键已存在(GetOrAdd没有执行工厂函数),说明是缓存命中
- if (_candidateCache.ContainsKey(cacheKey))
- {
- Interlocked.Increment(ref _cacheHits);
- }
-
- // 🔥 关键修复:返回副本以保证线程安全,避免并发修改原HashSet
- return new HashSet(candidates);
- }
- catch (Exception ex)
- {
- LogManager.Error($"[垂直扫描处理器] 获取候选项失败: {ex.Message},点坐标: ({point.X}, {point.Y}, {point.Z})");
- return new HashSet(); // 返回空集合
- }
- }
-
-
-
- ///
- /// 第二级筛选:高度筛选
- ///
- /// 候选模型项
- /// 最小Z坐标
- /// 最大Z坐标
- /// 高度筛选后的模型项
- private List HeightFiltering(IEnumerable items, double minZ, double maxZ)
- {
- var filtered = new ConcurrentBag();
-
- try
- {
- // 使用ConcurrentBag避免锁竞争,提高性能和稳定性
- Parallel.ForEach(items, new ParallelOptions { MaxDegreeOfParallelism = _parallelDegree }, item =>
- {
- try
- {
- if (item?.HasGeometry == true)
- {
- var bbox = item.BoundingBox();
- if (bbox != null)
- {
- // 检查高度范围是否有重叠(加上容差)
- if (bbox.Max.Z >= (minZ - HEIGHT_TOLERANCE) &&
- bbox.Min.Z <= (maxZ + HEIGHT_TOLERANCE))
- {
- filtered.Add(item);
- }
- }
- }
- }
- catch (Exception ex)
- {
- LogManager.Debug($"[垂直扫描处理器] 高度筛选失败: {item?.DisplayName ?? "NULL"}, {ex.Message}");
- }
- });
- }
- catch (Exception ex)
- {
- LogManager.Warning($"[垂直扫描处理器] 高度筛选并行处理失败: {ex.Message},回退到串行处理");
-
- // 如果并行处理失败,使用串行处理
- foreach (var item in items ?? new List())
- {
- try
- {
- if (item?.HasGeometry == true)
- {
- var bbox = item.BoundingBox();
- if (bbox != null &&
- bbox.Max.Z >= (minZ - HEIGHT_TOLERANCE) &&
- bbox.Min.Z <= (maxZ + HEIGHT_TOLERANCE))
- {
- filtered.Add(item);
- }
- }
- }
- catch (Exception serialEx)
- {
- LogManager.Debug($"[垂直扫描处理器] 串行高度筛选失败: {item?.DisplayName ?? "NULL"}, {serialEx.Message}");
- }
- }
- }
-
- return filtered.ToList();
- }
-
- ///
- /// 第三级筛选:精确几何相交测试(空间哈希优化)
- ///
- /// 高度筛选后的模型项
- /// 基础点
- /// 扫描高度
- /// 相交测试结果
- private List PerformIntersectionTests(List items, Point3D basePoint, double scanHeight)
- {
- var results = new ConcurrentBag();
-
- try
- {
- // 并行执行相交测试,添加更强的异常处理
- Parallel.ForEach(items, new ParallelOptions { MaxDegreeOfParallelism = _parallelDegree }, item =>
- {
- try
- {
- if (item != null)
- {
- var intersectionData = TestVerticalLineIntersection(item, basePoint, scanHeight);
- if (intersectionData != null)
- {
- // 简化逻辑:所有与垂直射线相交的非通道元素都视为障碍物
- // 因为在空间哈希构建时已经排除了通道元素
- results.Add(new IntersectionResult
- {
- ModelItem = item,
- IntersectionData = intersectionData,
- IsObstacle = true, // 所有相交的非通道元素都是障碍物
- IsPassable = false // 不可通行
- });
- }
- }
- }
- catch (Exception ex)
- {
- LogManager.Debug($"【垂直扫描处理器】 相交测试失败: {item?.DisplayName ?? "NULL"}, {ex.Message}");
- }
- });
- }
- catch (Exception ex)
- {
- LogManager.Warning($"【垂直扫描处理器】 并行相交测试失败: {ex.Message},回退到串行处理");
-
- // 如果并行处理失败,使用串行处理
- foreach (var item in items ?? new List())
- {
- try
- {
- if (item != null)
- {
- var intersectionData = TestVerticalLineIntersection(item, basePoint, scanHeight);
- if (intersectionData != null)
- {
- // 简化逻辑:所有与垂直射线相交的非通道元素都视为障碍物
- results.Add(new IntersectionResult
- {
- ModelItem = item,
- IntersectionData = intersectionData,
- IsObstacle = true, // 所有相交的非通道元素都是障碍物
- IsPassable = false // 不可通行
- });
- }
- }
- }
- catch (Exception serialEx)
- {
- LogManager.Debug($"【垂直扫描处理器】 串行相交测试失败: {item?.DisplayName ?? "NULL"}, {serialEx.Message}");
- }
- }
- }
-
- return results.ToList();
- }
-
- ///
- /// 计算可通行区间
- ///
- /// 相交测试结果
- /// 基础Z坐标
- /// 扫描高度
- /// 车辆高度
- /// 可通行区间
- private HeightInterval CalculatePassableInterval(
- List intersectionResults,
- double baseZ,
- double scanHeight,
- double vehicleHeight)
- {
-
- // 收集所有障碍物的高度范围
- var obstacles = new List();
- var floors = new List();
-
- foreach (var result in intersectionResults)
- {
- if (result.IsObstacle && result.IntersectionData != null)
- {
- var obstacleInterval = new HeightInterval(
- result.IntersectionData.MinZ,
- result.IntersectionData.MaxZ
- );
- obstacles.Add(obstacleInterval);
- }
- else if (result.IsPassable && result.IntersectionData != null)
- {
- // 检查是否为地面/楼板
- if (IsFloorLike(result.ModelItem, result.IntersectionData))
- {
- var floorInterval = new HeightInterval(
- result.IntersectionData.MinZ,
- result.IntersectionData.MaxZ
- );
- floors.Add(floorInterval);
- }
- }
- }
-
- // 合并重叠的障碍物区间
- var mergedObstacles = MergeOverlappingIntervals(obstacles);
-
- // 计算最优可通行区间(取最大的一个)
- HeightInterval bestInterval = new HeightInterval();
- var scanRange = new HeightInterval(baseZ, baseZ + scanHeight);
-
- // 如果没有找到地面,使用基础Z坐标作为默认地面
- if (!floors.Any())
- {
- floors.Add(new HeightInterval(baseZ - 0.1, baseZ + 0.1));
- }
-
- // 对每个潜在的地面,计算其上方的可通行空间,取最大的
- foreach (var floor in floors)
- {
- double floorTop = floor.MaxZ;
- double availableTop = baseZ + scanHeight;
-
- // 检查地面上方是否有足够的净空高度
- var conflictingObstacles = mergedObstacles
- .Where(obs => obs.MinZ < availableTop && obs.MaxZ > floorTop)
- .OrderBy(obs => obs.MinZ)
- .ToList();
-
- if (!conflictingObstacles.Any())
- {
- // 没有障碍物,整个高度范围都可通行
- double clearHeight = availableTop - floorTop;
-
- if (clearHeight >= MIN_PASSABLE_HEIGHT)
- {
- var interval = new HeightInterval(floorTop, availableTop);
- if (interval.MaxZ - interval.MinZ > bestInterval.MaxZ - bestInterval.MinZ)
- {
- bestInterval = interval;
- }
- }
- }
- else
- {
- // 有障碍物,计算障碍物之间的可通行空间,取最大的
- double currentBottom = floorTop;
-
- foreach (var obstacle in conflictingObstacles)
- {
- double obstacleBottom = Math.Max(obstacle.MinZ, currentBottom);
-
- if (obstacleBottom > currentBottom)
- {
- double clearHeight = obstacleBottom - currentBottom;
-
- if (clearHeight >= vehicleHeight)
- {
- var interval = new HeightInterval(currentBottom, obstacleBottom);
- if (interval.MaxZ - interval.MinZ > bestInterval.MaxZ - bestInterval.MinZ)
- {
- bestInterval = interval;
- }
- }
- }
-
- currentBottom = Math.Max(currentBottom, obstacle.MaxZ);
- }
-
- // 检查最后一个障碍物之后的空间
- if (currentBottom < availableTop)
- {
- double clearHeight = availableTop - currentBottom;
-
- if (clearHeight >= vehicleHeight)
- {
- var interval = new HeightInterval(currentBottom, availableTop);
- if (interval.MaxZ - interval.MinZ > bestInterval.MaxZ - bestInterval.MinZ)
- {
- bestInterval = interval;
- }
- }
- }
- }
- }
-
- return bestInterval;
- }
-
- #endregion
-
- #region 私有辅助方法
-
- ///
- /// 检查边界框是否在指定范围内
- ///
- /// 要检查的边界框
- /// 范围边界框
- /// 是否在范围内
- private bool IsWithinBounds(BoundingBox3D bbox, BoundingBox3D bounds)
- {
- return bbox.Max.X >= bounds.Min.X && bbox.Min.X <= bounds.Max.X &&
- bbox.Max.Y >= bounds.Min.Y && bbox.Min.Y <= bounds.Max.Y &&
- bbox.Max.Z >= bounds.Min.Z && bbox.Min.Z <= bounds.Max.Z;
- }
-
- ///
- /// 获取边界框的所有空间哈希键
- ///
- /// 边界框
- /// 空间哈希键列表
- private List GetSpatialHashKeys(BoundingBox3D bbox)
- {
- var keys = new List();
-
- int minX = (int)Math.Floor(bbox.Min.X / _spatialHashSize);
- int maxX = (int)Math.Floor(bbox.Max.X / _spatialHashSize);
- int minY = (int)Math.Floor(bbox.Min.Y / _spatialHashSize);
- int maxY = (int)Math.Floor(bbox.Max.Y / _spatialHashSize);
-
- for (int x = minX; x <= maxX; x++)
- {
- for (int y = minY; y <= maxY; y++)
- {
- keys.Add($"{x},{y}");
- }
- }
-
- return keys;
- }
-
- ///
- /// 获取点的空间哈希键(包括相邻网格)
- ///
- /// 查询点
- /// 空间哈希键列表
- private List GetSpatialHashKeysForPoint(Point3D point)
- {
- var keys = new List();
- int centerX = (int)Math.Floor(point.X / _spatialHashSize);
- int centerY = (int)Math.Floor(point.Y / _spatialHashSize);
-
- // 单桶模式
- keys.Add($"{centerX},{centerY}");
-
- // 智能查询范围策略:根据空间哈希大小调整查询桶数量
- // - 哈希桶<1.5m:只查询中心桶(1个)
- // - 哈希桶1.5-3m:查询十字形(5个桶)
- // - 哈希桶>3m:查询3x3(9个桶)
-
- // if (_spatialHashSize < 1.5)
- // {
- // // 单桶模式 - 对于很小的哈希桶,相邻桶基本不会有相关模型
- // keys.Add($"{centerX},{centerY}");
- // }
- // else if (_spatialHashSize < 3.0)
- // {
- // // 5个桶模式(十字形)- 只查询上下左右和中心
- // keys.Add($"{centerX},{centerY}");
- // keys.Add($"{centerX-1},{centerY}");
- // keys.Add($"{centerX+1},{centerY}");
- // keys.Add($"{centerX},{centerY-1}");
- // keys.Add($"{centerX},{centerY+1}");
- // }
- // else
- // {
- // // 9个桶模式(3x3)- 原有方式,用于较大的哈希桶
- // for (int dx = -1; dx <= 1; dx++)
- // {
- // for (int dy = -1; dy <= 1; dy++)
- // {
- // keys.Add($"{centerX + dx},{centerY + dy}");
- // }
- // }
- // }
-
- return keys;
- }
-
- ///
- /// 测试垂直线与模型项的相交
- ///
- /// 模型项
- /// 基础点
- /// 扫描高度
- /// 相交数据,如果不相交则返回null
- private IntersectionData TestVerticalLineIntersection(ModelItem item, Point3D basePoint, double scanHeight)
- {
- try
- {
- if (!item.HasGeometry)
- return null;
-
- // 直接提取模型项的三角形几何数据
- var triangles = GeometryHelper.ExtractTriangles(item);
- if (triangles == null || triangles.Count == 0)
- {
- return null;
- }
-
- // 执行射线-三角形相交检测
- var intersections = PerformVerticalRayIntersection(basePoint, scanHeight, triangles);
- if (intersections == null || intersections.Count == 0)
- {
- return null;
- }
-
- // 计算相交的Z范围
- double minZ = intersections.Min();
- double maxZ = intersections.Max();
-
- // 确保相交区间与扫描区间有重叠
- double scanMinZ = basePoint.Z;
- double scanMaxZ = basePoint.Z + scanHeight;
-
- double intersectionMinZ = Math.Max(minZ, scanMinZ);
- double intersectionMaxZ = Math.Min(maxZ, scanMaxZ);
-
- if (intersectionMaxZ > intersectionMinZ)
- {
- return new IntersectionData
- {
- MinZ = intersectionMinZ,
- MaxZ = intersectionMaxZ,
- IntersectionPoint = new Point3D(basePoint.X, basePoint.Y, (intersectionMinZ + intersectionMaxZ) / 2)
- };
- }
-
- return null;
- }
- catch (Exception ex)
- {
- LogManager.Debug($"【垂直扫描处理器】 射线相交测试异常: {item.DisplayName}, {ex.Message}");
- return null;
- }
- }
-
- ///
- /// 执行垂直射线与三角形相交检测
- ///
- /// 射线起点
- /// 扫描高度
- /// 三角形列表
- /// 相交点Z坐标列表
- private List PerformVerticalRayIntersection(Point3D basePoint, double scanHeight, List triangles)
- {
- var intersectionPoints = new List();
-
- try
- {
- // 创建垂直向上的射线(从basePoint开始向上扫描scanHeight距离)
- var rayOrigin = new Point3D(basePoint.X, basePoint.Y, basePoint.Z);
- var rayDirection = new Point3D(0, 0, 1); // 向上
-
- foreach (var triangle in triangles)
- {
- if (GeometryHelper.RayTriangleIntersect(rayOrigin, rayDirection, triangle, out double intersectionZ))
- {
- // 检查相交点是否在扫描范围内
- if (intersectionZ >= basePoint.Z && intersectionZ <= basePoint.Z + scanHeight)
- {
- intersectionPoints.Add(intersectionZ);
- }
- }
- }
-
- return intersectionPoints;
- }
- catch (Exception ex)
- {
- LogManager.Debug($"【垂直扫描处理器】 射线-三角形相交计算失败: {ex.Message}");
- return intersectionPoints;
- }
- }
-
-
- ///
- /// 检查模型项是否类似地面/楼板
- ///
- /// 模型项
- /// 相交数据
- /// 是否为地面类型
- private bool IsFloorLike(ModelItem item, IntersectionData intersectionData)
- {
- string displayName = item.DisplayName?.ToLower() ?? "";
-
- // 通过名称判断
- string[] floorKeywords = {
- "地面", "floor", "楼板", "slab", "板", "deck",
- "地板", "flooring", "基础", "foundation"
- };
-
- foreach (string keyword in floorKeywords)
- {
- if (displayName.Contains(keyword))
- {
- return true;
- }
- }
-
- // 通过几何特征判断(薄的水平结构)
- double thickness = intersectionData.MaxZ - intersectionData.MinZ;
- return thickness < 0.5; // 小于50cm厚度认为是楼板
- }
-
- ///
- /// 合并重叠的区间
- ///
- /// 区间列表
- /// 合并后的区间列表
- private List MergeOverlappingIntervals(List intervals)
- {
- if (!intervals.Any())
- return new List();
-
- var sortedIntervals = intervals.OrderBy(i => i.MinZ).ToList();
- var merged = new List();
-
- var current = sortedIntervals[0];
- for (int i = 1; i < sortedIntervals.Count; i++)
- {
- var next = sortedIntervals[i];
-
- if (next.MinZ <= current.MaxZ + HEIGHT_TOLERANCE)
- {
- // 合并重叠区间
- current = new HeightInterval(current.MinZ, Math.Max(current.MaxZ, next.MaxZ));
- }
- else
- {
- merged.Add(current);
- current = next;
- }
- }
- merged.Add(current);
-
- return merged;
- }
-
- ///
- /// 检查指定的ModelItem是否为通道集合中任意一个通道的子节点
- ///
- /// 要检查的ModelItem
- /// 通道集合
- /// 如果是通道的子节点则返回true
- private bool IsChildOfChannelItems(ModelItem item, HashSet channelItemsSet)
- {
- try
- {
- if (item?.Parent == null)
- return false;
-
- // 递归向上检查父节点链
- var currentParent = item.Parent;
- while (currentParent != null)
- {
- if (channelItemsSet.Contains(currentParent))
- {
- return true; // 找到了通道父节点
- }
- currentParent = currentParent.Parent;
- }
-
- return false;
- }
- catch (Exception ex)
- {
- LogManager.Debug($"【垂直扫描处理器】 检查子节点关系时出错: {item?.DisplayName ?? "NULL"}, {ex.Message}");
- return false; // 出错时保守处理,不排除
- }
- }
-
- #endregion
-
- #region 内部数据结构
-
- ///
- /// 相交数据结构
- ///
- private class IntersectionData
- {
- public double MinZ { get; set; }
- public double MaxZ { get; set; }
- public Point3D IntersectionPoint { get; set; }
- }
-
- ///
- /// 相交测试结果
- ///
- private class IntersectionResult
- {
- public ModelItem ModelItem { get; set; }
- public IntersectionData IntersectionData { get; set; }
- public bool IsObstacle { get; set; }
- public bool IsPassable { get; set; }
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
index 1714109..3e84b9c 100644
--- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
+++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
@@ -501,6 +501,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
///
private void InitializeAnimationSettings()
{
+ // 从配置加载动画参数
+ var config = NavisworksTransport.Core.Config.ConfigManager.Instance.Current;
+
// 初始化可用帧率
AvailableFrameRates.Clear();
var frameRates = new[] { 15, 24, 30, 60 };
@@ -508,10 +511,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
AvailableFrameRates.Add(rate);
}
- SelectedFrameRate = 30; // 默认30fps
- // 设置默认动画参数
- AnimationDuration = 10.0;
+ // 从配置读取帧率
+ SelectedFrameRate = config.Animation.FrameRate;
+
+ // 从配置读取动画持续时间
+ AnimationDuration = config.Animation.DurationSeconds;
// 设置初始状态 - 修改: 默认状态应该是未激活,等待有效动画
CanPauseAnimation = false;
@@ -520,16 +525,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 初始化碰撞检测状态
HasCollisionResults = false;
UpdateMainStatus("碰撞检测就绪");
-
- // 初始化碰撞检测参数
- DetectionGap = 0.05; // 0.05米
- AnimationFrameRate = 30; // 30FPS
+
+ // 从配置读取碰撞检测参数
+ DetectionGap = config.Animation.DetectionGapMeters;
+ AnimationFrameRate = config.Animation.FrameRate;
// 注意:CollisionDetectionAccuracy(步长)和MovementSpeed(速度)现在是计算属性,不需要设置初始值
// 修改: 使用新的按钮状态更新方法来设置正确的初始状态
UpdateAnimationButtonStates();
- LogManager.Info("动画设置初始化完成");
+ LogManager.Info($"动画设置初始化完成 - 帧率:{SelectedFrameRate}fps, 持续时间:{AnimationDuration}秒, 检测间隙:{DetectionGap}米");
}
///
diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
index 9eebedf..65c1c39 100644
--- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs
+++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
@@ -11,6 +11,7 @@ using System.IO;
using Microsoft.Win32;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Core;
+using NavisworksTransport.Core.Config;
using NavisworksTransport.UI.WPF.Collections;
using NavisworksTransport.UI.WPF.Models;
using NavisworksTransport.UI.WPF.Commands;
@@ -73,7 +74,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private double _vehicleLength = 1.0; // 车辆长度(米)
private double _vehicleWidth = 1.0; // 车辆宽度(米)
private double _vehicleHeight = 2.0; // 车辆高度(米)
- private double _safetyMargin = 0.25; // 安全间隙(米)
+ private double _safetyMargin = 0.05; // 安全间隙(米)
// 网格大小参数
private bool _isGridSizeManuallyEnabled = false; // 是否启用手动网格大小设置
@@ -481,50 +482,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#region 构造函数
- public PathEditingViewModel() : base()
- {
- try
- {
- _uiStateManager = UIStateManager.Instance;
- _pathDataManager = new PathDataManager();
- // 不在构造函数中创建PathPlanningManager,由外部设置
- _pathPlanningManager = null;
-
- if (_uiStateManager == null)
- {
- throw new InvalidOperationException("UIStateManager初始化失败");
- }
-
- // PathPlanningManager将在外部设置,这里不需要检查
-
- // 初始化集合
- PathRoutes = new ObservableCollection();
-
- // 初始化路径策略选项
- InitializePathStrategyOptions();
-
- // 初始化命令
- InitializeCommands();
-
- // 初始化车辆参数同步(在PathPointRenderPlugin实例不为空时才同步)
- // 如果PathPointRenderPlugin尚未初始化,将在属性变更时自动同步
- SyncVehicleParametersToRenderPlugin();
-
- // 注意:不在这里订阅PathPlanningManager事件,
- // 因为PathPlanningManager还没有设置,事件订阅在PathPlanningManager属性setter中处理
-
- LogManager.Info("PathEditingViewModel构造函数执行完成,已迁移原有业务逻辑");
- }
- catch (Exception ex)
- {
- LogManager.Error($"PathEditingViewModel构造函数异常: {ex.Message}", ex);
- UpdateMainStatus("初始化失败,请检查日志");
- throw;
- }
- }
-
///
- /// 带主ViewModel参数的构造函数,支持统一状态栏
+ /// 构造函数,需要传入主ViewModel以支持统一状态栏
///
/// 主ViewModel,用于统一状态栏
public PathEditingViewModel(LogisticsControlViewModel mainViewModel) : base()
@@ -551,7 +510,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 初始化路径策略选项
InitializePathStrategyOptions();
-
+
+ // 从配置加载参数
+ LoadParametersFromConfig();
+
// 初始化命令
InitializeCommands();
@@ -607,6 +569,31 @@ namespace NavisworksTransport.UI.WPF.ViewModels
_selectedPathStrategy = _pathStrategyOptions.FirstOrDefault(x => x.Value == PathStrategy.Shortest);
}
+ ///
+ /// 从配置文件加载参数
+ ///
+ private void LoadParametersFromConfig()
+ {
+ try
+ {
+ var config = ConfigManager.Instance.Current;
+
+ // 从 PathEditing 配置加载所有参数
+ _gridSize = config.PathEditing.CellSizeMeters;
+ _vehicleLength = config.PathEditing.VehicleLengthMeters;
+ _vehicleWidth = config.PathEditing.VehicleWidthMeters;
+ _vehicleHeight = config.PathEditing.VehicleHeightMeters;
+ _safetyMargin = config.PathEditing.SafetyMarginMeters;
+
+ LogManager.Info($"从配置加载参数 - 车辆: {_vehicleLength}x{_vehicleWidth}x{_vehicleHeight}米, 安全间隙: {_safetyMargin}米, 网格: {_gridSize}米");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"加载配置参数失败: {ex.Message}", ex);
+ // 使用默认值,不抛出异常
+ }
+ }
+
private void InitializeCommands()
{
NewPathCommand = new RelayCommand(async () => await ExecuteNewPathAsync(), () => CanExecuteNewPath);
diff --git a/src/UI/WPF/Views/LogisticsControlPanel.xaml b/src/UI/WPF/Views/LogisticsControlPanel.xaml
index 0644871..3f12e0d 100644
--- a/src/UI/WPF/Views/LogisticsControlPanel.xaml
+++ b/src/UI/WPF/Views/LogisticsControlPanel.xaml
@@ -56,7 +56,7 @@ NavisworksTransport 主控制面板 - 采用与其他视图一致的Navisworks 2
-
+
diff --git a/src/UI/WPF/Views/LogisticsControlPanel.xaml.cs b/src/UI/WPF/Views/LogisticsControlPanel.xaml.cs
index 0047164..b039187 100644
--- a/src/UI/WPF/Views/LogisticsControlPanel.xaml.cs
+++ b/src/UI/WPF/Views/LogisticsControlPanel.xaml.cs
@@ -170,6 +170,11 @@ namespace NavisworksTransport.UI.WPF
}
}
+ ///
+ /// PathEditingView引用
+ ///
+ private PathEditingView PathEditingView;
+
///
/// 初始化PathEditingView
///
@@ -177,25 +182,29 @@ namespace NavisworksTransport.UI.WPF
{
try
{
- // 重新创建PathEditingView,传入主ViewModel引用
+ // 创建PathEditingView,传入主ViewModel引用
var newPathEditingView = new PathEditingView(ViewModel);
-
- // 替换XAML中的PathEditingView
- if (PathEditingTab?.Content is Border pathEditingBorder)
+
+ // 设置到ContentControl中
+ if (PathEditingContent != null)
{
- pathEditingBorder.Child = newPathEditingView;
-
+ PathEditingContent.Content = newPathEditingView;
+
// 更新引用
PathEditingView = newPathEditingView;
}
-
+
if (PathEditingView?.ViewModel != null)
{
// 将PathPlanningManager传递给PathEditingView
PathEditingView.ViewModel.PathPlanningManager = _pathPlanningManager;
-
+
LogManager.Info("PathEditingView初始化完成 - 支持统一状态栏");
}
+ else
+ {
+ LogManager.Error("PathEditingContent占位符未找到");
+ }
}
catch (Exception ex)
{
diff --git a/src/UI/WPF/Views/PathEditingView.xaml.cs b/src/UI/WPF/Views/PathEditingView.xaml.cs
index 714cce6..5141154 100644
--- a/src/UI/WPF/Views/PathEditingView.xaml.cs
+++ b/src/UI/WPF/Views/PathEditingView.xaml.cs
@@ -19,19 +19,8 @@ namespace NavisworksTransport.UI.WPF.Views
///
public PathEditingViewModel ViewModel { get; private set; }
- public PathEditingView()
- {
- InitializeComponent();
-
- // 创建并设置ViewModel
- ViewModel = new PathEditingViewModel();
- DataContext = ViewModel;
-
- LogManager.Info("PathEditingView初始化完成");
- }
-
///
- /// 带主ViewModel参数的构造函数,支持统一状态栏
+ /// 构造函数,需要传入主ViewModel以支持统一状态栏
///
/// 主ViewModel,用于统一状态栏
public PathEditingView(LogisticsControlViewModel mainViewModel)
diff --git a/src/Utils/CoordinateConverter.cs b/src/Utils/CoordinateConverter.cs
index b62090d..4c39364 100644
--- a/src/Utils/CoordinateConverter.cs
+++ b/src/Utils/CoordinateConverter.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Autodesk.Navisworks.Api;
+using NavisworksTransport.Core.Config;
namespace NavisworksTransport
{
@@ -17,7 +18,24 @@ namespace NavisworksTransport
private double _zoomFactor = 1.0;
private double _offsetX = 0.0;
private double _offsetY = 0.0;
- private const double _marginRatio = 0.1; // 10%边距
+
+ ///
+ /// 获取地图边距比例(从配置读取)
+ ///
+ private double MarginRatio
+ {
+ get
+ {
+ try
+ {
+ return ConfigManager.Instance.Current.Visualization.MarginRatio;
+ }
+ catch
+ {
+ return 0.1; // 配置加载失败时使用默认值10%
+ }
+ }
+ }
///
/// 地图宽度(像素)
@@ -138,12 +156,13 @@ namespace NavisworksTransport
throw new ArgumentNullException(nameof(mapPoint));
// 计算可用的地图尺寸(减去边距)
- double availableWidth = _mapWidth * (1.0 - 2 * _marginRatio);
- double availableHeight = _mapHeight * (1.0 - 2 * _marginRatio);
+ double marginRatio = MarginRatio;
+ double availableWidth = _mapWidth * (1.0 - 2 * marginRatio);
+ double availableHeight = _mapHeight * (1.0 - 2 * marginRatio);
// 从地图坐标计算相对位置
- double relativeX = (mapPoint.X - _mapWidth * _marginRatio) / availableWidth;
- double relativeY = 1.0 - ((mapPoint.Y - _mapHeight * _marginRatio) / availableHeight); // Y轴翻转
+ double relativeX = (mapPoint.X - _mapWidth * marginRatio) / availableWidth;
+ double relativeY = 1.0 - ((mapPoint.Y - _mapHeight * marginRatio) / availableHeight); // Y轴翻转
// 转换为世界坐标
double worldX = _channelBounds.MinPoint.X + relativeX * (_channelBounds.MaxPoint.X - _channelBounds.MinPoint.X);
@@ -172,12 +191,13 @@ namespace NavisworksTransport
double relativeY = (worldPoint.Y - _channelBounds.MinPoint.Y) / worldHeight;
// 计算可用的地图尺寸(减去边距)
- double availableWidth = _mapWidth * (1.0 - 2 * _marginRatio);
- double availableHeight = _mapHeight * (1.0 - 2 * _marginRatio);
+ double marginRatio = MarginRatio;
+ double availableWidth = _mapWidth * (1.0 - 2 * marginRatio);
+ double availableHeight = _mapHeight * (1.0 - 2 * marginRatio);
// 转换为地图像素坐标
- double mapX = relativeX * availableWidth + _mapWidth * _marginRatio;
- double mapY = (1.0 - relativeY) * availableHeight + _mapHeight * _marginRatio; // Y轴翻转
+ double mapX = relativeX * availableWidth + _mapWidth * marginRatio;
+ double mapY = (1.0 - relativeY) * availableHeight + _mapHeight * marginRatio; // Y轴翻转
// 确保坐标在地图范围内
mapX = Math.Max(0, Math.Min(_mapWidth, mapX));
diff --git a/src/Utils/FloorDetector.cs b/src/Utils/FloorDetector.cs
index d091598..756e0fd 100644
--- a/src/Utils/FloorDetector.cs
+++ b/src/Utils/FloorDetector.cs
@@ -10,19 +10,12 @@ namespace NavisworksTransport
///
public class FloorDetector
{
- #region 常量定义
-
- private const double DEFAULT_FLOOR_HEIGHT_THRESHOLD = 2.5; // 默认最小楼层高度(米)
- private const double DEFAULT_ELEVATION_TOLERANCE = 0.5; // 默认高程容差(米)
-
// 常见的楼层属性名称
private readonly string[] COMMON_FLOOR_ATTRIBUTES = {
"Level", "Floor", "Storey", "楼层", "层", "Level Name", "Story",
"Building Level", "Floor Level", "Elevation", "Z", "Height"
};
- #endregion
-
#region 公共方法
///
@@ -190,9 +183,6 @@ namespace NavisworksTransport
}
}
-
- // GetFloorByElevation方法已删除 - 性能优化:不再支持基于高程的楼层查找
-
///
/// 从给定的模型项集合中检测楼层信息 - 不进行深度遍历
///
@@ -346,7 +336,7 @@ namespace NavisworksTransport
{
try
{
- string floorValue = GetAttributeValue(item, attributeName);
+ string floorValue = CategoryAttributeManager.GetGeneralPropertyValueSafe(item, attributeName);
if (!string.IsNullOrEmpty(floorValue))
{
if (!floorGroups.ContainsKey(floorValue))
@@ -388,19 +378,6 @@ namespace NavisworksTransport
return floors.OrderBy(f => f.Elevation).ToList();
}
- private string GetAttributeValue(ModelItem item, string attributeName)
- {
- try
- {
- // 使用 CategoryAttributeManager 的安全属性获取方法,简化代码
- return CategoryAttributeManager.GetGeneralPropertyValueSafe(item, attributeName);
- }
- catch
- {
- return null;
- }
- }
-
#endregion