增加剖面盒基本功能;修改变量名车辆为物体
This commit is contained in:
parent
e4433ee073
commit
949c7ed6b5
@ -8,14 +8,14 @@ cell_size_meters = 0.5
|
||||
# 最大高度差(米)- 楼梯、坡道可接受的高度阈值
|
||||
max_height_diff_meters = 0.35
|
||||
|
||||
# 车辆长度(米)
|
||||
vehicle_length_meters = 1.5
|
||||
# 运动物体长度(米)
|
||||
object_length_meters = 1.5
|
||||
|
||||
# 车辆宽度(米)
|
||||
vehicle_width_meters = 1.0
|
||||
# 运动物体宽度(米)
|
||||
object_width_meters = 1.0
|
||||
|
||||
# 车辆高度(米)
|
||||
vehicle_height_meters = 2.0
|
||||
# 运动物体高度(米)
|
||||
object_height_meters = 2.0
|
||||
|
||||
# 安全间隙(米)
|
||||
safety_margin_meters = 0.1
|
||||
|
||||
@ -24,19 +24,19 @@ namespace NavisworksTransport.Commands
|
||||
public Point3D EndPoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 车辆长度(米)
|
||||
/// 运动物体长度(米)
|
||||
/// </summary>
|
||||
public double VehicleLength { get; set; } = 1.0;
|
||||
public double ObjectLength { get; set; } = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// 车辆宽度(米)
|
||||
/// 运动物体宽度(米)
|
||||
/// </summary>
|
||||
public double VehicleWidth { get; set; } = 1.0;
|
||||
public double ObjectWidth { get; set; } = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// 车辆高度(米)
|
||||
/// 运动物体高度(米)
|
||||
/// </summary>
|
||||
public double VehicleHeight { get; set; } = 2.0;
|
||||
public double ObjectHeight { get; set; } = 2.0;
|
||||
|
||||
/// <summary>
|
||||
/// 安全边距(米)
|
||||
@ -76,13 +76,13 @@ namespace NavisworksTransport.Commands
|
||||
if (EndPoint == null)
|
||||
errors.Add("终点不能为空");
|
||||
|
||||
if (VehicleLength <= 0 || VehicleLength > 20)
|
||||
if (ObjectLength <= 0 || ObjectLength > 20)
|
||||
errors.Add("车辆长度必须在0-20米之间");
|
||||
|
||||
if (VehicleWidth <= 0 || VehicleWidth > 10)
|
||||
if (ObjectWidth <= 0 || ObjectWidth > 10)
|
||||
errors.Add("车辆宽度必须在0-10米之间");
|
||||
|
||||
if (VehicleHeight <= 0 || VehicleHeight > 10)
|
||||
if (ObjectHeight <= 0 || ObjectHeight > 10)
|
||||
errors.Add("车辆高度必须在0-10米之间");
|
||||
|
||||
if (SafetyMargin < 0 || SafetyMargin > 5)
|
||||
@ -279,7 +279,7 @@ namespace NavisworksTransport.Commands
|
||||
var actualGridSize = _parameters.GridSize > 0 ? _parameters.GridSize : -1;
|
||||
LogInfo($"使用参数 - 起点: ({_parameters.StartPoint.X:F2}, {_parameters.StartPoint.Y:F2}), " +
|
||||
$"终点: ({_parameters.EndPoint.X:F2}, {_parameters.EndPoint.Y:F2}), " +
|
||||
$"车辆宽度: {_parameters.VehicleWidth}米, 安全边距: {_parameters.SafetyMargin}米, " +
|
||||
$"运动物体宽度: {_parameters.ObjectWidth}米, 安全边距: {_parameters.SafetyMargin}米, " +
|
||||
$"网格大小: {(actualGridSize > 0 ? $"用户设置 {actualGridSize:F2}米" : "自动选择")}");
|
||||
|
||||
// 第三阶段:执行路径规划(30% - 80%)
|
||||
@ -309,17 +309,17 @@ namespace NavisworksTransport.Commands
|
||||
};
|
||||
|
||||
// 计算车辆半径:基于长度和宽度的较大值的一半
|
||||
var vehicleRadius = Math.Max(_parameters.VehicleLength, _parameters.VehicleWidth) / 2.0;
|
||||
LogInfo($"使用车辆半径: {vehicleRadius}m(基于车辆长度{_parameters.VehicleLength}m和宽度{_parameters.VehicleWidth}m的较大值)");
|
||||
var objectRadius = Math.Max(_parameters.ObjectLength, _parameters.ObjectWidth) / 2.0;
|
||||
LogInfo($"使用运动物体半径: {objectRadius}m(基于长度{_parameters.ObjectLength}m和宽度{_parameters.ObjectWidth}m的较大值)");
|
||||
|
||||
// 调用PathPlanningManager的AutoPlanPath方法执行真实的A*算法
|
||||
var pathPlanTask = _pathPlanningManager.AutoPlanPath(
|
||||
startPathPoint,
|
||||
endPathPoint,
|
||||
vehicleRadius,
|
||||
objectRadius,
|
||||
_parameters.SafetyMargin,
|
||||
actualGridSize,
|
||||
_parameters.VehicleHeight, // 使用参数中的车辆高度
|
||||
_parameters.ObjectHeight, // 使用参数中的运动物体高度
|
||||
_parameters.Strategy); // 使用参数中指定的路径策略
|
||||
|
||||
generatedRoute = await pathPlanTask;
|
||||
@ -454,21 +454,21 @@ namespace NavisworksTransport.Commands
|
||||
/// </summary>
|
||||
/// <param name="startPoint">起点</param>
|
||||
/// <param name="endPoint">终点</param>
|
||||
/// <param name="vehicleSize">车辆尺寸(应用于长度和宽度)</param>
|
||||
/// <param name="objectSize">运动物体尺寸(应用于长度和宽度)</param>
|
||||
/// <param name="pathName">路径名称</param>
|
||||
/// <param name="vehicleHeight">车辆高度(可选,默认2.0米)</param>
|
||||
/// <param name="objectHeight">运动物体高度(可选,默认2.0米)</param>
|
||||
/// <param name="strategy">路径策略(可选,默认最短路径)</param>
|
||||
/// <returns>自动路径规划命令实例</returns>
|
||||
public static AutoPathPlanningCommand CreateQuick(Point3D startPoint, Point3D endPoint,
|
||||
double vehicleSize = 1.0, string pathName = null, double vehicleHeight = 2.0, PathStrategy strategy = PathStrategy.Shortest)
|
||||
double objectSize = 1.0, string pathName = null, double objectHeight = 2.0, PathStrategy strategy = PathStrategy.Shortest)
|
||||
{
|
||||
var parameters = new AutoPathPlanningParameters
|
||||
{
|
||||
StartPoint = startPoint,
|
||||
EndPoint = endPoint,
|
||||
VehicleLength = vehicleSize,
|
||||
VehicleWidth = vehicleSize,
|
||||
VehicleHeight = vehicleHeight,
|
||||
ObjectLength = objectSize,
|
||||
ObjectWidth = objectSize,
|
||||
ObjectHeight = objectHeight,
|
||||
SafetyMargin = 0.5,
|
||||
GridSize = -1, // 自动选择
|
||||
PathName = pathName,
|
||||
@ -487,7 +487,7 @@ namespace NavisworksTransport.Commands
|
||||
{
|
||||
return $"自动路径规划命令 - 起点:({_parameters.StartPoint?.X:F1}, {_parameters.StartPoint?.Y:F1}), " +
|
||||
$"终点:({_parameters.EndPoint?.X:F1}, {_parameters.EndPoint?.Y:F1}), " +
|
||||
$"车辆尺寸:长{_parameters.VehicleLength}×宽{_parameters.VehicleWidth}×高{_parameters.VehicleHeight}米, " +
|
||||
$"运动物体尺寸:长{_parameters.ObjectLength}×宽{_parameters.ObjectWidth}×高{_parameters.ObjectHeight}米, " +
|
||||
$"状态:{Status}";
|
||||
}
|
||||
|
||||
|
||||
@ -160,7 +160,7 @@ namespace NavisworksTransport.Commands
|
||||
{
|
||||
StartPoint = startPoint,
|
||||
EndPoint = endPoint,
|
||||
VehicleWidth = args.Length > 2 && args[2] is double v ? v : 1.0,
|
||||
ObjectWidth = args.Length > 2 && args[2] is double v ? v : 1.0,
|
||||
SafetyMargin = args.Length > 3 && args[3] is double v1 ? v1 : 0.5,
|
||||
GridSize = args.Length > 4 && args[4] is double v2 ? v2 : -1,
|
||||
PathName = args.Length > 5 ? args[5]?.ToString() : null,
|
||||
@ -182,10 +182,10 @@ namespace NavisworksTransport.Commands
|
||||
if (startPoint == null || endPoint == null)
|
||||
throw new ArgumentException("起点和终点必须是 Point3D 类型");
|
||||
|
||||
var vehicleSize = args.Length > 2 && args[2] is double v ? v : 1.0;
|
||||
var objectSize = args.Length > 2 && args[2] is double v ? v : 1.0;
|
||||
var pathName = args.Length > 3 ? args[3]?.ToString() : null;
|
||||
|
||||
return AutoPathPlanningCommand.CreateQuick(startPoint, endPoint, vehicleSize, pathName);
|
||||
return AutoPathPlanningCommand.CreateQuick(startPoint, endPoint, objectSize, pathName);
|
||||
});
|
||||
|
||||
// 注册模拟路径规划命令(保留用于测试)- 暂时注释掉避免类型推断问题
|
||||
|
||||
@ -82,9 +82,9 @@ namespace NavisworksTransport.Commands
|
||||
|
||||
// 设置车辆参数(从配置获取)
|
||||
var config = ConfigManager.Instance.Current;
|
||||
route.MaxVehicleLength = config.PathEditing.VehicleLengthMeters;
|
||||
route.MaxVehicleWidth = config.PathEditing.VehicleWidthMeters;
|
||||
route.MaxVehicleHeight = config.PathEditing.VehicleHeightMeters;
|
||||
route.MaxObjectLength = config.PathEditing.ObjectLengthMeters;
|
||||
route.MaxObjectWidth = config.PathEditing.ObjectWidthMeters;
|
||||
route.MaxObjectHeight = config.PathEditing.ObjectHeightMeters;
|
||||
route.SafetyMargin = config.PathEditing.SafetyMarginMeters;
|
||||
|
||||
// 计算总长度
|
||||
|
||||
@ -17,22 +17,22 @@ namespace NavisworksTransport.Commands
|
||||
private readonly Document _document;
|
||||
private readonly double _cellSize;
|
||||
private readonly int _samplingRate;
|
||||
private readonly double _vehicleRadius;
|
||||
private readonly double _vehicleHeight;
|
||||
private readonly double _objectRadius;
|
||||
private readonly double _objectHeight;
|
||||
|
||||
public VoxelGridSDFTestCommand(
|
||||
Document document,
|
||||
double cellSize,
|
||||
int samplingRate,
|
||||
double vehicleRadius,
|
||||
double vehicleHeight)
|
||||
double objectRadius,
|
||||
double objectHeight)
|
||||
: base("VoxelGridSDFTest", "体素网格SDF测试", "使用签名距离场进行精确体素化")
|
||||
{
|
||||
_document = document ?? throw new ArgumentNullException(nameof(document));
|
||||
_cellSize = cellSize;
|
||||
_samplingRate = samplingRate;
|
||||
_vehicleRadius = vehicleRadius;
|
||||
_vehicleHeight = vehicleHeight;
|
||||
_objectRadius = objectRadius;
|
||||
_objectHeight = objectHeight;
|
||||
}
|
||||
|
||||
protected override PathPlanningResult ValidateParameters()
|
||||
@ -56,8 +56,8 @@ namespace NavisworksTransport.Commands
|
||||
{
|
||||
LogInfo("=== 开始体素网格 SDF 测试 ===");
|
||||
LogInfo($"体素大小: {_cellSize}米");
|
||||
LogInfo($"车辆半径: {_vehicleRadius}米");
|
||||
LogInfo($"车辆高度: {_vehicleHeight}米");
|
||||
LogInfo($"车辆半径: {_objectRadius}米");
|
||||
LogInfo($"车辆高度: {_objectHeight}米");
|
||||
LogInfo($"采样率: {_samplingRate}");
|
||||
|
||||
UpdateProgress(5, "正在获取模型空间范围...");
|
||||
@ -90,8 +90,8 @@ namespace NavisworksTransport.Commands
|
||||
var voxelGrid = generator.GenerateFromBIMWithSDF(
|
||||
spaceBounds,
|
||||
_cellSize,
|
||||
_vehicleRadius,
|
||||
_vehicleHeight,
|
||||
_objectRadius,
|
||||
_objectHeight,
|
||||
allModelItems);
|
||||
|
||||
LogInfo($"体素网格生成完成: {voxelGrid.SizeX}×{voxelGrid.SizeY}×{voxelGrid.SizeZ} = {voxelGrid.TotalVoxels} 个体素");
|
||||
|
||||
@ -15,24 +15,24 @@ namespace NavisworksTransport.Commands
|
||||
{
|
||||
private readonly Document _document;
|
||||
private readonly double _cellSize;
|
||||
private readonly double _vehicleRadius;
|
||||
private readonly double _vehicleHeight;
|
||||
private readonly double _objectRadius;
|
||||
private readonly double _objectHeight;
|
||||
private readonly Point3D _startPoint;
|
||||
private readonly Point3D _endPoint;
|
||||
|
||||
public VoxelPathFindingTestCommand(
|
||||
Document document,
|
||||
double cellSize,
|
||||
double vehicleRadius,
|
||||
double vehicleHeight,
|
||||
double objectRadius,
|
||||
double objectHeight,
|
||||
Point3D startPoint,
|
||||
Point3D endPoint)
|
||||
: base("VoxelPathFindingTest", "体素路径规划测试", "测试VoxelPathFinder的3D A*路径规划")
|
||||
{
|
||||
_document = document ?? throw new ArgumentNullException(nameof(document));
|
||||
_cellSize = cellSize;
|
||||
_vehicleRadius = vehicleRadius;
|
||||
_vehicleHeight = vehicleHeight;
|
||||
_objectRadius = objectRadius;
|
||||
_objectHeight = objectHeight;
|
||||
_startPoint = startPoint;
|
||||
_endPoint = endPoint;
|
||||
}
|
||||
@ -58,8 +58,8 @@ namespace NavisworksTransport.Commands
|
||||
{
|
||||
LogInfo("=== 开始体素路径规划测试 ===");
|
||||
LogInfo($"体素大小: {_cellSize}米");
|
||||
LogInfo($"车辆半径: {_vehicleRadius}米");
|
||||
LogInfo($"车辆高度: {_vehicleHeight}米");
|
||||
LogInfo($"车辆半径: {_objectRadius}米");
|
||||
LogInfo($"车辆高度: {_objectHeight}米");
|
||||
LogInfo($"起点: ({_startPoint.X:F2}, {_startPoint.Y:F2}, {_startPoint.Z:F2})");
|
||||
LogInfo($"终点: ({_endPoint.X:F2}, {_endPoint.Y:F2}, {_endPoint.Z:F2})");
|
||||
|
||||
@ -92,8 +92,8 @@ namespace NavisworksTransport.Commands
|
||||
var voxelGrid = generator.GenerateFromBIMWithSDF(
|
||||
spaceBounds,
|
||||
_cellSize,
|
||||
_vehicleRadius,
|
||||
_vehicleHeight,
|
||||
_objectRadius,
|
||||
_objectHeight,
|
||||
allModelItems);
|
||||
|
||||
LogInfo($"体素网格生成完成: {voxelGrid.SizeX}×{voxelGrid.SizeY}×{voxelGrid.SizeZ} = {voxelGrid.TotalVoxels:N0} 个体素");
|
||||
|
||||
@ -89,10 +89,11 @@ namespace NavisworksTransport.Core.Animation
|
||||
private static readonly Dictionary<string, List<AnimationFrame>> _animationFrameCache = new Dictionary<string, List<AnimationFrame>>(); // 动画帧缓存
|
||||
private static readonly Dictionary<string, List<CollisionResult>> _collisionResultCache = new Dictionary<string, List<CollisionResult>>(); // 碰撞结果缓存
|
||||
private ModelItem _animatedObject;
|
||||
private bool _isVirtualVehicle = false; // 是否使用虚拟车辆
|
||||
private double _virtualVehicleLength = 0; // 虚拟车辆长度(米)
|
||||
private double _virtualVehicleWidth = 0; // 虚拟车辆宽度(米)
|
||||
private double _virtualVehicleHeight = 0; // 虚拟车辆高度(米)
|
||||
private bool _useVirtualObject = false; // 是否使用虚拟运动物体
|
||||
private double _virtualObjectLength = 0; // 虚拟运动物体长度(模型单位)
|
||||
private double _virtualObjectWidth = 0; // 虚拟运动物体宽度(模型单位)
|
||||
private double _virtualObjectHeight = 0; // 虚拟运动物体高度(模型单位)
|
||||
private bool _useSectionClip = true; // 是否使用剖面盒优化(默认启用)
|
||||
private List<Point3D> _pathPoints;
|
||||
private List<ModelItem> _manualCollisionTargets = new List<ModelItem>();
|
||||
private bool _manualCollisionOverrideEnabled = false;
|
||||
@ -350,7 +351,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
/// </summary>
|
||||
public void SyncToPathStart(ModelItem item, List<Point3D> points)
|
||||
{
|
||||
MoveVehicleToPathStart(item, points);
|
||||
MoveObjectToPathStart(item, points);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -364,16 +365,16 @@ namespace NavisworksTransport.Core.Animation
|
||||
var doc = NavisApplication.ActiveDocument;
|
||||
if (doc == null) return;
|
||||
|
||||
// 🔥 支持虚拟车辆的恢复
|
||||
// 🔥 支持虚拟物体的恢复
|
||||
ModelItem objectToRestore = null;
|
||||
bool isVirtual = _isVirtualVehicle;
|
||||
bool isVirtual = _useVirtualObject;
|
||||
|
||||
if (isVirtual)
|
||||
{
|
||||
objectToRestore = VirtualVehicleManager.Instance.CurrentVirtualVehicle;
|
||||
objectToRestore = VirtualObjectManager.Instance.CurrentVirtualObject;
|
||||
if (objectToRestore == null)
|
||||
{
|
||||
LogManager.Warning("[归位] 虚拟车辆未激活,跳过恢复");
|
||||
LogManager.Warning("[归位] 虚拟物体未激活,跳过恢复");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -403,7 +404,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
originalBoundingBox.Min.Z
|
||||
);
|
||||
|
||||
string objectName = isVirtual ? "虚拟车辆" : objectToRestore.DisplayName;
|
||||
string objectName = isVirtual ? "虚拟物体" : objectToRestore.DisplayName;
|
||||
LogManager.Info($"[归位] {objectName} 已彻底恢复到原始位置, yaw={_currentYaw:F3}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -429,18 +430,27 @@ namespace NavisworksTransport.Core.Animation
|
||||
public void SetAnimatedObject(ModelItem animatedObject)
|
||||
{
|
||||
_animatedObject = animatedObject;
|
||||
_isVirtualVehicle = (animatedObject == null);
|
||||
_useVirtualObject = (animatedObject == null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置虚拟车辆参数(批处理专用)
|
||||
/// 设置虚拟物体参数(批处理专用)
|
||||
/// </summary>
|
||||
public void SetVirtualVehicleParameters(bool isVirtualVehicle, double length, double width, double height)
|
||||
public void SetVirtualObjectParameters(bool useVirtualObject, double length, double width, double height)
|
||||
{
|
||||
_isVirtualVehicle = isVirtualVehicle;
|
||||
_virtualVehicleLength = length;
|
||||
_virtualVehicleWidth = width;
|
||||
_virtualVehicleHeight = height;
|
||||
_useVirtualObject = useVirtualObject;
|
||||
_virtualObjectLength = length;
|
||||
_virtualObjectWidth = width;
|
||||
_virtualObjectHeight = height;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置是否使用剖面盒优化
|
||||
/// </summary>
|
||||
public void SetUseSectionClip(bool useSectionClip)
|
||||
{
|
||||
_useSectionClip = useSectionClip;
|
||||
LogManager.Info($"[PathAnimationManager] 剖面盒优化已{(useSectionClip ? "启用" : "禁用")}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -561,18 +571,18 @@ namespace NavisworksTransport.Core.Animation
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将车辆移动到路径起点
|
||||
/// 将物体移动到路径起点
|
||||
/// </summary>
|
||||
/// <param name="animatedObject">动画对象(可选,如果不提供则使用当前的_animatedObject)</param>
|
||||
/// <param name="pathPoints">路径点(可选,如果不提供则使用当前的_pathPoints)</param>
|
||||
public void MoveVehicleToPathStart(ModelItem animatedObject = null, List<Point3D> pathPoints = null)
|
||||
public void MoveObjectToPathStart(ModelItem animatedObject = null, List<Point3D> pathPoints = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 🔥 重要:先恢复物体到原始状态(CAD位置和原始朝向),确保每次计算都从相同的状态开始
|
||||
// 这样可以避免之前旋转导致的包围盒尺寸计算不准确的问题
|
||||
// 注意:也要处理虚拟车辆(_isVirtualVehicle为true时_animatedObject可能为null)
|
||||
if (_animatedObject != null || _isVirtualVehicle)
|
||||
// 注意:也要处理虚拟物体(_useVirtualObject为true时_animatedObject可能为null)
|
||||
if (_animatedObject != null || _useVirtualObject)
|
||||
{
|
||||
RestoreObjectToCADPosition();
|
||||
LogManager.Info($"[移动到起点] 已恢复物体到原始状态, _currentYaw={_currentYaw * 180 / Math.PI:F2}°");
|
||||
@ -586,7 +596,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
_originalCenter = animatedObject.BoundingBox().Center;
|
||||
_currentPosition = new Point3D(_originalCenter.X, _originalCenter.Y, animatedObject.BoundingBox().Min.Z);
|
||||
|
||||
// 统一逻辑:从当前 Transform 中提取实际朝向(无论虚拟车辆还是普通物体)
|
||||
// 统一逻辑:从当前 Transform 中提取实际朝向(无论虚拟物体还是普通物体)
|
||||
_currentYaw = ModelItemTransformHelper.GetYawFromTransform(_originalTransform);
|
||||
}
|
||||
|
||||
@ -636,19 +646,19 @@ namespace NavisworksTransport.Core.Animation
|
||||
if (_route?.PathType == PathType.Hoisting)
|
||||
{
|
||||
// 吊装路径:第一个路径点(起吊点)是地面位置,物体底面应该在这里
|
||||
// 不需要向下移动车辆高度
|
||||
// 不需要向下移动物体高度
|
||||
LogManager.Debug($"[移动到起点] 吊装路径:起吊点是地面位置,物体底面Z={startPosition.Z:F2}");
|
||||
}
|
||||
else if (_route?.PathType == PathType.Rail)
|
||||
{
|
||||
// 空轨路径:路径点是悬挂点,物体悬挂在下方
|
||||
double vehicleHeight = _animatedObject.BoundingBox().Max.Z - _animatedObject.BoundingBox().Min.Z;
|
||||
startPosition = new Point3D(startPosition.X, startPosition.Y, startPosition.Z - vehicleHeight);
|
||||
LogManager.Debug($"[移动到起点] 空轨路径调整: 悬挂点Z={_pathPoints[0].Z:F2}, 物体底面Z={startPosition.Z:F2}, 物体高度={vehicleHeight:F2}");
|
||||
double objectHeight = _animatedObject.BoundingBox().Max.Z - _animatedObject.BoundingBox().Min.Z;
|
||||
startPosition = new Point3D(startPosition.X, startPosition.Y, startPosition.Z - objectHeight);
|
||||
LogManager.Debug($"[移动到起点] 空轨路径调整: 悬挂点Z={_pathPoints[0].Z:F2}, 物体底面Z={startPosition.Z:F2}, 物体高度={objectHeight:F2}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 地面路径:points[0] 是地面位置,车辆底面应该在这里
|
||||
// 地面路径:points[0] 是地面位置,物体底面应该在这里
|
||||
LogManager.Debug($"[移动到起点] 地面路径: pos=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2})");
|
||||
}
|
||||
|
||||
@ -680,16 +690,16 @@ namespace NavisworksTransport.Core.Animation
|
||||
LogManager.Info($"实际物体位置: X={actualCenter.X:F2}, Y={actualCenter.Y:F2}, Z={actualCenter.Z:F2}");
|
||||
LogManager.Info($"实际物体朝向: {actualYaw * 180 / Math.PI:F2}度");
|
||||
}
|
||||
else if (_isVirtualVehicle)
|
||||
else if (_useVirtualObject)
|
||||
{
|
||||
var virtualVehicle = VirtualVehicleManager.Instance.CurrentVirtualVehicle;
|
||||
if (virtualVehicle != null)
|
||||
var virtualObject = VirtualObjectManager.Instance.CurrentVirtualObject;
|
||||
if (virtualObject != null)
|
||||
{
|
||||
var bbox = virtualVehicle.BoundingBox();
|
||||
var bbox = virtualObject.BoundingBox();
|
||||
var actualCenter = bbox.Center;
|
||||
var actualYaw = ModelItemTransformHelper.GetYawFromTransform(virtualVehicle.Transform);
|
||||
LogManager.Info($"虚拟车辆位置: X={actualCenter.X:F2}, Y={actualCenter.Y:F2}, Z={actualCenter.Z:F2}");
|
||||
LogManager.Info($"虚拟车辆朝向: {actualYaw * 180 / Math.PI:F2}度");
|
||||
var actualYaw = ModelItemTransformHelper.GetYawFromTransform(virtualObject.Transform);
|
||||
LogManager.Info($"虚拟物体位置: X={actualCenter.X:F2}, Y={actualCenter.Y:F2}, Z={actualCenter.Z:F2}");
|
||||
LogManager.Info($"虚拟物体朝向: {actualYaw * 180 / Math.PI:F2}度");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -708,11 +718,50 @@ namespace NavisworksTransport.Core.Animation
|
||||
{
|
||||
LogManager.Info("=== 使用路径预计算动画帧 ===");
|
||||
|
||||
// 🔥 设置剖面盒优化(根据配置)
|
||||
if (_useSectionClip && _route != null && _route.Points != null && _route.Points.Count > 0)
|
||||
{
|
||||
var pathPoints = _route.Points.Select(p => p.Position).ToList();
|
||||
|
||||
// 计算剖面盒边距(模型单位):物体尺寸 + 安全间隙
|
||||
double objectLength, objectWidth, objectHeight;
|
||||
|
||||
if (_useVirtualObject)
|
||||
{
|
||||
// 虚拟物体:使用预设尺寸
|
||||
objectLength = _virtualObjectLength;
|
||||
objectWidth = _virtualObjectWidth;
|
||||
objectHeight = _virtualObjectHeight;
|
||||
LogManager.Debug($"[预计算] 使用虚拟运动物体尺寸: {objectLength:F2} x {objectWidth:F2} x {objectHeight:F2} (模型单位)");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 真实运动物体:从包围盒获取尺寸
|
||||
var bbox = _animatedObject.BoundingBox();
|
||||
objectLength = bbox.Max.X - bbox.Min.X;
|
||||
objectWidth = bbox.Max.Y - bbox.Min.Y;
|
||||
objectHeight = bbox.Max.Z - bbox.Min.Z;
|
||||
LogManager.Debug($"[预计算] 使用真实运动物体尺寸: {objectLength:F2} x {objectWidth:F2} x {objectHeight:F2} (模型单位), 物体: {_animatedObject.DisplayName}");
|
||||
}
|
||||
|
||||
double maxObjectSize = Math.Max(Math.Max(objectLength, objectWidth), objectHeight);
|
||||
double margin = maxObjectSize + _safetyMargin;
|
||||
double heightMargin = objectHeight + _safetyMargin;
|
||||
|
||||
SectionClipHelper.SetClipBoxByPath(pathPoints, margin, heightMargin);
|
||||
LogManager.Info($"[预计算] 已启用剖面盒优化 - 运动物体最大尺寸: {maxObjectSize:F2}, 安全间隙: {_safetyMargin:F2}, 边距: {margin:F2}, 高度边距: {heightMargin:F2} (模型单位)");
|
||||
}
|
||||
else if (!_useSectionClip)
|
||||
{
|
||||
SectionClipHelper.ClearClipBox();
|
||||
LogManager.Info("[预计算] 已禁用剖面盒优化(性能对比测试模式)");
|
||||
}
|
||||
|
||||
// 🔥 重要:预计算前先将物体移动到起点位置
|
||||
if (_animatedObject != null && _route != null && _route.Points != null && _route.Points.Count > 0)
|
||||
{
|
||||
var pathPoints = _route.Points.Select(p => p.Position).ToList();
|
||||
MoveVehicleToPathStart(_animatedObject, pathPoints);
|
||||
MoveObjectToPathStart(_animatedObject, pathPoints);
|
||||
LogManager.Info("[预计算] 物体已移动到路径起点");
|
||||
}
|
||||
|
||||
@ -849,7 +898,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
LogManager.Info(spatialIndexManager.GetStatistics());
|
||||
|
||||
// 🔥 优化:使用AABB查询代替球形查询,查询范围更精确
|
||||
// 不再预计算球形半径,改为每帧计算车辆AABB + 安全间隙的搜索AABB
|
||||
// 不再预计算球形半径,改为每帧计算物体AABB + 安全间隙的搜索AABB
|
||||
LogManager.Info($"空间查询使用AABB模式,安全间隙: {_safetyMargin:F4}模型单位");
|
||||
}
|
||||
|
||||
@ -889,14 +938,14 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 计算朝向(使用当前线段的方向)
|
||||
yawRadians = Math.Atan2(p2.Y - p1.Y, p2.X - p1.X);
|
||||
|
||||
// 吊装路径:所有线段都使用水平吊运方向(与MoveVehicleToPathStart保持一致)
|
||||
// 吊装路径:所有线段都使用水平吊运方向(与MoveObjectToPathStart保持一致)
|
||||
if (_route.PathType == PathType.Hoisting)
|
||||
{
|
||||
yawRadians = Math.Atan2(_pathPoints[2].Y - _pathPoints[1].Y, _pathPoints[2].X - _pathPoints[1].X);
|
||||
}
|
||||
|
||||
// 🔥 空中路径:根据路径类型和线段索引调整物体位置
|
||||
double vehicleHeight = _animatedObject.BoundingBox().Max.Z - _animatedObject.BoundingBox().Min.Z;
|
||||
double objectHeight = _animatedObject.BoundingBox().Max.Z - _animatedObject.BoundingBox().Min.Z;
|
||||
|
||||
if (_route.PathType == PathType.Hoisting)
|
||||
{
|
||||
@ -919,25 +968,25 @@ namespace NavisworksTransport.Core.Animation
|
||||
|
||||
if (segmentIndex == firstSegment)
|
||||
{
|
||||
// 起吊段:从地面逐渐上升到悬挂点-车辆高度
|
||||
// 起吊段:从地面逐渐上升到悬挂点-物体高度
|
||||
// 进度0时(地面):物体底面在地面,不向下移动
|
||||
// 进度1时(悬挂点):物体顶面在悬挂点,物体底面=悬挂点-车辆高度
|
||||
double heightOffset = segmentProgress * vehicleHeight;
|
||||
// 进度1时(悬挂点):物体顶面在悬挂点,物体底面=悬挂点-物体高度
|
||||
double heightOffset = segmentProgress * objectHeight;
|
||||
framePosition = new Point3D(framePosition.X, framePosition.Y, framePosition.Z - heightOffset);
|
||||
LogManager.Debug($"[吊装路径-起吊段] 进度={segmentProgress:F2}, 高度偏移={heightOffset:F2}, 物体底面Z={framePosition.Z:F2}");
|
||||
}
|
||||
else if (segmentIndex > firstSegment && segmentIndex < lastSegment)
|
||||
{
|
||||
// 平移段(中间的所有线段):全程都是悬挂点,物体顶面在悬挂点
|
||||
framePosition = new Point3D(framePosition.X, framePosition.Y, framePosition.Z - vehicleHeight);
|
||||
framePosition = new Point3D(framePosition.X, framePosition.Y, framePosition.Z - objectHeight);
|
||||
LogManager.Debug($"[吊装路径-平移段] 线段{segmentIndex}, 进度={segmentProgress:F2}, 物体底面Z={framePosition.Z:F2}");
|
||||
}
|
||||
else if (segmentIndex == lastSegment)
|
||||
{
|
||||
// 下降段:从悬挂点-车辆高度逐渐下降到地面
|
||||
// 进度0时(悬挂点):物体顶面在悬挂点,物体底面=悬挂点-车辆高度
|
||||
// 下降段:从悬挂点-物体高度逐渐下降到地面
|
||||
// 进度0时(悬挂点):物体顶面在悬挂点,物体底面=悬挂点-物体高度
|
||||
// 进度1时(地面):物体底面在地面,不向下移动
|
||||
double heightOffset = (1 - segmentProgress) * vehicleHeight;
|
||||
double heightOffset = (1 - segmentProgress) * objectHeight;
|
||||
framePosition = new Point3D(framePosition.X, framePosition.Y, framePosition.Z - heightOffset);
|
||||
LogManager.Debug($"[吊装路径-下降段] 进度={segmentProgress:F2}, 高度偏移={heightOffset:F2}, 物体底面Z={framePosition.Z:F2}");
|
||||
}
|
||||
@ -946,8 +995,8 @@ namespace NavisworksTransport.Core.Animation
|
||||
{
|
||||
// 空轨路径:路径点是悬挂点,物体悬挂在下方
|
||||
// 物体顶面应该在路径点,所以物体底面 = 路径点 - 物体高度
|
||||
framePosition = new Point3D(framePosition.X, framePosition.Y, framePosition.Z - vehicleHeight);
|
||||
LogManager.Debug($"[空轨路径] 调整物体位置: 悬挂点Z={framePosition.Z + vehicleHeight:F2}, 物体底面Z={framePosition.Z:F2}");
|
||||
framePosition = new Point3D(framePosition.X, framePosition.Y, framePosition.Z - objectHeight);
|
||||
LogManager.Debug($"[空轨路径] 调整物体位置: 悬挂点Z={framePosition.Z + objectHeight:F2}, 物体底面Z={framePosition.Z:F2}");
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -994,30 +1043,30 @@ namespace NavisworksTransport.Core.Animation
|
||||
|
||||
// 虚拟碰撞检测
|
||||
|
||||
// 计算车辆包围盒相对于framePosition的偏移
|
||||
var currentVehicleBoundingBox = _animatedObject.BoundingBox();
|
||||
// 计算物体包围盒相对于framePosition的偏移
|
||||
var currentObjectBoundingBox = _animatedObject.BoundingBox();
|
||||
var originalCenter = new Point3D(
|
||||
(currentVehicleBoundingBox.Min.X + currentVehicleBoundingBox.Max.X) / 2,
|
||||
(currentVehicleBoundingBox.Min.Y + currentVehicleBoundingBox.Max.Y) / 2,
|
||||
(currentVehicleBoundingBox.Min.Z + currentVehicleBoundingBox.Max.Z) / 2
|
||||
(currentObjectBoundingBox.Min.X + currentObjectBoundingBox.Max.X) / 2,
|
||||
(currentObjectBoundingBox.Min.Y + currentObjectBoundingBox.Max.Y) / 2,
|
||||
(currentObjectBoundingBox.Min.Z + currentObjectBoundingBox.Max.Z) / 2
|
||||
);
|
||||
|
||||
// 计算偏移量(当前包围盒中心到framePosition的偏移)
|
||||
var offsetX = framePosition.X - originalCenter.X;
|
||||
var offsetY = framePosition.Y - originalCenter.Y;
|
||||
var offsetZ = framePosition.Z - currentVehicleBoundingBox.Min.Z; // Z方向:framePosition是底面,originalCenter是中心
|
||||
var offsetZ = framePosition.Z - currentObjectBoundingBox.Min.Z; // Z方向:framePosition是底面,originalCenter是中心
|
||||
|
||||
// 创建新的包围盒(将当前包围盒移动到framePosition)
|
||||
var virtualBoundingBox = new BoundingBox3D(
|
||||
new Point3D(
|
||||
currentVehicleBoundingBox.Min.X + offsetX,
|
||||
currentVehicleBoundingBox.Min.Y + offsetY,
|
||||
currentObjectBoundingBox.Min.X + offsetX,
|
||||
currentObjectBoundingBox.Min.Y + offsetY,
|
||||
framePosition.Z // 底面Z坐标
|
||||
),
|
||||
new Point3D(
|
||||
currentVehicleBoundingBox.Max.X + offsetX,
|
||||
currentVehicleBoundingBox.Max.Y + offsetY,
|
||||
framePosition.Z + (currentVehicleBoundingBox.Max.Z - currentVehicleBoundingBox.Min.Z) // 保持高度
|
||||
currentObjectBoundingBox.Max.X + offsetX,
|
||||
currentObjectBoundingBox.Max.Y + offsetY,
|
||||
framePosition.Z + (currentObjectBoundingBox.Max.Z - currentObjectBoundingBox.Min.Z) // 保持高度
|
||||
)
|
||||
);
|
||||
|
||||
@ -1034,7 +1083,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
else
|
||||
{
|
||||
// 🔥 优化:使用AABB查询代替球形查询,避免球体扩大的无效范围
|
||||
// 查询AABB = 车辆AABB + 安全间隙扩展
|
||||
// 查询AABB = 物体AABB + 安全间隙扩展
|
||||
var searchBounds = new BoundingBox3D(
|
||||
new Point3D(
|
||||
virtualBoundingBox.Min.X - _safetyMargin,
|
||||
@ -1088,12 +1137,12 @@ namespace NavisworksTransport.Core.Animation
|
||||
(virtualBoundingBox.Min.Y + virtualBoundingBox.Max.Y + colliderBox.Min.Y + colliderBox.Max.Y) / 4,
|
||||
(virtualBoundingBox.Min.Z + virtualBoundingBox.Max.Z + colliderBox.Min.Z + colliderBox.Max.Z) / 4
|
||||
),
|
||||
// 🔥 重要:记录虚拟车辆的包围盒中心,而不是底面中心
|
||||
// 🔥 重要:记录虚拟物体的包围盒中心,而不是底面中心
|
||||
// 原因:
|
||||
// 1. framePosition是路径点,代表车辆在地面上的位置(底面中心)
|
||||
// 1. framePosition是路径点,代表物体在地面上的位置(底面中心)
|
||||
// 2. ClashDetective移动逻辑使用包围盒中心进行定位
|
||||
// 3. 如果记录底面中心,ClashDetective会把包围盒中心移动到底面位置,导致车辆下沉半个高度
|
||||
// 4. 记录包围盒中心可以确保ClashDetective移动后的位置与预计算时的虚拟车辆位置一致
|
||||
// 3. 如果记录底面中心,ClashDetective会把包围盒中心移动到底面位置,导致物体下沉半个高度
|
||||
// 4. 记录包围盒中心可以确保ClashDetective移动后的位置与预计算时的虚拟物体位置一致
|
||||
Item1Position = new Point3D(
|
||||
framePosition.X,
|
||||
framePosition.Y,
|
||||
@ -1355,7 +1404,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
if (distanceToStart > 0.1 || yawDiff > 0.01)
|
||||
{
|
||||
LogManager.Info($"[动画开始] 物体不在起点,重置到起点: 距离={distanceToStart:F2}m, 角度差={yawDiff * 180 / Math.PI:F2}°");
|
||||
MoveVehicleToPathStart();
|
||||
MoveObjectToPathStart();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1423,10 +1472,10 @@ namespace NavisworksTransport.Core.Animation
|
||||
{
|
||||
var firstFrame = _animationFrames[0];
|
||||
|
||||
LogManager.Debug($"[动画开始] _currentYaw之前={_currentYaw * 180 / Math.PI:F2}度, _isVirtualVehicle={_isVirtualVehicle}");
|
||||
LogManager.Debug($"[动画开始] _currentYaw之前={_currentYaw * 180 / Math.PI:F2}度, _useVirtualObject={_useVirtualObject}");
|
||||
|
||||
// 🔥 确保物体在起点位置和朝向
|
||||
// 注意:MoveVehicleToPathStart 已在 StartAnimation 中调用,这里只是日志记录
|
||||
// 注意:MoveObjectToPathStart 已在 StartAnimation 中调用,这里只是日志记录
|
||||
LogManager.Debug($"[动画开始] 物体应在起点: pos=({firstFrame.Position.X:F2},{firstFrame.Position.Y:F2}), yaw={firstFrame.YawRadians:F3}rad");
|
||||
}
|
||||
else
|
||||
@ -1446,12 +1495,12 @@ namespace NavisworksTransport.Core.Animation
|
||||
ModelHighlightHelper.ClearCollisionHighlights();
|
||||
LogManager.Debug("[动画开始] 已清除所有碰撞高亮");
|
||||
|
||||
// 不再高亮车辆对象,保持原始外观(客户要求)
|
||||
// 不再高亮物体对象,保持原始外观(客户要求)
|
||||
// if (_animatedObject != null)
|
||||
// {
|
||||
// var vehicleItems = new List<ModelItem> { _animatedObject };
|
||||
// ModelHighlightHelper.HighlightItems(ModelHighlightHelper.AnimatedObjectCategory, vehicleItems);
|
||||
// LogManager.Debug("[动画开始] 已高亮车辆对象为绿色");
|
||||
// var animatedObjectItems = new List<ModelItem> { _animatedObject };
|
||||
// ModelHighlightHelper.HighlightItems(ModelHighlightHelper.AnimatedObjectCategory, animatedObjectItems);
|
||||
// LogManager.Debug("[动画开始] 已高亮物体对象为绿色");
|
||||
// }
|
||||
|
||||
// 启动动画播放
|
||||
@ -1572,7 +1621,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
_pausedProgress = 0.0; // 重置暂停进度
|
||||
_currentFrameIndex = 0; // 重置帧索引
|
||||
|
||||
// 清除所有高亮(包括车辆和碰撞)
|
||||
// 清除所有高亮(包括物体和碰撞)
|
||||
ModelHighlightHelper.ClearAllHighlights();
|
||||
LogManager.Info("动画停止:已清除所有高亮");
|
||||
|
||||
@ -1658,7 +1707,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 直接设置为完成状态,避免中间状态切换
|
||||
SetState(AnimationState.Finished);
|
||||
|
||||
// 清除所有高亮(包括车辆和碰撞)
|
||||
// 清除所有高亮(包括物体和碰撞)
|
||||
ModelHighlightHelper.ClearAllHighlights();
|
||||
LogManager.Info("动画完成:已清除所有高亮");
|
||||
|
||||
@ -1689,12 +1738,12 @@ namespace NavisworksTransport.Core.Animation
|
||||
_detectionTolerance,
|
||||
_currentRouteId,
|
||||
_animatedObject,
|
||||
_isVirtualVehicle,
|
||||
_useVirtualObject,
|
||||
_animationFrameRate,
|
||||
_animationDuration,
|
||||
_virtualVehicleLength,
|
||||
_virtualVehicleWidth,
|
||||
_virtualVehicleHeight,
|
||||
_virtualObjectLength,
|
||||
_virtualObjectWidth,
|
||||
_virtualObjectHeight,
|
||||
_pathPoints
|
||||
);
|
||||
}
|
||||
@ -1811,7 +1860,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 第二步:如果已经生成了动画路径,则重新对齐到起点(带旋转)
|
||||
if (_animationFrames != null && _animationFrames.Count > 0)
|
||||
{
|
||||
MoveVehicleToPathStart();
|
||||
MoveObjectToPathStart();
|
||||
LogManager.Info("已重新对齐到路径起点");
|
||||
}
|
||||
}
|
||||
@ -2809,15 +2858,15 @@ namespace NavisworksTransport.Core.Animation
|
||||
/// <param name="durationSeconds">动画持续时间(秒)</param>
|
||||
/// <param name="pathName">路径名称</param>
|
||||
/// <param name="routeId">路由ID</param>
|
||||
public void CreateAnimation(ModelItem animatedObject, List<Point3D> pathPoints, double durationSeconds = 10.0, string pathName = "未知路径", string routeId = null, bool isVirtualVehicle = false,
|
||||
double virtualVehicleLength = 0, double virtualVehicleWidth = 0, double virtualVehicleHeight = 0, double safetyMargin = 0)
|
||||
public void CreateAnimation(ModelItem animatedObject, List<Point3D> pathPoints, double durationSeconds = 10.0, string pathName = "未知路径", string routeId = null, bool useVirtualObject = false,
|
||||
double virtualObjectLength = 0, double virtualObjectWidth = 0, double virtualObjectHeight = 0, double safetyMargin = 0)
|
||||
{
|
||||
_pathName = pathName;
|
||||
_currentRouteId = routeId;
|
||||
_isVirtualVehicle = isVirtualVehicle; // 设置是否使用虚拟车辆
|
||||
_virtualVehicleLength = virtualVehicleLength; // 模型单位
|
||||
_virtualVehicleWidth = virtualVehicleWidth; // 模型单位
|
||||
_virtualVehicleHeight = virtualVehicleHeight; // 模型单位
|
||||
_useVirtualObject = useVirtualObject; // 设置是否使用虚拟运动物体
|
||||
_virtualObjectLength = virtualObjectLength; // 模型单位
|
||||
_virtualObjectWidth = virtualObjectWidth; // 模型单位
|
||||
_virtualObjectHeight = virtualObjectHeight; // 模型单位
|
||||
_safetyMargin = safetyMargin; // 模型单位
|
||||
_pathPoints = pathPoints;
|
||||
_animatedObject = animatedObject;
|
||||
@ -2829,14 +2878,14 @@ namespace NavisworksTransport.Core.Animation
|
||||
_originalCenter = animatedObject.BoundingBox().Center;
|
||||
_currentPosition = new Point3D(_originalCenter.X, _originalCenter.Y, animatedObject.BoundingBox().Min.Z);
|
||||
|
||||
// 保持当前的 _currentYaw(因为物体可能已经被 MoveVehicleToPathStart 旋转)
|
||||
// 保持当前的 _currentYaw(因为物体可能已经被 MoveObjectToPathStart 旋转)
|
||||
// 不要从 Transform 中提取,因为 Transform 返回的是原始值,不是当前值
|
||||
LogManager.Debug($"[CreateAnimation] 保持_currentYaw={_currentYaw * 180 / Math.PI:F2}度不变, _isVirtualVehicle={_isVirtualVehicle}");
|
||||
LogManager.Debug($"[CreateAnimation] 保持_currentYaw={_currentYaw * 180 / Math.PI:F2}度不变, _useVirtualObject={_useVirtualObject}");
|
||||
}
|
||||
|
||||
// 设置动画参数并预计算动画帧
|
||||
// 注意:物体应该在调用CreateAnimation之前已经通过MoveVehicleToPathStart旋转到起点
|
||||
LogManager.Debug($"[CreateAnimation开始] _currentYaw之前={_currentYaw * 180 / Math.PI:F2}度, _isVirtualVehicle={_isVirtualVehicle}");
|
||||
// 注意:物体应该在调用CreateAnimation之前已经通过MoveObjectToPathStart旋转到起点
|
||||
LogManager.Debug($"[CreateAnimation开始] _currentYaw之前={_currentYaw * 180 / Math.PI:F2}度, _useVirtualObject={_useVirtualObject}");
|
||||
SetupAnimation(animatedObject, durationSeconds, _route);
|
||||
LogManager.Debug($"[CreateAnimation结束] _currentYaw之后={_currentYaw * 180 / Math.PI:F2}度");
|
||||
// 设置动画状态为Ready(动画已生成,可以播放)
|
||||
@ -2858,7 +2907,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
try
|
||||
{
|
||||
// 重新计算并应用朝向
|
||||
MoveVehicleToPathStart();
|
||||
MoveObjectToPathStart();
|
||||
LogManager.Info($"[角度修正] 物体角度已更新: {_objectRotationCorrection:F1}°");
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -2930,7 +2979,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
}
|
||||
else
|
||||
{
|
||||
// 无碰撞:清除碰撞高亮(保留车辆高亮)
|
||||
// 无碰撞:清除碰撞高亮(保留物体高亮)
|
||||
ModelHighlightHelper.ClearCategory(ModelHighlightHelper.PrecomputeCollisionResultsCategory);
|
||||
LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 清除碰撞高亮");
|
||||
}
|
||||
@ -3131,10 +3180,10 @@ namespace NavisworksTransport.Core.Animation
|
||||
sb.Append($"|DetectionTolerance:{_detectionTolerance:F4}");
|
||||
sb.Append("|");
|
||||
|
||||
// 包含虚拟车辆尺寸(确保车辆尺寸改变时重新检测)
|
||||
// 使用传入的车辆尺寸参数,而不是从ConfigManager读取
|
||||
var vehicleSizeString = $"Vehicle:{_virtualVehicleLength:F2}x{_virtualVehicleWidth:F2}x{_virtualVehicleHeight:F2}";
|
||||
sb.Append(vehicleSizeString);
|
||||
// 包含虚拟物体尺寸(确保物体尺寸改变时重新检测)
|
||||
// 使用传入的物体尺寸参数,而不是从ConfigManager读取
|
||||
var objectSizeString = $"Object:{_virtualObjectLength:F2}x{_virtualObjectWidth:F2}x{_virtualObjectHeight:F2}";
|
||||
sb.Append(objectSizeString);
|
||||
sb.Append("|");
|
||||
|
||||
// 包含角度修正(确保角度修正改变时重新检测)
|
||||
|
||||
@ -398,19 +398,19 @@ namespace NavisworksTransport.Core
|
||||
|
||||
// 获取运动物体
|
||||
ModelItem animatedObject = null;
|
||||
bool isVirtualVehicle = item.IsVirtualVehicle;
|
||||
bool isVirtualObject = item.IsVirtualObject;
|
||||
|
||||
if (isVirtualVehicle)
|
||||
if (isVirtualObject)
|
||||
{
|
||||
// 使用现有的虚拟车辆,不创建和清理
|
||||
// ShowVirtualVehicle 会显示虚拟车辆并更新尺寸(如果已存在)
|
||||
VirtualVehicleManager.Instance.ShowVirtualVehicle(
|
||||
item.VirtualVehicleLength,
|
||||
item.VirtualVehicleWidth,
|
||||
item.VirtualVehicleHeight
|
||||
// ShowVirtualObject 会显示虚拟车辆并更新尺寸(如果已存在)
|
||||
VirtualObjectManager.Instance.ShowVirtualObject(
|
||||
item.VirtualObjectLength,
|
||||
item.VirtualObjectWidth,
|
||||
item.VirtualObjectHeight
|
||||
);
|
||||
|
||||
animatedObject = VirtualVehicleManager.Instance.CurrentVirtualVehicle;
|
||||
animatedObject = VirtualObjectManager.Instance.CurrentVirtualObject;
|
||||
|
||||
if (animatedObject == null)
|
||||
{
|
||||
@ -516,19 +516,19 @@ namespace NavisworksTransport.Core
|
||||
FrameRate = item.FrameRate,
|
||||
DurationSeconds = item.DurationSeconds,
|
||||
DetectionToleranceMeters = item.DetectionToleranceMeters,
|
||||
VirtualVehicleLength = item.VirtualVehicleLength,
|
||||
VirtualVehicleWidth = item.VirtualVehicleWidth,
|
||||
VirtualVehicleHeight = item.VirtualVehicleHeight,
|
||||
VirtualObjectLength = item.VirtualObjectLength,
|
||||
VirtualObjectWidth = item.VirtualObjectWidth,
|
||||
VirtualObjectHeight = item.VirtualObjectHeight,
|
||||
CollisionDetectionEnabled = true,
|
||||
ReportGenerationEnabled = true
|
||||
};
|
||||
var frames = _processor.PrecomputeFrames(
|
||||
pathRoute,
|
||||
animatedObject,
|
||||
isVirtualVehicle,
|
||||
config.VirtualVehicleLength,
|
||||
config.VirtualVehicleWidth,
|
||||
config.VirtualVehicleHeight,
|
||||
isVirtualObject,
|
||||
config.VirtualObjectLength,
|
||||
config.VirtualObjectWidth,
|
||||
config.VirtualObjectHeight,
|
||||
config.FrameRate,
|
||||
config.DurationSeconds,
|
||||
config.DetectionToleranceMeters,
|
||||
@ -555,12 +555,12 @@ namespace NavisworksTransport.Core
|
||||
pathRoute.Name,
|
||||
pathRoute.Id,
|
||||
animatedObject,
|
||||
isVirtualVehicle,
|
||||
isVirtualObject,
|
||||
item.FrameRate,
|
||||
item.DurationSeconds,
|
||||
item.VirtualVehicleLength,
|
||||
item.VirtualVehicleWidth,
|
||||
item.VirtualVehicleHeight,
|
||||
item.VirtualObjectLength,
|
||||
item.VirtualObjectWidth,
|
||||
item.VirtualObjectHeight,
|
||||
pathPoints
|
||||
);
|
||||
|
||||
|
||||
@ -26,10 +26,10 @@ namespace NavisworksTransport.Core.Collision
|
||||
public List<AnimationFrame> PrecomputeFrames(
|
||||
PathRoute route,
|
||||
ModelItem animatedObject,
|
||||
bool isVirtualVehicle,
|
||||
double virtualVehicleLength,
|
||||
double virtualVehicleWidth,
|
||||
double virtualVehicleHeight,
|
||||
bool isVirtualObject,
|
||||
double virtualObjectLength,
|
||||
double virtualObjectWidth,
|
||||
double virtualObjectHeight,
|
||||
int frameRate,
|
||||
double duration,
|
||||
double detectionGap,
|
||||
@ -43,7 +43,7 @@ namespace NavisworksTransport.Core.Collision
|
||||
// 设置动画管理器参数(但不触发UI操作)
|
||||
_animationManager.SetRoute(route);
|
||||
_animationManager.SetAnimatedObject(animatedObject);
|
||||
_animationManager.SetVirtualVehicleParameters(isVirtualVehicle, virtualVehicleLength, virtualVehicleWidth, virtualVehicleHeight);
|
||||
_animationManager.SetVirtualObjectParameters(isVirtualObject, virtualObjectLength, virtualObjectWidth, virtualObjectHeight);
|
||||
_animationManager.SetAnimationParameters(frameRate, duration, detectionGap);
|
||||
_animationManager.SetObjectRotationCorrectionDirect(objectRotationCorrection);
|
||||
|
||||
@ -75,12 +75,12 @@ namespace NavisworksTransport.Core.Collision
|
||||
string pathName,
|
||||
string routeId,
|
||||
ModelItem animatedObject,
|
||||
bool isVirtualVehicle,
|
||||
bool isVirtualObject,
|
||||
int frameRate,
|
||||
double duration,
|
||||
double virtualVehicleLength,
|
||||
double virtualVehicleWidth,
|
||||
double virtualVehicleHeight,
|
||||
double virtualObjectLength,
|
||||
double virtualObjectWidth,
|
||||
double virtualObjectHeight,
|
||||
List<Point3D> pathPoints = null)
|
||||
{
|
||||
try
|
||||
@ -93,12 +93,12 @@ namespace NavisworksTransport.Core.Collision
|
||||
detectionGap,
|
||||
routeId,
|
||||
animatedObject,
|
||||
isVirtualVehicle,
|
||||
isVirtualObject,
|
||||
frameRate,
|
||||
duration,
|
||||
virtualVehicleLength,
|
||||
virtualVehicleWidth,
|
||||
virtualVehicleHeight,
|
||||
virtualObjectLength,
|
||||
virtualObjectWidth,
|
||||
virtualObjectHeight,
|
||||
pathPoints
|
||||
);
|
||||
|
||||
|
||||
@ -206,8 +206,8 @@ namespace NavisworksTransport
|
||||
/// </summary>
|
||||
private void SaveClashDetectiveResultToDatabase(string routeId, List<CollisionResult> clashResults,
|
||||
int frameRate, double duration, double detectionGap,
|
||||
ModelItem animatedObject, bool isVirtualVehicle,
|
||||
double virtualVehicleLength, double virtualVehicleWidth, double virtualVehicleHeight,
|
||||
ModelItem animatedObject, bool isVirtualObject,
|
||||
double virtualObjectLength, double virtualObjectWidth, double virtualObjectHeight,
|
||||
int precomputedCollisionCount = 0)
|
||||
{
|
||||
try
|
||||
@ -217,24 +217,24 @@ namespace NavisworksTransport
|
||||
{
|
||||
// 获取动画对象名称和路径信息
|
||||
string animatedObjectName = "未知对象";
|
||||
int? vehicleModelIndex = null;
|
||||
string vehiclePathId = null;
|
||||
int? ObjectModelIndex = null;
|
||||
string ObjectPathId = null;
|
||||
|
||||
if (!isVirtualVehicle && animatedObject != null)
|
||||
if (!isVirtualObject && animatedObject != null)
|
||||
{
|
||||
animatedObjectName = ModelItemAnalysisHelper.GetSafeDisplayName(animatedObject);
|
||||
// 获取真实车辆的 PathId 信息
|
||||
var pathId = Application.ActiveDocument.Models.CreatePathId(animatedObject);
|
||||
vehicleModelIndex = pathId.ModelIndex;
|
||||
vehiclePathId = pathId.PathId;
|
||||
ObjectModelIndex = pathId.ModelIndex;
|
||||
ObjectPathId = pathId.PathId;
|
||||
}
|
||||
else if (isVirtualVehicle)
|
||||
else if (isVirtualObject)
|
||||
{
|
||||
animatedObjectName = "虚拟车辆";
|
||||
}
|
||||
|
||||
// 打印虚拟车辆尺寸(用于调试)
|
||||
LogManager.Info($"[SaveClashDetectiveResultToDatabase] IsVirtualVehicle={isVirtualVehicle}, 虚拟车辆尺寸: Length={virtualVehicleLength:F2}m, Width={virtualVehicleWidth:F2}m, Height={virtualVehicleHeight:F2}m");
|
||||
// 打印虚拟物体尺寸(用于调试)
|
||||
LogManager.Info($"[SaveClashDetectiveResultToDatabase] IsVirtualObject={isVirtualObject}, 虚拟物体尺寸: Length={virtualObjectLength:F2}m, Width={virtualObjectWidth:F2}m, Height={virtualObjectHeight:F2}m");
|
||||
|
||||
var record = new ClashDetectiveResultRecord
|
||||
{
|
||||
@ -247,16 +247,16 @@ namespace NavisworksTransport
|
||||
Duration = duration,
|
||||
DetectionGap = detectionGap,
|
||||
AnimatedObjectName = animatedObjectName,
|
||||
IsVirtualVehicle = isVirtualVehicle,
|
||||
VehicleModelIndex = vehicleModelIndex,
|
||||
VehiclePathId = vehiclePathId,
|
||||
VirtualVehicleLength = virtualVehicleLength,
|
||||
VirtualVehicleWidth = virtualVehicleWidth,
|
||||
VirtualVehicleHeight = virtualVehicleHeight,
|
||||
IsVirtualObject = isVirtualObject,
|
||||
ObjectModelIndex = ObjectModelIndex,
|
||||
ObjectPathId = ObjectPathId,
|
||||
VirtualObjectLength = virtualObjectLength,
|
||||
VirtualObjectWidth = virtualObjectWidth,
|
||||
VirtualObjectHeight = virtualObjectHeight,
|
||||
CreatedAt = DateTime.Now
|
||||
};
|
||||
var resultId = pathDatabase.SaveClashDetectiveResult(record);
|
||||
LogManager.Info($"ClashDetective结果已保存到数据库,Id={resultId}, IsVirtualVehicle={isVirtualVehicle}");
|
||||
LogManager.Info($"ClashDetective结果已保存到数据库,Id={resultId}, IsVirtualObject={isVirtualObject}");
|
||||
|
||||
// 保存被撞物体信息(只保存Item2,不保存车辆Item1)
|
||||
// 同时保存碰撞时运动物体的位置和朝向,用于还原碰撞场景
|
||||
@ -355,8 +355,8 @@ namespace NavisworksTransport
|
||||
|
||||
// 1. 从数据库读取测试信息(添加JOIN获取PathName)
|
||||
var testInfoSql = @"
|
||||
SELECT cdr.Id, pr.Name AS PathName, cdr.RouteId, cdr.IsVirtualVehicle, cdr.VehicleModelIndex, cdr.VehiclePathId,
|
||||
cdr.VirtualVehicleLength, cdr.VirtualVehicleWidth, cdr.VirtualVehicleHeight
|
||||
SELECT cdr.Id, pr.Name AS PathName, cdr.RouteId, cdr.IsVirtualObject, cdr.ObjectModelIndex, cdr.ObjectPathId,
|
||||
cdr.VirtualObjectLength, cdr.VirtualObjectWidth, cdr.VirtualObjectHeight
|
||||
FROM ClashDetectiveResults cdr
|
||||
INNER JOIN PathRoutes pr ON cdr.RouteId = pr.Id
|
||||
WHERE cdr.TestName = @testName
|
||||
@ -375,12 +375,12 @@ namespace NavisworksTransport
|
||||
Id = Convert.ToInt32(reader["Id"]),
|
||||
PathName = reader["PathName"].ToString(),
|
||||
RouteId = reader["RouteId"]?.ToString(),
|
||||
IsVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]),
|
||||
VehicleModelIndex = reader["VehicleModelIndex"] != DBNull.Value ? Convert.ToInt32(reader["VehicleModelIndex"]) : (int?)null,
|
||||
VehiclePathId = reader["VehiclePathId"] != DBNull.Value ? reader["VehiclePathId"].ToString() : null,
|
||||
VirtualVehicleLength = reader["VirtualVehicleLength"] != DBNull.Value ? Convert.ToDouble(reader["VirtualVehicleLength"]) : 0.0,
|
||||
VirtualVehicleWidth = reader["VirtualVehicleWidth"] != DBNull.Value ? Convert.ToDouble(reader["VirtualVehicleWidth"]) : 0.0,
|
||||
VirtualVehicleHeight = reader["VirtualVehicleHeight"] != DBNull.Value ? Convert.ToDouble(reader["VirtualVehicleHeight"]) : 0.0
|
||||
IsVirtualObject = Convert.ToBoolean(reader["IsVirtualObject"]),
|
||||
ObjectModelIndex = reader["ObjectModelIndex"] != DBNull.Value ? Convert.ToInt32(reader["ObjectModelIndex"]) : (int?)null,
|
||||
ObjectPathId = reader["ObjectPathId"] != DBNull.Value ? reader["ObjectPathId"].ToString() : null,
|
||||
VirtualObjectLength = reader["VirtualObjectLength"] != DBNull.Value ? Convert.ToDouble(reader["VirtualObjectLength"]) : 0.0,
|
||||
VirtualObjectWidth = reader["VirtualObjectWidth"] != DBNull.Value ? Convert.ToDouble(reader["VirtualObjectWidth"]) : 0.0,
|
||||
VirtualObjectHeight = reader["VirtualObjectHeight"] != DBNull.Value ? Convert.ToDouble(reader["VirtualObjectHeight"]) : 0.0
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -393,45 +393,45 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
// 2. 重建车辆对象
|
||||
ModelItem vehicleObject = null;
|
||||
if (testInfo.IsVirtualVehicle)
|
||||
ModelItem ObjectObject = null;
|
||||
if (testInfo.IsVirtualObject)
|
||||
{
|
||||
// 显示虚拟车辆
|
||||
var modelToMeters = UnitsConverter.GetUnitsToMetersConversionFactor();
|
||||
VirtualVehicleManager.Instance.ShowVirtualVehicle(
|
||||
testInfo.VirtualVehicleLength * modelToMeters,
|
||||
testInfo.VirtualVehicleWidth * modelToMeters,
|
||||
testInfo.VirtualVehicleHeight * modelToMeters
|
||||
VirtualObjectManager.Instance.ShowVirtualObject(
|
||||
testInfo.VirtualObjectLength * modelToMeters,
|
||||
testInfo.VirtualObjectWidth * modelToMeters,
|
||||
testInfo.VirtualObjectHeight * modelToMeters
|
||||
);
|
||||
vehicleObject = VirtualVehicleManager.Instance.CurrentVirtualVehicle
|
||||
ObjectObject = VirtualObjectManager.Instance.CurrentVirtualObject
|
||||
?? throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 显示虚拟车辆失败");
|
||||
}
|
||||
else if (testInfo.VehicleModelIndex.HasValue && !string.IsNullOrEmpty(testInfo.VehiclePathId))
|
||||
else if (testInfo.ObjectModelIndex.HasValue && !string.IsNullOrEmpty(testInfo.ObjectPathId))
|
||||
{
|
||||
// 通过 PathId 查找真实车辆
|
||||
try
|
||||
{
|
||||
var pathIdObj = new Autodesk.Navisworks.Api.DocumentParts.ModelItemPathId
|
||||
{
|
||||
ModelIndex = testInfo.VehicleModelIndex.Value,
|
||||
PathId = testInfo.VehiclePathId
|
||||
ModelIndex = testInfo.ObjectModelIndex.Value,
|
||||
PathId = testInfo.ObjectPathId
|
||||
};
|
||||
vehicleObject = Application.ActiveDocument.Models.ResolvePathId(pathIdObj) ?? throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 无法通过 PathId 找到车辆对象: ModelIndex={testInfo.VehicleModelIndex}, PathId={testInfo.VehiclePathId}");
|
||||
LogManager.Info($"[LoadClashDetectiveResultsFromDatabase] 已找到真实车辆: {ModelItemAnalysisHelper.GetSafeDisplayName(vehicleObject)}");
|
||||
ObjectObject = Application.ActiveDocument.Models.ResolvePathId(pathIdObj) ?? throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 无法通过 PathId 找到车辆对象: ModelIndex={testInfo.ObjectModelIndex}, PathId={testInfo.ObjectPathId}");
|
||||
LogManager.Info($"[LoadClashDetectiveResultsFromDatabase] 已找到真实车辆: {ModelItemAnalysisHelper.GetSafeDisplayName(ObjectObject)}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] ResolvePathId 失败: ModelIndex={testInfo.VehicleModelIndex}, PathId={testInfo.VehiclePathId}", ex);
|
||||
throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] ResolvePathId 失败: ModelIndex={testInfo.ObjectModelIndex}, PathId={testInfo.ObjectPathId}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (vehicleObject == null)
|
||||
if (ObjectObject == null)
|
||||
{
|
||||
throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 无法重建车辆对象: IsVirtualVehicle={testInfo.IsVirtualVehicle}, VehicleModelIndex={testInfo.VehicleModelIndex}, VehiclePathId={testInfo.VehiclePathId}");
|
||||
throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 无法重建车辆对象: IsVirtualObject={testInfo.IsVirtualObject}, ObjectModelIndex={testInfo.ObjectModelIndex}, ObjectPathId={testInfo.ObjectPathId}");
|
||||
}
|
||||
|
||||
// 如果是虚拟车辆,将其移动到路径起点
|
||||
if (testInfo.IsVirtualVehicle && !string.IsNullOrEmpty(testInfo.RouteId))
|
||||
if (testInfo.IsVirtualObject && !string.IsNullOrEmpty(testInfo.RouteId))
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -446,7 +446,7 @@ namespace NavisworksTransport
|
||||
|
||||
// 使用 PathAnimationManager 将车辆移动到起点
|
||||
var pathAnimationManager = PathAnimationManager.GetInstance();
|
||||
pathAnimationManager.MoveVehicleToPathStart(vehicleObject, new List<Point3D> { startPointPosition, startPointPosition });
|
||||
pathAnimationManager.MoveObjectToPathStart(ObjectObject, new List<Point3D> { startPointPosition, startPointPosition });
|
||||
LogManager.Info($"[LoadClashDetectiveResultsFromDatabase] 虚拟车辆已移动到路径起点: ({startPointPosition.X:F2}, {startPointPosition.Y:F2}, {startPointPosition.Z:F2})");
|
||||
}
|
||||
}
|
||||
@ -529,7 +529,7 @@ namespace NavisworksTransport
|
||||
ClashGuid = Guid.NewGuid(),
|
||||
DisplayName = $"历史碰撞: {collidedObjectName}",
|
||||
Status = ClashResultStatus.Active,
|
||||
Item1 = vehicleObject,
|
||||
Item1 = ObjectObject,
|
||||
Item2 = collidedObject,
|
||||
Center = collidedObject.BoundingBox().Center,
|
||||
Distance = 0.0,
|
||||
@ -669,12 +669,12 @@ namespace NavisworksTransport
|
||||
double detectionGap,
|
||||
string routeId,
|
||||
ModelItem animatedObject,
|
||||
bool isVirtualVehicle,
|
||||
bool isVirtualObject,
|
||||
int frameRate,
|
||||
double duration,
|
||||
double virtualVehicleLength,
|
||||
double virtualVehicleWidth,
|
||||
double virtualVehicleHeight,
|
||||
double virtualObjectLength,
|
||||
double virtualObjectWidth,
|
||||
double virtualObjectHeight,
|
||||
Progress progress = null,
|
||||
int precomputedCollisionCount = 0)
|
||||
{
|
||||
@ -738,10 +738,10 @@ namespace NavisworksTransport
|
||||
duration,
|
||||
detectionGap,
|
||||
animatedObject,
|
||||
isVirtualVehicle,
|
||||
virtualVehicleLength,
|
||||
virtualVehicleWidth,
|
||||
virtualVehicleHeight,
|
||||
isVirtualObject,
|
||||
virtualObjectLength,
|
||||
virtualObjectWidth,
|
||||
virtualObjectHeight,
|
||||
precomputedCollisionCount
|
||||
);
|
||||
|
||||
@ -1061,8 +1061,8 @@ namespace NavisworksTransport
|
||||
_clashDetectiveCollisionCount = clashResults.Count;
|
||||
|
||||
// 保存到数据库(使用去重后的结果)
|
||||
SaveClashDetectiveResultToDatabase(routeId, finalClashResults, frameRate, duration, detectionGap, animatedObject, isVirtualVehicle,
|
||||
virtualVehicleLength, virtualVehicleWidth, virtualVehicleHeight, precomputedCollisionCount);
|
||||
SaveClashDetectiveResultToDatabase(routeId, finalClashResults, frameRate, duration, detectionGap, animatedObject, isVirtualObject,
|
||||
virtualObjectLength, virtualObjectWidth, virtualObjectHeight, precomputedCollisionCount);
|
||||
|
||||
LogManager.Info($"[ClashDetective] 结果已保存到数据库");
|
||||
|
||||
@ -1077,24 +1077,24 @@ namespace NavisworksTransport
|
||||
/// <param name="detectionGap">检测间隙容差</param>
|
||||
/// <param name="routeId">路由ID</param>
|
||||
/// <param name="animatedObject">动画对象(如果是真实车辆)</param>
|
||||
/// <param name="isVirtualVehicle">是否使用虚拟车辆</param>
|
||||
/// <param name="isVirtualObject">是否使用虚拟物体</param>
|
||||
/// <param name="frameRate">帧率</param>
|
||||
/// <param name="duration">动画时长</param>
|
||||
/// <param name="virtualVehicleLength">虚拟车辆长度(米)</param>
|
||||
/// <param name="virtualVehicleWidth">虚拟车辆宽度(米)</param>
|
||||
/// <param name="virtualVehicleHeight">虚拟车辆高度(米)</param>
|
||||
/// <param name="virtualObjectLength">虚拟车辆长度(米)</param>
|
||||
/// <param name="virtualObjectWidth">虚拟车辆宽度(米)</param>
|
||||
/// <param name="virtualObjectHeight">虚拟车辆高度(米)</param>
|
||||
/// <param name="pathPoints">路径点列表(用于测试完成后恢复物体位置)</param>
|
||||
public void CreateAllAnimationCollisionTests(
|
||||
List<CollisionResult> precomputedCollisions,
|
||||
double detectionGap,
|
||||
string routeId,
|
||||
ModelItem animatedObject,
|
||||
bool isVirtualVehicle,
|
||||
bool isVirtualObject,
|
||||
int frameRate,
|
||||
double duration,
|
||||
double virtualVehicleLength,
|
||||
double virtualVehicleWidth,
|
||||
double virtualVehicleHeight,
|
||||
double virtualObjectLength,
|
||||
double virtualObjectWidth,
|
||||
double virtualObjectHeight,
|
||||
List<Point3D> pathPoints = null)
|
||||
{
|
||||
try
|
||||
@ -1137,12 +1137,12 @@ namespace NavisworksTransport
|
||||
detectionGap,
|
||||
routeId,
|
||||
animatedObject,
|
||||
isVirtualVehicle,
|
||||
isVirtualObject,
|
||||
frameRate,
|
||||
duration,
|
||||
virtualVehicleLength,
|
||||
virtualVehicleWidth,
|
||||
virtualVehicleHeight,
|
||||
virtualObjectLength,
|
||||
virtualObjectWidth,
|
||||
virtualObjectHeight,
|
||||
progress,
|
||||
precomputedCollisionCount
|
||||
);
|
||||
@ -1929,12 +1929,12 @@ namespace NavisworksTransport
|
||||
double detectionGap,
|
||||
string routeId,
|
||||
ModelItem animatedObject,
|
||||
bool isVirtualVehicle,
|
||||
bool isVirtualObject,
|
||||
int frameRate,
|
||||
double duration,
|
||||
double virtualVehicleLength,
|
||||
double virtualVehicleWidth,
|
||||
double virtualVehicleHeight,
|
||||
double virtualObjectLength,
|
||||
double virtualObjectWidth,
|
||||
double virtualObjectHeight,
|
||||
List<Point3D> pathPoints = null)
|
||||
{
|
||||
try
|
||||
@ -1953,12 +1953,12 @@ namespace NavisworksTransport
|
||||
detectionGap,
|
||||
routeId,
|
||||
animatedObject,
|
||||
isVirtualVehicle,
|
||||
isVirtualObject,
|
||||
frameRate,
|
||||
duration,
|
||||
virtualVehicleLength,
|
||||
virtualVehicleWidth,
|
||||
virtualVehicleHeight,
|
||||
virtualObjectLength,
|
||||
virtualObjectWidth,
|
||||
virtualObjectHeight,
|
||||
null,
|
||||
precomputedCollisionCount
|
||||
);
|
||||
@ -1987,7 +1987,7 @@ namespace NavisworksTransport
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// PathAnimationManager.GetInstance().MoveVehicleToPathStart(animatedObject, pathPoints);
|
||||
// PathAnimationManager.GetInstance().MoveObjectToPathStart(animatedObject, pathPoints);
|
||||
// LogManager.Info($"[批处理] 已将 {animatedObject.DisplayName} 恢复到路径起点位置");
|
||||
// }
|
||||
// catch (Exception restoreEx)
|
||||
|
||||
@ -15,11 +15,11 @@ namespace NavisworksTransport.Core.Collision
|
||||
/// 预计算动画帧和碰撞(纯计算,无UI操作)
|
||||
/// </summary>
|
||||
/// <param name="route">路径</param>
|
||||
/// <param name="animatedObject">动画对象(可为null,表示使用虚拟车辆)</param>
|
||||
/// <param name="isVirtualVehicle">是否使用虚拟车辆</param>
|
||||
/// <param name="virtualVehicleLength">虚拟车辆长度(米)</param>
|
||||
/// <param name="virtualVehicleWidth">虚拟车辆宽度(米)</param>
|
||||
/// <param name="virtualVehicleHeight">虚拟车辆高度(米)</param>
|
||||
/// <param name="animatedObject">动画对象(可为null,表示使用虚拟物体)</param>
|
||||
/// <param name="isVirtualObject">是否使用虚拟物体</param>
|
||||
/// <param name="virtualObjectLength">虚拟物体长度(米)</param>
|
||||
/// <param name="virtualObjectWidth">虚拟物体宽度(米)</param>
|
||||
/// <param name="virtualObjectHeight">虚拟物体高度(米)</param>
|
||||
/// <param name="frameRate">帧率</param>
|
||||
/// <param name="duration">持续时间(秒)</param>
|
||||
/// <param name="detectionGap">检测间隙(米)</param>
|
||||
@ -28,10 +28,10 @@ namespace NavisworksTransport.Core.Collision
|
||||
List<AnimationFrame> PrecomputeFrames(
|
||||
PathRoute route,
|
||||
ModelItem animatedObject,
|
||||
bool isVirtualVehicle,
|
||||
double virtualVehicleLength,
|
||||
double virtualVehicleWidth,
|
||||
double virtualVehicleHeight,
|
||||
bool isVirtualObject,
|
||||
double virtualObjectLength,
|
||||
double virtualObjectWidth,
|
||||
double virtualObjectHeight,
|
||||
int frameRate,
|
||||
double duration,
|
||||
double detectionGap,
|
||||
@ -46,13 +46,13 @@ namespace NavisworksTransport.Core.Collision
|
||||
/// <param name="detectionGap">检测间隙(米)</param>
|
||||
/// <param name="pathName">路径名称</param>
|
||||
/// <param name="routeId">路径ID</param>
|
||||
/// <param name="animatedObject">动画对象(可为null,表示使用虚拟车辆)</param>
|
||||
/// <param name="isVirtualVehicle">是否使用虚拟车辆</param>
|
||||
/// <param name="animatedObject">动画对象(可为null,表示使用虚拟物体)</param>
|
||||
/// <param name="isVirtualObject">是否使用虚拟物体</param>
|
||||
/// <param name="frameRate">帧率</param>
|
||||
/// <param name="duration">持续时间(秒)</param>
|
||||
/// <param name="virtualVehicleLength">虚拟车辆长度(米)</param>
|
||||
/// <param name="virtualVehicleWidth">虚拟车辆宽度(米)</param>
|
||||
/// <param name="virtualVehicleHeight">虚拟车辆高度(米)</param>
|
||||
/// <param name="virtualObjectLength">虚拟物体长度(米)</param>
|
||||
/// <param name="virtualObjectWidth">虚拟物体宽度(米)</param>
|
||||
/// <param name="virtualObjectHeight">虚拟物体高度(米)</param>
|
||||
/// <param name="pathPoints">路径点列表(用于测试完成后恢复物体位置)</param>
|
||||
/// <returns>ClashDetective测试名称</returns>
|
||||
string CreateAndRunClashDetectiveTest(
|
||||
@ -61,12 +61,12 @@ namespace NavisworksTransport.Core.Collision
|
||||
string pathName,
|
||||
string routeId,
|
||||
ModelItem animatedObject,
|
||||
bool isVirtualVehicle,
|
||||
bool isVirtualObject,
|
||||
int frameRate,
|
||||
double duration,
|
||||
double virtualVehicleLength,
|
||||
double virtualVehicleWidth,
|
||||
double virtualVehicleHeight,
|
||||
double virtualObjectLength,
|
||||
double virtualObjectWidth,
|
||||
double virtualObjectHeight,
|
||||
List<Point3D> pathPoints = null);
|
||||
}
|
||||
}
|
||||
@ -388,9 +388,9 @@ namespace NavisworksTransport.Core.Config
|
||||
// 使用带默认值的读取方法,不抛出异常
|
||||
config.PathEditing.CellSizeMeters = GetDoubleValueWithDefault(pathEdit, "cell_size_meters", 0.5, missingItems);
|
||||
config.PathEditing.MaxHeightDiffMeters = GetDoubleValueWithDefault(pathEdit, "max_height_diff_meters", 0.35, missingItems);
|
||||
config.PathEditing.VehicleLengthMeters = GetDoubleValueWithDefault(pathEdit, "vehicle_length_meters", 1.5, missingItems);
|
||||
config.PathEditing.VehicleWidthMeters = GetDoubleValueWithDefault(pathEdit, "vehicle_width_meters", 1.0, missingItems);
|
||||
config.PathEditing.VehicleHeightMeters = GetDoubleValueWithDefault(pathEdit, "vehicle_height_meters", 2.0, missingItems);
|
||||
config.PathEditing.ObjectLengthMeters = GetDoubleValueWithDefault(pathEdit, "object_length_meters", 1.5, missingItems);
|
||||
config.PathEditing.ObjectWidthMeters = GetDoubleValueWithDefault(pathEdit, "object_width_meters", 1.0, missingItems);
|
||||
config.PathEditing.ObjectHeightMeters = GetDoubleValueWithDefault(pathEdit, "object_height_meters", 2.0, missingItems);
|
||||
config.PathEditing.SafetyMarginMeters = GetDoubleValueWithDefault(pathEdit, "safety_margin_meters", 0.1, missingItems);
|
||||
config.PathEditing.DefaultPathTurnRadiusMeters = GetDoubleValueWithDefault(pathEdit, "default_path_turn_radius", 2.5, missingItems);
|
||||
config.PathEditing.ArcSamplingStepMeters = GetDoubleValueWithDefault(pathEdit, "arc_sampling_step", 0.05, missingItems);
|
||||
@ -613,9 +613,9 @@ namespace NavisworksTransport.Core.Config
|
||||
{
|
||||
pathEdit["cell_size_meters"] = config.PathEditing.CellSizeMeters;
|
||||
pathEdit["max_height_diff_meters"] = config.PathEditing.MaxHeightDiffMeters;
|
||||
pathEdit["vehicle_length_meters"] = config.PathEditing.VehicleLengthMeters;
|
||||
pathEdit["vehicle_width_meters"] = config.PathEditing.VehicleWidthMeters;
|
||||
pathEdit["vehicle_height_meters"] = config.PathEditing.VehicleHeightMeters;
|
||||
pathEdit["object_length_meters"] = config.PathEditing.ObjectLengthMeters;
|
||||
pathEdit["object_width_meters"] = config.PathEditing.ObjectWidthMeters;
|
||||
pathEdit["object_height_meters"] = config.PathEditing.ObjectHeightMeters;
|
||||
pathEdit["safety_margin_meters"] = config.PathEditing.SafetyMarginMeters;
|
||||
pathEdit["default_path_turn_radius"] = config.PathEditing.DefaultPathTurnRadiusMeters;
|
||||
pathEdit["arc_sampling_step"] = config.PathEditing.ArcSamplingStepMeters;
|
||||
@ -714,7 +714,7 @@ namespace NavisworksTransport.Core.Config
|
||||
|
||||
var newConfig = ParseTomlToConfig(templateContent);
|
||||
LogManager.Info($"解析后的配置 - CellSizeMeters: {newConfig.PathEditing.CellSizeMeters}");
|
||||
LogManager.Info($"解析后的配置 - VehicleLengthMeters: {newConfig.PathEditing.VehicleLengthMeters}");
|
||||
LogManager.Info($"解析后的配置 - ObjectLengthMeters: {newConfig.PathEditing.ObjectLengthMeters}");
|
||||
|
||||
_currentConfig = newConfig;
|
||||
|
||||
|
||||
@ -72,19 +72,19 @@ namespace NavisworksTransport.Core.Config
|
||||
public double MaxHeightDiffMeters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 车辆长度(米)
|
||||
/// 运动物体长度(米)
|
||||
/// </summary>
|
||||
public double VehicleLengthMeters { get; set; }
|
||||
public double ObjectLengthMeters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 车辆宽度(米)
|
||||
/// 运动物体宽度(米)
|
||||
/// </summary>
|
||||
public double VehicleWidthMeters { get; set; }
|
||||
public double ObjectWidthMeters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 车辆高度(米)
|
||||
/// 运动物体高度(米)
|
||||
/// </summary>
|
||||
public double VehicleHeightMeters { get; set; }
|
||||
public double ObjectHeightMeters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 安全间隙(米)
|
||||
@ -114,19 +114,19 @@ namespace NavisworksTransport.Core.Config
|
||||
public double MaxHeightDiff => MaxHeightDiffMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
|
||||
|
||||
/// <summary>
|
||||
/// 车辆长度(模型单位)
|
||||
/// 运动物体长度(模型单位)
|
||||
/// </summary>
|
||||
public double VehicleLength => VehicleLengthMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
|
||||
public double ObjectLength => ObjectLengthMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
|
||||
|
||||
/// <summary>
|
||||
/// 车辆宽度(模型单位)
|
||||
/// 运动物体宽度(模型单位)
|
||||
/// </summary>
|
||||
public double VehicleWidth => VehicleWidthMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
|
||||
public double ObjectWidth => ObjectWidthMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
|
||||
|
||||
/// <summary>
|
||||
/// 车辆高度(模型单位)
|
||||
/// 运动物体高度(模型单位)
|
||||
/// </summary>
|
||||
public double VehicleHeight => VehicleHeightMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
|
||||
public double ObjectHeight => ObjectHeightMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
|
||||
|
||||
/// <summary>
|
||||
/// 安全间隙(模型单位)
|
||||
|
||||
@ -387,8 +387,8 @@ namespace NavisworksTransport
|
||||
if (activeDoc != null && activeDoc.Models != null && activeDoc.Models.Count > 0)
|
||||
{
|
||||
LogManager.Info("[文档管理] 插件加载时发现包含模型的活动文档,立即初始化管理器");
|
||||
// 🔥 插件加载时不是虚拟车辆变化,传入 false
|
||||
InitializeManagers(isVirtualVehicleChange: false);
|
||||
// 🔥 插件加载时不是虚拟物体变化,传入 false
|
||||
InitializeManagers(isVirtualObjectChange: false);
|
||||
}
|
||||
else if (activeDoc != null)
|
||||
{
|
||||
@ -495,14 +495,14 @@ namespace NavisworksTransport
|
||||
LogManager.Warning($"[文档管理] 订阅新文档事件时出现警告: {ex.Message}");
|
||||
}
|
||||
|
||||
// 🔥 优化:检测是否是虚拟车辆引起的文档变化
|
||||
bool isVirtualVehicleChange = IsVirtualVehicleChange(activeDoc);
|
||||
if (isVirtualVehicleChange)
|
||||
// 🔥 优化:检测是否是虚拟物体引起的文档变化
|
||||
bool isVirtualObjectChange = IsVirtualObjectChange(activeDoc);
|
||||
if (isVirtualObjectChange)
|
||||
{
|
||||
LogManager.Info("[文档管理] 检测到虚拟车辆文档变化,使用快速初始化模式");
|
||||
LogManager.Info("[文档管理] 检测到虚拟物体文档变化,使用快速初始化模式");
|
||||
}
|
||||
|
||||
InitializeManagers(isVirtualVehicleChange);
|
||||
InitializeManagers(isVirtualObjectChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -513,29 +513,29 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测是否是虚拟车辆引起的文档变化
|
||||
/// 🔥 优化:通过 VirtualVehicleManager 的标志精确检测,避免误触发缓存重建
|
||||
/// 检测是否是虚拟物体引起的文档变化
|
||||
/// 🔥 优化:通过 VirtualObjectManager 的标志精确检测,避免误触发缓存重建
|
||||
/// </summary>
|
||||
private bool IsVirtualVehicleChange(Document doc)
|
||||
private bool IsVirtualObjectChange(Document doc)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 🔥 优先检查 VirtualVehicleManager 的更新标志(最准确)
|
||||
if (VirtualVehicleManager.Instance.IsUpdatingVirtualVehicle)
|
||||
// 🔥 优先检查 VirtualObjectManager 的更新标志(最准确)
|
||||
if (VirtualObjectManager.Instance.IsUpdatingVirtualObject)
|
||||
{
|
||||
LogManager.Debug("[文档管理] VirtualVehicleManager 正在更新,判定为虚拟车辆变化");
|
||||
LogManager.Debug("[文档管理] VirtualObjectManager 正在更新,判定为虚拟物体变化");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (doc?.Models == null) return false;
|
||||
|
||||
// 备选:检查是否包含虚拟车辆模型
|
||||
// 备选:检查是否包含虚拟物体模型
|
||||
foreach (var model in doc.Models)
|
||||
{
|
||||
var modelName = model.RootItem?.DisplayName ?? "";
|
||||
if (modelName.Contains("unit_cube") || modelName.Contains("VirtualVehicle"))
|
||||
if (modelName.Contains("unit_cube") || modelName.Contains("VirtualObject"))
|
||||
{
|
||||
LogManager.Debug($"[文档管理] 检测到虚拟车辆模型: {modelName}");
|
||||
LogManager.Debug($"[文档管理] 检测到虚拟物体模型: {modelName}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -544,7 +544,7 @@ namespace NavisworksTransport
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Debug($"[文档管理] 检测虚拟车辆变化时出错: {ex.Message}");
|
||||
LogManager.Debug($"[文档管理] 检测虚拟物体变化时出错: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -693,8 +693,8 @@ namespace NavisworksTransport
|
||||
/// <summary>
|
||||
/// 初始化各个管理器
|
||||
/// </summary>
|
||||
/// <param name="isVirtualVehicleChange">是否由虚拟车辆变化引起</param>
|
||||
private void InitializeManagers(bool isVirtualVehicleChange = false)
|
||||
/// <param name="isVirtualObjectChange">是否由虚拟物体变化引起</param>
|
||||
private void InitializeManagers(bool isVirtualObjectChange = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -713,10 +713,10 @@ namespace NavisworksTransport
|
||||
// 通知DocumentStateManager文档已就绪
|
||||
DocumentStateManager.Instance.OnDocumentReady();
|
||||
|
||||
// 🔥 优化:虚拟车辆变化时不清除缓存,避免80秒重建
|
||||
if (isVirtualVehicleChange)
|
||||
// 🔥 优化:虚拟物体变化时不清除缓存,避免80秒重建
|
||||
if (isVirtualObjectChange)
|
||||
{
|
||||
LogManager.Info("[文档管理] 检测到虚拟车辆变化,保留现有缓存,仅更新运动物体引用");
|
||||
LogManager.Info("[文档管理] 检测到虚拟物体变化,保留现有缓存,仅更新运动物体引用");
|
||||
// 只清除运动物体引用,不清除基础缓存
|
||||
ClashDetectiveIntegration.ClearAnimatedObject();
|
||||
}
|
||||
@ -811,15 +811,15 @@ namespace NavisworksTransport
|
||||
LogManager.Warning($"[文档管理] 清理Idle事件管理器时出现警告: {ex.Message}");
|
||||
}
|
||||
|
||||
// 清理虚拟车辆
|
||||
// 清理虚拟物体
|
||||
try
|
||||
{
|
||||
VirtualVehicleManager.Instance.Cleanup();
|
||||
LogManager.Info("[文档管理] 已清理虚拟车辆");
|
||||
VirtualObjectManager.Instance.Cleanup();
|
||||
LogManager.Info("[文档管理] 已清理虚拟物体");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[文档管理] 清理虚拟车辆时出现警告: {ex.Message}");
|
||||
LogManager.Warning($"[文档管理] 清理虚拟物体时出现警告: {ex.Message}");
|
||||
}
|
||||
|
||||
// 清除临时材质
|
||||
|
||||
@ -25,11 +25,11 @@ namespace NavisworksTransport.Core.Models
|
||||
public double DetectionToleranceMeters { get; set; }
|
||||
|
||||
// 运动物体配置
|
||||
public bool IsVirtualVehicle { get; set; }
|
||||
public double VirtualVehicleLength { get; set; }
|
||||
public double VirtualVehicleWidth { get; set; }
|
||||
public double VirtualVehicleHeight { get; set; }
|
||||
public string MovingObjectName { get; set; } // 运动物体名称,虚拟车辆时为 null
|
||||
public bool IsVirtualObject { get; set; }
|
||||
public double VirtualObjectLength { get; set; }
|
||||
public double VirtualObjectWidth { get; set; }
|
||||
public double VirtualObjectHeight { get; set; }
|
||||
public string MovingObjectName { get; set; } // 运动物体名称,虚拟物体时为 null
|
||||
|
||||
// 碰撞检测配置
|
||||
public bool DetectAllObjects { get; set; } = true;
|
||||
|
||||
@ -11,10 +11,10 @@ namespace NavisworksTransport.Core.Models
|
||||
public bool CollisionDetectionEnabled { get; set; }
|
||||
public bool ReportGenerationEnabled { get; set; }
|
||||
|
||||
// 虚拟车辆参数
|
||||
public double VirtualVehicleLength { get; set; }
|
||||
public double VirtualVehicleWidth { get; set; }
|
||||
public double VirtualVehicleHeight { get; set; }
|
||||
// 虚拟物体参数
|
||||
public double VirtualObjectLength { get; set; }
|
||||
public double VirtualObjectWidth { get; set; }
|
||||
public double VirtualObjectHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 序列化为JSON字符串(简化版)
|
||||
|
||||
@ -31,7 +31,7 @@ namespace NavisworksTransport
|
||||
/// <summary>
|
||||
/// JSON格式的车辆限制数据
|
||||
/// </summary>
|
||||
public class JsonVehicleLimits
|
||||
public class JsonObjectLimits
|
||||
{
|
||||
public double maxLength { get; set; }
|
||||
public double maxWidth { get; set; }
|
||||
@ -49,7 +49,7 @@ namespace NavisworksTransport
|
||||
public string description { get; set; }
|
||||
public string pathType { get; set; }
|
||||
public double totalLength { get; set; }
|
||||
public JsonVehicleLimits vehicleLimits { get; set; }
|
||||
public JsonObjectLimits ObjectLimits { get; set; }
|
||||
public double gridSize { get; set; }
|
||||
public double liftHeightMeters { get; set; }
|
||||
public string created { get; set; }
|
||||
@ -270,11 +270,11 @@ namespace NavisworksTransport
|
||||
description = route.Description ?? "",
|
||||
pathType = route.PathType.ToString(),
|
||||
totalLength = Math.Round(route.TotalLength, exportSettings?.Precision ?? 3),
|
||||
vehicleLimits = new
|
||||
ObjectLimits = new
|
||||
{
|
||||
maxLength = Math.Round(route.MaxVehicleLength, exportSettings?.Precision ?? 3),
|
||||
maxWidth = Math.Round(route.MaxVehicleWidth, exportSettings?.Precision ?? 3),
|
||||
maxHeight = Math.Round(route.MaxVehicleHeight, exportSettings?.Precision ?? 3),
|
||||
maxLength = Math.Round(route.MaxObjectLength, exportSettings?.Precision ?? 3),
|
||||
maxWidth = Math.Round(route.MaxObjectWidth, exportSettings?.Precision ?? 3),
|
||||
maxHeight = Math.Round(route.MaxObjectHeight, exportSettings?.Precision ?? 3),
|
||||
safetyMargin = Math.Round(route.SafetyMargin, exportSettings?.Precision ?? 3)
|
||||
},
|
||||
gridSize = Math.Round(route.GridSize, exportSettings?.Precision ?? 3),
|
||||
@ -476,10 +476,10 @@ namespace NavisworksTransport
|
||||
Id = jsonRoute.id,
|
||||
Description = jsonRoute.description ?? "",
|
||||
CreatedTime = ParseJsonDateTime(jsonRoute.created),
|
||||
MaxVehicleLength = jsonRoute.vehicleLimits?.maxLength ?? 0,
|
||||
MaxVehicleWidth = jsonRoute.vehicleLimits?.maxWidth ?? 0,
|
||||
MaxVehicleHeight = jsonRoute.vehicleLimits?.maxHeight ?? 0,
|
||||
SafetyMargin = jsonRoute.vehicleLimits?.safetyMargin ?? 0,
|
||||
MaxObjectLength = jsonRoute.ObjectLimits?.maxLength ?? 0,
|
||||
MaxObjectWidth = jsonRoute.ObjectLimits?.maxWidth ?? 0,
|
||||
MaxObjectHeight = jsonRoute.ObjectLimits?.maxHeight ?? 0,
|
||||
SafetyMargin = jsonRoute.ObjectLimits?.safetyMargin ?? 0,
|
||||
GridSize = jsonRoute.gridSize,
|
||||
LiftHeightMeters = jsonRoute.liftHeightMeters
|
||||
};
|
||||
@ -989,9 +989,9 @@ namespace NavisworksTransport
|
||||
routeElement.SetAttribute("description", route.Description ?? "");
|
||||
routeElement.SetAttribute("pathType", route.PathType.ToString());
|
||||
routeElement.SetAttribute("totalLength", route.TotalLength.ToString("F3"));
|
||||
routeElement.SetAttribute("maxVehicleLength", route.MaxVehicleLength.ToString("F3"));
|
||||
routeElement.SetAttribute("maxVehicleWidth", route.MaxVehicleWidth.ToString("F3"));
|
||||
routeElement.SetAttribute("maxVehicleHeight", route.MaxVehicleHeight.ToString("F3"));
|
||||
routeElement.SetAttribute("maxObjectLength", route.MaxObjectLength.ToString("F3"));
|
||||
routeElement.SetAttribute("maxObjectWidth", route.MaxObjectWidth.ToString("F3"));
|
||||
routeElement.SetAttribute("maxObjectHeight", route.MaxObjectHeight.ToString("F3"));
|
||||
routeElement.SetAttribute("safetyMargin", route.SafetyMargin.ToString("F3"));
|
||||
routeElement.SetAttribute("gridSize", route.GridSize.ToString("F3"));
|
||||
routeElement.SetAttribute("liftHeightMeters", route.LiftHeightMeters.ToString("F3"));
|
||||
@ -1112,9 +1112,9 @@ namespace NavisworksTransport
|
||||
Name = routeNode.Attributes?["name"]?.Value ?? "导入路径",
|
||||
Description = routeNode.Attributes?["description"]?.Value ?? "",
|
||||
PathType = pathType,
|
||||
MaxVehicleLength = double.TryParse(routeNode.Attributes?["maxVehicleLength"]?.Value, out double maxLength) ? maxLength : 0,
|
||||
MaxVehicleWidth = double.TryParse(routeNode.Attributes?["maxVehicleWidth"]?.Value, out double maxWidth) ? maxWidth : 0,
|
||||
MaxVehicleHeight = double.TryParse(routeNode.Attributes?["maxVehicleHeight"]?.Value, out double maxHeight) ? maxHeight : 0,
|
||||
MaxObjectLength = double.TryParse(routeNode.Attributes?["maxObjectLength"]?.Value, out double maxLength) ? maxLength : 0,
|
||||
MaxObjectWidth = double.TryParse(routeNode.Attributes?["maxObjectWidth"]?.Value, out double maxWidth) ? maxWidth : 0,
|
||||
MaxObjectHeight = double.TryParse(routeNode.Attributes?["maxObjectHeight"]?.Value, out double maxHeight) ? maxHeight : 0,
|
||||
SafetyMargin = double.TryParse(routeNode.Attributes?["safetyMargin"]?.Value, out double safetyMargin) ? safetyMargin : 0,
|
||||
GridSize = double.TryParse(routeNode.Attributes?["gridSize"]?.Value, out double gridSize) ? gridSize : 0,
|
||||
LiftHeightMeters = double.TryParse(routeNode.Attributes?["liftHeightMeters"]?.Value, out double liftHeight) ? liftHeight : 0
|
||||
@ -1212,13 +1212,13 @@ namespace NavisworksTransport
|
||||
pathElement.SetAttribute("length", route.TotalLength.ToString("F3"));
|
||||
|
||||
// 添加车辆限制元素
|
||||
var vehicleConstraints = xmlDoc.CreateElement("VehicleConstraints", _delmiaNamespace);
|
||||
vehicleConstraints.SetAttribute("maxLength", route.MaxVehicleLength.ToString("F3"));
|
||||
vehicleConstraints.SetAttribute("maxWidth", route.MaxVehicleWidth.ToString("F3"));
|
||||
vehicleConstraints.SetAttribute("maxHeight", route.MaxVehicleHeight.ToString("F3"));
|
||||
vehicleConstraints.SetAttribute("safetyMargin", route.SafetyMargin.ToString("F3"));
|
||||
vehicleConstraints.SetAttribute("gridSize", route.GridSize.ToString("F3"));
|
||||
pathElement.AppendChild(vehicleConstraints);
|
||||
var ObjectConstraints = xmlDoc.CreateElement("ObjectConstraints", _delmiaNamespace);
|
||||
ObjectConstraints.SetAttribute("maxLength", route.MaxObjectLength.ToString("F3"));
|
||||
ObjectConstraints.SetAttribute("maxWidth", route.MaxObjectWidth.ToString("F3"));
|
||||
ObjectConstraints.SetAttribute("maxHeight", route.MaxObjectHeight.ToString("F3"));
|
||||
ObjectConstraints.SetAttribute("safetyMargin", route.SafetyMargin.ToString("F3"));
|
||||
ObjectConstraints.SetAttribute("gridSize", route.GridSize.ToString("F3"));
|
||||
pathElement.AppendChild(ObjectConstraints);
|
||||
|
||||
// 添加路径段
|
||||
var segmentsElement = xmlDoc.CreateElement("Segments", _delmiaNamespace);
|
||||
|
||||
@ -62,6 +62,12 @@ namespace NavisworksTransport
|
||||
// 这样可以确保所有表都存在,避免在旧数据库中缺少新表的问题
|
||||
CreateTables();
|
||||
|
||||
// 执行数据库迁移(处理字段名变更等)
|
||||
if (!isNewDatabase)
|
||||
{
|
||||
RunMigrations();
|
||||
}
|
||||
|
||||
if (isNewDatabase)
|
||||
{
|
||||
LogManager.Info($"创建新数据库: {_dbPath}");
|
||||
@ -86,9 +92,9 @@ namespace NavisworksTransport
|
||||
EstimatedTime REAL,
|
||||
TurnRadius REAL,
|
||||
IsCurved INTEGER,
|
||||
MaxVehicleLength REAL,
|
||||
MaxVehicleWidth REAL,
|
||||
MaxVehicleHeight REAL,
|
||||
MaxObjectLength REAL,
|
||||
MaxObjectWidth REAL,
|
||||
MaxObjectHeight REAL,
|
||||
SafetyMargin REAL,
|
||||
GridSize REAL,
|
||||
PathType INTEGER,
|
||||
@ -184,12 +190,12 @@ namespace NavisworksTransport
|
||||
Duration REAL,
|
||||
DetectionGap REAL,
|
||||
AnimatedObjectName TEXT,
|
||||
IsVirtualVehicle INTEGER,
|
||||
VehicleModelIndex INTEGER,
|
||||
VehiclePathId TEXT,
|
||||
VirtualVehicleLength REAL,
|
||||
VirtualVehicleWidth REAL,
|
||||
VirtualVehicleHeight REAL,
|
||||
IsVirtualObject INTEGER,
|
||||
ObjectModelIndex INTEGER,
|
||||
ObjectPathId TEXT,
|
||||
VirtualObjectLength REAL,
|
||||
VirtualObjectWidth REAL,
|
||||
VirtualObjectHeight REAL,
|
||||
CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
");
|
||||
@ -260,10 +266,10 @@ namespace NavisworksTransport
|
||||
FrameRate INTEGER NOT NULL,
|
||||
DurationSeconds REAL NOT NULL,
|
||||
DetectionToleranceMeters REAL NOT NULL,
|
||||
IsVirtualVehicle INTEGER NOT NULL,
|
||||
VirtualVehicleLength REAL,
|
||||
VirtualVehicleWidth REAL,
|
||||
VirtualVehicleHeight REAL,
|
||||
IsVirtualObject INTEGER NOT NULL,
|
||||
VirtualObjectLength REAL,
|
||||
VirtualObjectWidth REAL,
|
||||
VirtualObjectHeight REAL,
|
||||
DetectAllObjects INTEGER NOT NULL DEFAULT 1,
|
||||
ClashDetectiveTestName TEXT,
|
||||
CollisionCount INTEGER,
|
||||
@ -339,6 +345,124 @@ namespace NavisworksTransport
|
||||
ExecuteNonQuery("CREATE INDEX IF NOT EXISTS idx_clash_excluded_object ON ClashDetectiveExcludedObjects(ExcludedObjectId)");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行数据库迁移
|
||||
/// 处理字段名变更等结构升级
|
||||
/// </summary>
|
||||
private void RunMigrations()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 迁移1: ClashDetectiveResults 表字段名变更 (VirtualVehicleXxx -> VirtualObjectXxx)
|
||||
MigrateClashDetectiveResultsTable();
|
||||
|
||||
// 迁移2: BatchQueueItems 表字段名变更
|
||||
MigrateBatchQueueItemsTable();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[数据库迁移] 执行迁移时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 迁移 ClashDetectiveResults 表字段名
|
||||
/// </summary>
|
||||
private void MigrateClashDetectiveResultsTable()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否存在旧字段名
|
||||
var columns = GetTableColumns("ClashDetectiveResults");
|
||||
|
||||
// 迁移 VirtualVehicleWidth -> VirtualObjectWidth
|
||||
if (columns.Contains("VirtualVehicleWidth") && !columns.Contains("VirtualObjectWidth"))
|
||||
{
|
||||
ExecuteNonQuery("ALTER TABLE ClashDetectiveResults RENAME COLUMN VirtualVehicleWidth TO VirtualObjectWidth");
|
||||
LogManager.Info("[数据库迁移] ClashDetectiveResults.VirtualVehicleWidth -> VirtualObjectWidth");
|
||||
}
|
||||
|
||||
// 迁移 VirtualVehicleHeight -> VirtualObjectHeight
|
||||
if (columns.Contains("VirtualVehicleHeight") && !columns.Contains("VirtualObjectHeight"))
|
||||
{
|
||||
ExecuteNonQuery("ALTER TABLE ClashDetectiveResults RENAME COLUMN VirtualVehicleHeight TO VirtualObjectHeight");
|
||||
LogManager.Info("[数据库迁移] ClashDetectiveResults.VirtualVehicleHeight -> VirtualObjectHeight");
|
||||
}
|
||||
|
||||
// 迁移 VirtualObjecctLength -> VirtualObjectLength (同时修复拼写错误)
|
||||
if (columns.Contains("VirtualObjecctLength") && !columns.Contains("VirtualObjectLength"))
|
||||
{
|
||||
ExecuteNonQuery("ALTER TABLE ClashDetectiveResults RENAME COLUMN VirtualObjecctLength TO VirtualObjectLength");
|
||||
LogManager.Info("[数据库迁移] ClashDetectiveResults.VirtualObjecctLength -> VirtualObjectLength");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[数据库迁移] ClashDetectiveResults 表迁移失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 迁移 BatchQueueItems 表字段名
|
||||
/// </summary>
|
||||
private void MigrateBatchQueueItemsTable()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否存在旧字段名
|
||||
var columns = GetTableColumns("BatchQueueItems");
|
||||
|
||||
// 迁移 VirtualVehicleWidth -> VirtualObjectWidth
|
||||
if (columns.Contains("VirtualVehicleWidth") && !columns.Contains("VirtualObjectWidth"))
|
||||
{
|
||||
ExecuteNonQuery("ALTER TABLE BatchQueueItems RENAME COLUMN VirtualVehicleWidth TO VirtualObjectWidth");
|
||||
LogManager.Info("[数据库迁移] BatchQueueItems.VirtualVehicleWidth -> VirtualObjectWidth");
|
||||
}
|
||||
|
||||
// 迁移 VirtualVehicleHeight -> VirtualObjectHeight
|
||||
if (columns.Contains("VirtualVehicleHeight") && !columns.Contains("VirtualObjectHeight"))
|
||||
{
|
||||
ExecuteNonQuery("ALTER TABLE BatchQueueItems RENAME COLUMN VirtualVehicleHeight TO VirtualObjectHeight");
|
||||
LogManager.Info("[数据库迁移] BatchQueueItems.VirtualVehicleHeight -> VirtualObjectHeight");
|
||||
}
|
||||
|
||||
// 迁移 VirtualObjecctLength -> VirtualObjectLength
|
||||
if (columns.Contains("VirtualObjecctLength") && !columns.Contains("VirtualObjectLength"))
|
||||
{
|
||||
ExecuteNonQuery("ALTER TABLE BatchQueueItems RENAME COLUMN VirtualObjecctLength TO VirtualObjectLength");
|
||||
LogManager.Info("[数据库迁移] BatchQueueItems.VirtualObjecctLength -> VirtualObjectLength");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[数据库迁移] BatchQueueItems 表迁移失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取表的列名列表
|
||||
/// </summary>
|
||||
private List<string> GetTableColumns(string tableName)
|
||||
{
|
||||
var columns = new List<string>();
|
||||
try
|
||||
{
|
||||
using (var cmd = new SQLiteCommand($"PRAGMA table_info({tableName})", _connection))
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
columns.Add(reader["name"].ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"[数据库迁移] 获取 {tableName} 表列信息失败: {ex.Message}");
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存路径基本信息
|
||||
/// </summary>
|
||||
@ -352,7 +476,7 @@ namespace NavisworksTransport
|
||||
// 保存路径基本信息
|
||||
var sql = @"
|
||||
INSERT OR REPLACE INTO PathRoutes
|
||||
(Id, Name, TotalLength, EstimatedTime, TurnRadius, IsCurved, MaxVehicleLength, MaxVehicleWidth, MaxVehicleHeight, SafetyMargin, GridSize, PathType, LiftHeightMeters, CreatedTime, LastModified)
|
||||
(Id, Name, TotalLength, EstimatedTime, TurnRadius, IsCurved, MaxObjectLength, MaxObjectWidth, MaxObjectHeight, SafetyMargin, GridSize, PathType, LiftHeightMeters, CreatedTime, LastModified)
|
||||
VALUES (@id, @name, @length, @time, @turnRadius, @isCurved, @maxLength, @maxWidth, @maxHeight, @safetyMargin, @gridSize, @pathType, @liftHeightMeters, @created, @modified)
|
||||
";
|
||||
|
||||
@ -364,9 +488,9 @@ namespace NavisworksTransport
|
||||
cmd.Parameters.AddWithValue("@time", route.EstimatedTime);
|
||||
cmd.Parameters.AddWithValue("@turnRadius", route.TurnRadius);
|
||||
cmd.Parameters.AddWithValue("@isCurved", route.IsCurved ? 1 : 0);
|
||||
cmd.Parameters.AddWithValue("@maxLength", route.MaxVehicleLength);
|
||||
cmd.Parameters.AddWithValue("@maxWidth", route.MaxVehicleWidth);
|
||||
cmd.Parameters.AddWithValue("@maxHeight", route.MaxVehicleHeight);
|
||||
cmd.Parameters.AddWithValue("@maxLength", route.MaxObjectLength);
|
||||
cmd.Parameters.AddWithValue("@maxWidth", route.MaxObjectWidth);
|
||||
cmd.Parameters.AddWithValue("@maxHeight", route.MaxObjectHeight);
|
||||
cmd.Parameters.AddWithValue("@safetyMargin", route.SafetyMargin);
|
||||
cmd.Parameters.AddWithValue("@gridSize", route.GridSize);
|
||||
cmd.Parameters.AddWithValue("@pathType", (int)route.PathType);
|
||||
@ -755,11 +879,11 @@ namespace NavisworksTransport
|
||||
var sql = @"
|
||||
INSERT INTO ClashDetectiveResults
|
||||
(TestName, RouteId, TestTime, CollisionCount, AnimationCollisionCount,
|
||||
FrameRate, Duration, DetectionGap, AnimatedObjectName, IsVirtualVehicle, VehicleModelIndex, VehiclePathId,
|
||||
VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, CreatedAt)
|
||||
FrameRate, Duration, DetectionGap, AnimatedObjectName, IsVirtualObject, ObjectModelIndex, ObjectPathId,
|
||||
VirtualObjectLength, VirtualObjectWidth, VirtualObjectHeight, CreatedAt)
|
||||
VALUES (@testName, @routeId, @testTime, @collisionCount, @animationCollisionCount,
|
||||
@frameRate, @duration, @detectionGap, @animatedObjectName, @isVirtualVehicle, @vehicleModelIndex, @vehiclePathId,
|
||||
@virtualVehicleLength, @virtualVehicleWidth, @virtualVehicleHeight, @createdAt)
|
||||
@frameRate, @duration, @detectionGap, @animatedObjectName, @isVirtualObject, @ObjectModelIndex, @ObjectPathId,
|
||||
@virtualObjectLength, @virtualObjectWidth, @virtualObjectHeight, @createdAt)
|
||||
";
|
||||
|
||||
long newId = 0;
|
||||
@ -774,12 +898,12 @@ namespace NavisworksTransport
|
||||
cmd.Parameters.AddWithValue("@duration", record.Duration);
|
||||
cmd.Parameters.AddWithValue("@detectionGap", record.DetectionGap);
|
||||
cmd.Parameters.AddWithValue("@animatedObjectName", record.AnimatedObjectName ?? "");
|
||||
cmd.Parameters.AddWithValue("@isVirtualVehicle", record.IsVirtualVehicle);
|
||||
cmd.Parameters.AddWithValue("@vehicleModelIndex", record.VehicleModelIndex.HasValue ? (object)record.VehicleModelIndex.Value : DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@vehiclePathId", record.VehiclePathId ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@virtualVehicleLength", record.VirtualVehicleLength);
|
||||
cmd.Parameters.AddWithValue("@virtualVehicleWidth", record.VirtualVehicleWidth);
|
||||
cmd.Parameters.AddWithValue("@virtualVehicleHeight", record.VirtualVehicleHeight);
|
||||
cmd.Parameters.AddWithValue("@isVirtualObject", record.IsVirtualObject);
|
||||
cmd.Parameters.AddWithValue("@ObjectModelIndex", record.ObjectModelIndex.HasValue ? (object)record.ObjectModelIndex.Value : DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@ObjectPathId", record.ObjectPathId ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@virtualObjectLength", record.VirtualObjectLength);
|
||||
cmd.Parameters.AddWithValue("@virtualObjectWidth", record.VirtualObjectWidth);
|
||||
cmd.Parameters.AddWithValue("@virtualObjectHeight", record.VirtualObjectHeight);
|
||||
cmd.Parameters.AddWithValue("@createdAt", record.CreatedAt);
|
||||
cmd.ExecuteNonQuery();
|
||||
newId = _connection.LastInsertRowId;
|
||||
@ -1320,9 +1444,9 @@ namespace NavisworksTransport
|
||||
EstimatedTime = Convert.ToDouble(reader["EstimatedTime"]),
|
||||
TurnRadius = Convert.ToDouble(reader["TurnRadius"]),
|
||||
IsCurved = Convert.ToInt32(reader["IsCurved"]) == 1,
|
||||
MaxVehicleLength = Convert.ToDouble(reader["MaxVehicleLength"]),
|
||||
MaxVehicleWidth = Convert.ToDouble(reader["MaxVehicleWidth"]),
|
||||
MaxVehicleHeight = Convert.ToDouble(reader["MaxVehicleHeight"]),
|
||||
MaxObjectLength = Convert.ToDouble(reader["MaxObjectLength"]),
|
||||
MaxObjectWidth = Convert.ToDouble(reader["MaxObjectWidth"]),
|
||||
MaxObjectHeight = Convert.ToDouble(reader["MaxObjectHeight"]),
|
||||
SafetyMargin = Convert.ToDouble(reader["SafetyMargin"]),
|
||||
GridSize = Convert.ToDouble(reader["GridSize"]),
|
||||
PathType = (PathType)Convert.ToInt32(reader["PathType"]),
|
||||
@ -2099,7 +2223,7 @@ namespace NavisworksTransport
|
||||
using (var cmd = new SQLiteCommand(_connection))
|
||||
{
|
||||
cmd.CommandText = @"
|
||||
SELECT Id, TestName, PathName, RouteId, TestTime, CollisionCount, AnimationCollisionCount, FrameRate, Duration, DetectionGap, AnimatedObjectName, IsVirtualVehicle, VehicleModelIndex, VehiclePathId, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight, CreatedAt
|
||||
SELECT Id, TestName, PathName, RouteId, TestTime, CollisionCount, AnimationCollisionCount, FrameRate, Duration, DetectionGap, AnimatedObjectName, IsVirtualObject, ObjectModelIndex, ObjectPathId, VirtualObjectLength, VirtualObjectWidth, VirtualObjectHeight, CreatedAt
|
||||
FROM ClashDetectiveResults
|
||||
WHERE TestName = @TestName";
|
||||
|
||||
@ -2122,12 +2246,12 @@ namespace NavisworksTransport
|
||||
Duration = Convert.ToDouble(reader["Duration"]),
|
||||
DetectionGap = Convert.ToDouble(reader["DetectionGap"]),
|
||||
AnimatedObjectName = reader["AnimatedObjectName"].ToString(),
|
||||
IsVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]),
|
||||
VehicleModelIndex = !Convert.IsDBNull(reader["VehicleModelIndex"]) ? (int?)Convert.ToInt32(reader["VehicleModelIndex"]) : null,
|
||||
VehiclePathId = reader["VehiclePathId"].ToString(),
|
||||
VirtualVehicleLength = Convert.ToDouble(reader["VirtualVehicleLength"]),
|
||||
VirtualVehicleWidth = Convert.ToDouble(reader["VirtualVehicleWidth"]),
|
||||
VirtualVehicleHeight = Convert.ToDouble(reader["VirtualVehicleHeight"]),
|
||||
IsVirtualObject = Convert.ToBoolean(reader["IsVirtualObject"]),
|
||||
ObjectModelIndex = !Convert.IsDBNull(reader["ObjectModelIndex"]) ? (int?)Convert.ToInt32(reader["ObjectModelIndex"]) : null,
|
||||
ObjectPathId = reader["ObjectPathId"].ToString(),
|
||||
VirtualObjectLength = Convert.ToDouble(reader["VirtualObjectLength"]),
|
||||
VirtualObjectWidth = Convert.ToDouble(reader["VirtualObjectWidth"]),
|
||||
VirtualObjectHeight = Convert.ToDouble(reader["VirtualObjectHeight"]),
|
||||
CreatedAt = DateTime.Parse(reader["CreatedAt"].ToString())
|
||||
};
|
||||
}
|
||||
@ -2157,7 +2281,7 @@ namespace NavisworksTransport
|
||||
{
|
||||
cmd.CommandText = @"
|
||||
SELECT Id, Name, CreatedTime, LastModified, TotalLength,
|
||||
TurnRadius, IsCurved, MaxVehicleLength, MaxVehicleWidth, MaxVehicleHeight,
|
||||
TurnRadius, IsCurved, MaxObjectLength, MaxObjectWidth, MaxObjectHeight,
|
||||
SafetyMargin, GridSize, PathType, LiftHeightMeters
|
||||
FROM PathRoutes
|
||||
WHERE Id = @Id";
|
||||
@ -2176,9 +2300,9 @@ namespace NavisworksTransport
|
||||
TotalLength = Convert.ToDouble(reader["TotalLength"]),
|
||||
TurnRadius = Convert.ToDouble(reader["TurnRadius"]),
|
||||
IsCurved = Convert.ToInt32(reader["IsCurved"]) == 1,
|
||||
MaxVehicleLength = Convert.ToDouble(reader["MaxVehicleLength"]),
|
||||
MaxVehicleWidth = Convert.ToDouble(reader["MaxVehicleWidth"]),
|
||||
MaxVehicleHeight = Convert.ToDouble(reader["MaxVehicleHeight"]),
|
||||
MaxObjectLength = Convert.ToDouble(reader["MaxObjectLength"]),
|
||||
MaxObjectWidth = Convert.ToDouble(reader["MaxObjectWidth"]),
|
||||
MaxObjectHeight = Convert.ToDouble(reader["MaxObjectHeight"]),
|
||||
SafetyMargin = Convert.ToDouble(reader["SafetyMargin"]),
|
||||
GridSize = Convert.ToDouble(reader["GridSize"]),
|
||||
PathType = (PathType)Convert.ToInt32(reader["PathType"]),
|
||||
@ -2212,14 +2336,14 @@ namespace NavisworksTransport
|
||||
INSERT INTO BatchQueueItems (
|
||||
RouteId, Status, CreatedTime, StartTime, EndTime, ErrorMessage,
|
||||
FrameRate, DurationSeconds, DetectionToleranceMeters,
|
||||
IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight,
|
||||
IsVirtualObject, VirtualObjectLength, VirtualObjectWidth, VirtualObjectHeight,
|
||||
DetectAllObjects,
|
||||
ClashDetectiveTestName, CollisionCount, ObjectRotationCorrection
|
||||
)
|
||||
VALUES (
|
||||
@RouteId, @Status, @CreatedTime, @StartTime, @EndTime, @ErrorMessage,
|
||||
@FrameRate, @DurationSeconds, @DetectionToleranceMeters,
|
||||
@IsVirtualVehicle, @VirtualVehicleLength, @VirtualVehicleWidth, @VirtualVehicleHeight,
|
||||
@IsVirtualObject, @VirtualObjectLength, @VirtualObjectWidth, @VirtualObjectHeight,
|
||||
@DetectAllObjects,
|
||||
@ClashDetectiveTestName, @CollisionCount, @ObjectRotationCorrection
|
||||
);
|
||||
@ -2234,10 +2358,10 @@ namespace NavisworksTransport
|
||||
cmd.Parameters.AddWithValue("@FrameRate", item.FrameRate);
|
||||
cmd.Parameters.AddWithValue("@DurationSeconds", item.DurationSeconds);
|
||||
cmd.Parameters.AddWithValue("@DetectionToleranceMeters", item.DetectionToleranceMeters);
|
||||
cmd.Parameters.AddWithValue("@IsVirtualVehicle", item.IsVirtualVehicle ? 1 : 0);
|
||||
cmd.Parameters.AddWithValue("@VirtualVehicleLength", item.VirtualVehicleLength);
|
||||
cmd.Parameters.AddWithValue("@VirtualVehicleWidth", item.VirtualVehicleWidth);
|
||||
cmd.Parameters.AddWithValue("@VirtualVehicleHeight", item.VirtualVehicleHeight);
|
||||
cmd.Parameters.AddWithValue("@IsVirtualObject", item.IsVirtualObject ? 1 : 0);
|
||||
cmd.Parameters.AddWithValue("@VirtualObjectLength", item.VirtualObjectLength);
|
||||
cmd.Parameters.AddWithValue("@VirtualObjectWidth", item.VirtualObjectWidth);
|
||||
cmd.Parameters.AddWithValue("@VirtualObjectHeight", item.VirtualObjectHeight);
|
||||
cmd.Parameters.AddWithValue("@DetectAllObjects", item.DetectAllObjects ? 1 : 0);
|
||||
cmd.Parameters.AddWithValue("@ClashDetectiveTestName", item.ClashDetectiveTestName ?? "");
|
||||
cmd.Parameters.AddWithValue("@CollisionCount", item.CollisionCount ?? (object)DBNull.Value);
|
||||
@ -2261,7 +2385,7 @@ namespace NavisworksTransport
|
||||
private BatchQueueItem ReadBatchQueueItemFromReader(SQLiteDataReader reader)
|
||||
{
|
||||
var itemId = Convert.ToInt32(reader["Id"]);
|
||||
var isVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]);
|
||||
var isVirtualObject = Convert.ToBoolean(reader["IsVirtualObject"]);
|
||||
|
||||
var item = new BatchQueueItem
|
||||
{
|
||||
@ -2277,10 +2401,10 @@ namespace NavisworksTransport
|
||||
FrameRate = Convert.ToInt32(reader["FrameRate"]),
|
||||
DurationSeconds = Convert.ToDouble(reader["DurationSeconds"]),
|
||||
DetectionToleranceMeters = Convert.ToDouble(reader["DetectionToleranceMeters"]),
|
||||
IsVirtualVehicle = isVirtualVehicle,
|
||||
VirtualVehicleLength = Convert.ToDouble(reader["VirtualVehicleLength"]),
|
||||
VirtualVehicleWidth = Convert.ToDouble(reader["VirtualVehicleWidth"]),
|
||||
VirtualVehicleHeight = Convert.ToDouble(reader["VirtualVehicleHeight"]),
|
||||
IsVirtualObject = isVirtualObject,
|
||||
VirtualObjectLength = Convert.ToDouble(reader["VirtualObjectLength"]),
|
||||
VirtualObjectWidth = Convert.ToDouble(reader["VirtualObjectWidth"]),
|
||||
VirtualObjectHeight = Convert.ToDouble(reader["VirtualObjectHeight"]),
|
||||
DetectAllObjects = Convert.ToBoolean(reader["DetectAllObjects"]),
|
||||
ClashDetectiveTestName = reader["ClashDetectiveTestName"].ToString(),
|
||||
CollisionCount = !Convert.IsDBNull(reader["CollisionCount"]) ? (int?)Convert.ToInt32(reader["CollisionCount"]) : null,
|
||||
@ -2288,7 +2412,7 @@ namespace NavisworksTransport
|
||||
};
|
||||
|
||||
// 填充 MovingObjectName 属性
|
||||
if (!isVirtualVehicle)
|
||||
if (!isVirtualObject)
|
||||
{
|
||||
// 从 ModelItemReferences 表查询运动物体名称
|
||||
var movingObjectReferences = GetModelItemReferencesSync(itemId, "BatchQueueItem", "MovingObject");
|
||||
@ -2315,7 +2439,7 @@ namespace NavisworksTransport
|
||||
var sql = @"
|
||||
SELECT bqi.Id, bqi.RouteId, pr.Name AS PathRouteName, pr.PathType, bqi.Status, bqi.CreatedTime, bqi.StartTime, bqi.EndTime, bqi.ErrorMessage,
|
||||
bqi.FrameRate, bqi.DurationSeconds, bqi.DetectionToleranceMeters,
|
||||
bqi.IsVirtualVehicle, bqi.VirtualVehicleLength, bqi.VirtualVehicleWidth, bqi.VirtualVehicleHeight,
|
||||
bqi.IsVirtualObject, bqi.VirtualObjectLength, bqi.VirtualObjectWidth, bqi.VirtualObjectHeight,
|
||||
bqi.DetectAllObjects,
|
||||
bqi.ClashDetectiveTestName, bqi.CollisionCount, bqi.ObjectRotationCorrection
|
||||
FROM BatchQueueItems bqi
|
||||
@ -2374,7 +2498,7 @@ namespace NavisworksTransport
|
||||
cmd.CommandText = @"
|
||||
SELECT bqi.Id, bqi.RouteId, pr.Name AS PathRouteName, pr.PathType, bqi.Status, bqi.CreatedTime, bqi.StartTime, bqi.EndTime, bqi.ErrorMessage,
|
||||
bqi.FrameRate, bqi.DurationSeconds, bqi.DetectionToleranceMeters,
|
||||
bqi.IsVirtualVehicle, bqi.VirtualVehicleLength, bqi.VirtualVehicleWidth, bqi.VirtualVehicleHeight,
|
||||
bqi.IsVirtualObject, bqi.VirtualObjectLength, bqi.VirtualObjectWidth, bqi.VirtualObjectHeight,
|
||||
bqi.DetectAllObjects,
|
||||
bqi.ClashDetectiveTestName, bqi.CollisionCount, bqi.ObjectRotationCorrection
|
||||
FROM BatchQueueItems bqi
|
||||
@ -2607,12 +2731,12 @@ namespace NavisworksTransport
|
||||
public double Duration { get; set; }
|
||||
public double DetectionGap { get; set; }
|
||||
public string AnimatedObjectName { get; set; }
|
||||
public bool IsVirtualVehicle { get; set; }
|
||||
public int? VehicleModelIndex { get; set; }
|
||||
public string VehiclePathId { get; set; }
|
||||
public double VirtualVehicleLength { get; set; }
|
||||
public double VirtualVehicleWidth { get; set; }
|
||||
public double VirtualVehicleHeight { get; set; }
|
||||
public bool IsVirtualObject { get; set; }
|
||||
public int? ObjectModelIndex { get; set; }
|
||||
public string ObjectPathId { get; set; }
|
||||
public double VirtualObjectLength { get; set; }
|
||||
public double VirtualObjectWidth { get; set; }
|
||||
public double VirtualObjectHeight { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@ -74,7 +74,7 @@ namespace NavisworksTransport
|
||||
private bool _showUnknownGrid = false;
|
||||
private bool _showDoorGrid = false;
|
||||
private GridMap _currentGridMap = null; // 保存当前网格地图用于刷新
|
||||
private double _currentVehicleHeight = 2.0; // 保存当前车辆高度(米)用于网格刷新
|
||||
private double _currentObjectHeight = 2.0; // 保存当前物体高度(米)用于网格刷新
|
||||
private bool _isPreviewMode = false;
|
||||
private int _previewInsertIndex = -1; // 保存预览点应该插入的索引位置
|
||||
|
||||
@ -141,7 +141,7 @@ namespace NavisworksTransport
|
||||
LogManager.Info("[路径管理] ✅ PathPointRenderPlugin实例获取成功");
|
||||
LogManager.Debug($"[路径管理] 渲染插件状态 - 启用: {_renderPlugin.IsEnabled}, 标记数量: {_renderPlugin.MarkerCount}");
|
||||
|
||||
// 推送默认的网格大小和车辆参数,确保渲染插件有合理的初始值
|
||||
// 推送默认的网格大小和物体参数,确保渲染插件有合理的初始值
|
||||
InitializeRenderPluginDefaults();
|
||||
}
|
||||
else
|
||||
@ -205,7 +205,7 @@ namespace NavisworksTransport
|
||||
|
||||
/// <summary>
|
||||
/// 初始化渲染插件的默认值
|
||||
/// 从配置文件读取网格大小和车辆参数,确保渲染插件在任何情况下都有正确的可视化效果
|
||||
/// 从配置文件读取网格大小和物体参数,确保渲染插件在任何情况下都有正确的可视化效果
|
||||
/// </summary>
|
||||
private void InitializeRenderPluginDefaults()
|
||||
{
|
||||
@ -1011,13 +1011,13 @@ namespace NavisworksTransport
|
||||
/// </summary>
|
||||
/// <param name="startPoint">起点</param>
|
||||
/// <param name="endPoint">终点</param>
|
||||
/// <param name="vehicleRadius">车辆尺寸(米)</param>
|
||||
/// <param name="ObjectRadius">物体尺寸(米)</param>
|
||||
/// <param name="safetyMargin">安全间隙(米)</param>
|
||||
/// <param name="gridSize">网格精度(米)</param>
|
||||
/// <param name="vehicleHeight">车辆高度(米)</param>
|
||||
/// <param name="ObjectHeight">物体高度(米)</param>
|
||||
/// <param name="strategy">路径规划策略</param>
|
||||
/// <returns>规划结果</returns>
|
||||
public Task<PathRoute> AutoPlanPath(PathPoint startPoint, PathPoint endPoint, double vehicleRadius, double safetyMargin, double gridSize, double vehicleHeight, PathStrategy strategy)
|
||||
public Task<PathRoute> AutoPlanPath(PathPoint startPoint, PathPoint endPoint, double ObjectRadius, double safetyMargin, double gridSize, double ObjectHeight, PathStrategy strategy)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -1029,7 +1029,7 @@ namespace NavisworksTransport
|
||||
LogManager.Info($"开始自动路径规划: {startPoint.Name} -> {endPoint.Name}");
|
||||
LogManager.Info($"起点坐标: ({startPoint.Position.X:F2}, {startPoint.Position.Y:F2}, {startPoint.Position.Z:F2})");
|
||||
LogManager.Info($"终点坐标: ({endPoint.Position.X:F2}, {endPoint.Position.Y:F2}, {endPoint.Position.Z:F2})");
|
||||
LogManager.Info($"车辆半径: {vehicleRadius}m, 安全间隙: {safetyMargin}m, 车辆高度: {vehicleHeight}m");
|
||||
LogManager.Info($"物体半径: {ObjectRadius}m, 安全间隙: {safetyMargin}m, 物体高度: {ObjectHeight}m");
|
||||
|
||||
RaiseStatusChanged("正在进行自动路径规划...", PathPlanningStatusType.Info);
|
||||
|
||||
@ -1060,7 +1060,7 @@ namespace NavisworksTransport
|
||||
// 获取当前文档
|
||||
var document = Application.ActiveDocument;
|
||||
LogManager.Info($"网格生成参数 - 边界: {bounds.Min.X:F2},{bounds.Min.Y:F2} -> {bounds.Max.X:F2},{bounds.Max.Y:F2}");
|
||||
LogManager.Info($"网格生成参数 - 网格大小: {gridSize}m, 车辆半径: {vehicleRadius}m, 安全边距: {safetyMargin}m");
|
||||
LogManager.Info($"网格生成参数 - 网格大小: {gridSize}m, 物体半径: {ObjectRadius}m, 安全边距: {safetyMargin}m");
|
||||
LogManager.Info($"网格生成参数 - 起点: ({startPoint.Position.X:F2}, {startPoint.Position.Y:F2}, {startPoint.Position.Z:F2})");
|
||||
LogManager.Info($"网格生成参数 - 终点: ({endPoint.Position.X:F2}, {endPoint.Position.Y:F2}, {endPoint.Position.Z:F2})");
|
||||
|
||||
@ -1069,11 +1069,11 @@ namespace NavisworksTransport
|
||||
gridMap = gridMapGenerator.GenerateFromBIM(
|
||||
bounds,
|
||||
gridSize,
|
||||
vehicleRadius,
|
||||
ObjectRadius,
|
||||
safetyMargin,
|
||||
startPoint.Position,
|
||||
endPoint.Position,
|
||||
vehicleHeight
|
||||
ObjectHeight
|
||||
);
|
||||
LogManager.Info("✅ 网格地图生成成功");
|
||||
}
|
||||
@ -1096,7 +1096,7 @@ namespace NavisworksTransport
|
||||
if (_showWalkableGrid || _showObstacleGrid || _showUnknownGrid || _showDoorGrid)
|
||||
{
|
||||
LogManager.Info("开始网格可视化,显示所有可通行网格单元");
|
||||
VisualizeGridCells(gridMap, vehicleHeight);
|
||||
VisualizeGridCells(gridMap, ObjectHeight);
|
||||
}
|
||||
|
||||
// 3. 获取通道高度数据
|
||||
@ -1132,9 +1132,9 @@ namespace NavisworksTransport
|
||||
try
|
||||
{
|
||||
pathFinder = new AutoPathFinder();
|
||||
double vehicleHeightInModelUnits = vehicleHeight * UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
|
||||
LogManager.Info($"使用2.5D模式进行路径查找,车辆高度: {vehicleHeight}m ({vehicleHeightInModelUnits:F2}模型单位),策略: {strategy}");
|
||||
pathResult = pathFinder.FindPath(startPoint.Position, endPoint.Position, gridMap, channelCoverage, vehicleHeightInModelUnits, strategy);
|
||||
double ObjectHeightInModelUnits = ObjectHeight * UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
|
||||
LogManager.Info($"使用2.5D模式进行路径查找,物体高度: {ObjectHeight}m ({ObjectHeightInModelUnits:F2}模型单位),策略: {strategy}");
|
||||
pathResult = pathFinder.FindPath(startPoint.Position, endPoint.Position, gridMap, channelCoverage, ObjectHeightInModelUnits, strategy);
|
||||
LogManager.Info("FindPath方法调用完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -1170,10 +1170,10 @@ namespace NavisworksTransport
|
||||
// 保存GridMap和参数到PathRoute以便后续恢复网格可视化
|
||||
autoRoute.AssociatedGridMap = gridMap;
|
||||
autoRoute.GridSize = gridSize;
|
||||
// 将vehicleRadius拆分为长宽(暂时使用相同值,后续可以传入更详细的参数)
|
||||
autoRoute.MaxVehicleLength = vehicleRadius * 2; // 车辆半径转换为长度
|
||||
autoRoute.MaxVehicleWidth = vehicleRadius * 2; // 车辆半径转换为宽度
|
||||
autoRoute.MaxVehicleHeight = vehicleHeight;
|
||||
// 将ObjectRadius拆分为长宽(暂时使用相同值,后续可以传入更详细的参数)
|
||||
autoRoute.MaxObjectLength = ObjectRadius * 2; // 物体半径转换为长度
|
||||
autoRoute.MaxObjectWidth = ObjectRadius * 2; // 物体半径转换为宽度
|
||||
autoRoute.MaxObjectHeight = ObjectHeight;
|
||||
autoRoute.SafetyMargin = safetyMargin;
|
||||
LogManager.Info($"已保存GridMap到路径: {routeName}, 网格大小: {gridSize}米");
|
||||
|
||||
@ -4535,7 +4535,7 @@ namespace NavisworksTransport
|
||||
if (_currentGridMap != null && IsAnyGridVisualizationEnabled)
|
||||
{
|
||||
LogManager.Info("[网格可视化] 使用缓存的网格地图重新渲染");
|
||||
VisualizeGridCells(_currentGridMap, _currentVehicleHeight);
|
||||
VisualizeGridCells(_currentGridMap, _currentObjectHeight);
|
||||
}
|
||||
else if (_currentGridMap == null)
|
||||
{
|
||||
@ -4557,8 +4557,8 @@ namespace NavisworksTransport
|
||||
/// 在每个可通行网格的中心绘制一个绿色小球
|
||||
/// </summary>
|
||||
/// <param name="gridMap">要可视化的网格地图</param>
|
||||
/// <param name="vehicleHeight">车辆高度(米),用于判断层高是否足够</param>
|
||||
public void VisualizeGridCells(GridMap gridMap, double vehicleHeight = 2.0)
|
||||
/// <param name="ObjectHeight">物体高度(米),用于判断层高是否足够</param>
|
||||
public void VisualizeGridCells(GridMap gridMap, double ObjectHeight = 2.0)
|
||||
{
|
||||
if (gridMap == null)
|
||||
{
|
||||
@ -4568,10 +4568,10 @@ namespace NavisworksTransport
|
||||
|
||||
try
|
||||
{
|
||||
// 保存当前网格地图和车辆高度用于后续刷新
|
||||
// 保存当前网格地图和物体高度用于后续刷新
|
||||
_currentGridMap = gridMap;
|
||||
_currentVehicleHeight = vehicleHeight;
|
||||
LogManager.Info($"[网格可视化] 开始可视化网格:{gridMap.Width}x{gridMap.Height}, 车辆高度:{vehicleHeight}m");
|
||||
_currentObjectHeight = ObjectHeight;
|
||||
LogManager.Info($"[网格可视化] 开始可视化网格:{gridMap.Width}x{gridMap.Height}, 物体高度:{ObjectHeight}m");
|
||||
|
||||
// 获取渲染插件
|
||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||
|
||||
@ -570,17 +570,17 @@ namespace NavisworksTransport
|
||||
/// <summary>
|
||||
/// 最大车辆长度(米) - 路径适用的车辆长度限制
|
||||
/// </summary>
|
||||
public double MaxVehicleLength { get; set; }
|
||||
public double MaxObjectLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大车辆宽度(米) - 路径适用的车辆宽度限制
|
||||
/// </summary>
|
||||
public double MaxVehicleWidth { get; set; }
|
||||
public double MaxObjectWidth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大车辆高度(米) - 路径适用的车辆高度限制
|
||||
/// </summary>
|
||||
public double MaxVehicleHeight { get; set; }
|
||||
public double MaxObjectHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 安全间隙(米)
|
||||
@ -906,9 +906,9 @@ namespace NavisworksTransport
|
||||
CompletionPercentage = CompletionPercentage,
|
||||
AssociatedGridMap = AssociatedGridMap, // 共享引用,不深拷贝
|
||||
GridSize = GridSize,
|
||||
MaxVehicleLength = MaxVehicleLength,
|
||||
MaxVehicleWidth = MaxVehicleWidth,
|
||||
MaxVehicleHeight = MaxVehicleHeight,
|
||||
MaxObjectLength = MaxObjectLength,
|
||||
MaxObjectWidth = MaxObjectWidth,
|
||||
MaxObjectHeight = MaxObjectHeight,
|
||||
SafetyMargin = SafetyMargin
|
||||
};
|
||||
|
||||
@ -1428,7 +1428,7 @@ namespace NavisworksTransport
|
||||
// 获取通道属性信息
|
||||
string channelType = "通道";
|
||||
string traversable = "是";
|
||||
string vehicleSize = "标准";
|
||||
string ObjectSize = "标准";
|
||||
|
||||
try
|
||||
{
|
||||
@ -1456,7 +1456,7 @@ namespace NavisworksTransport
|
||||
// 添加子项
|
||||
item.SubItems.Add(channelType);
|
||||
item.SubItems.Add(traversable);
|
||||
item.SubItems.Add(vehicleSize);
|
||||
item.SubItems.Add(ObjectSize);
|
||||
item.SubItems.Add(length.ToString("F2"));
|
||||
item.SubItems.Add(width.ToString("F2"));
|
||||
item.SubItems.Add(height.ToString("F2"));
|
||||
|
||||
@ -25,9 +25,9 @@ namespace NavisworksTransport
|
||||
RibbonLine,
|
||||
|
||||
/// <summary>
|
||||
/// 车辆通行空间模式 - 矩形通道
|
||||
/// 物体通行空间模式 - 矩形通道
|
||||
/// </summary>
|
||||
VehicleSpace
|
||||
ObjectSpace
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -78,9 +78,9 @@ namespace NavisworksTransport
|
||||
Line,
|
||||
|
||||
/// <summary>
|
||||
/// 车辆通行空间样式(灰色)
|
||||
/// 物体通行空间样式(灰色)
|
||||
/// </summary>
|
||||
VehicleSpace,
|
||||
ObjectSpace,
|
||||
|
||||
/// <summary>
|
||||
/// 预览点样式(白色)
|
||||
@ -166,9 +166,9 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 车辆通行空间标记,用于渲染车辆通道空间
|
||||
/// 物体通行空间标记,用于渲染物体通道空间
|
||||
/// </summary>
|
||||
public class VehicleSpaceMarker
|
||||
public class ObjectSpaceMarker
|
||||
{
|
||||
/// <summary>
|
||||
/// 通道起点
|
||||
@ -212,7 +212,7 @@ namespace NavisworksTransport
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"VehicleSpaceMarker[{FromIndex}->{ToIndex}, 宽度={Width:F2}m, 高度={Height:F2}m, 透明度={Alpha:F1}]";
|
||||
return $"ObjectSpaceMarker[{FromIndex}->{ToIndex}, 宽度={Width:F2}m, 高度={Height:F2}m, 透明度={Alpha:F1}]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,12 +267,12 @@ namespace NavisworksTransport
|
||||
public List<Point3D> SampledPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 带状连线高度(仅用于 RibbonLine 和 VehicleSpace 模式)
|
||||
/// 带状连线高度(仅用于 RibbonLine 和 ObjectSpace 模式)
|
||||
/// </summary>
|
||||
public double Height { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 带状连线宽度(仅用于 VehicleSpace 模式)
|
||||
/// 带状连线宽度(仅用于 ObjectSpace 模式)
|
||||
/// </summary>
|
||||
public double Width { get; set; }
|
||||
|
||||
@ -328,9 +328,9 @@ namespace NavisworksTransport
|
||||
public List<SquareMarker> TangentMarkers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 车辆通行空间标记集合
|
||||
/// 物体通行空间标记集合
|
||||
/// </summary>
|
||||
public List<VehicleSpaceMarker> VehicleSpaceMarkers { get; set; }
|
||||
public List<ObjectSpaceMarker> ObjectSpaceMarkers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示控制点可视化(用户意图)
|
||||
@ -351,7 +351,7 @@ namespace NavisworksTransport
|
||||
ControlLineMarkers = new List<LineMarker>();
|
||||
PathLineMarkers = new List<LineMarker>();
|
||||
TangentMarkers = new List<SquareMarker>();
|
||||
VehicleSpaceMarkers = new List<VehicleSpaceMarker>();
|
||||
ObjectSpaceMarkers = new List<ObjectSpaceMarker>();
|
||||
LastUpdated = DateTime.Now;
|
||||
}
|
||||
|
||||
@ -388,7 +388,7 @@ namespace NavisworksTransport
|
||||
|
||||
// 独立可视化开关(替代单一模式)
|
||||
private bool _showPathLines = true; // 显示路径线(地面连线/带状线)
|
||||
private bool _showVehicleSpace = false; // 显示通行空间
|
||||
private bool _showObjectSpace = false; // 显示通行空间
|
||||
|
||||
// 网格点类型配置
|
||||
private GridPointType _gridPointType = GridPointType.Rectangle;
|
||||
@ -464,14 +464,14 @@ namespace NavisworksTransport
|
||||
public static PathPointRenderPlugin Instance => _instance;
|
||||
|
||||
/// <summary>
|
||||
/// 路径可视化模式(向后兼容,根据 ShowPathLines 和 ShowVehicleSpace 计算)
|
||||
/// 路径可视化模式(向后兼容,根据 ShowPathLines 和 ShowObjectSpace 计算)
|
||||
/// </summary>
|
||||
public PathVisualizationMode VisualizationMode
|
||||
{
|
||||
get
|
||||
{
|
||||
// 根据新的独立开关计算模式
|
||||
if (_showVehicleSpace) return PathVisualizationMode.VehicleSpace;
|
||||
if (_showObjectSpace) return PathVisualizationMode.ObjectSpace;
|
||||
if (_showPathLines) return PathVisualizationMode.RibbonLine;
|
||||
return PathVisualizationMode.StandardLine;
|
||||
}
|
||||
@ -479,7 +479,7 @@ namespace NavisworksTransport
|
||||
{
|
||||
_visualizationMode = value;
|
||||
// 同步到新的独立开关
|
||||
_showVehicleSpace = (value == PathVisualizationMode.VehicleSpace);
|
||||
_showObjectSpace = (value == PathVisualizationMode.ObjectSpace);
|
||||
_showPathLines = (value == PathVisualizationMode.RibbonLine || value == PathVisualizationMode.StandardLine);
|
||||
// 模式改变时刷新所有普通路径(排除网格)
|
||||
RefreshNormalPaths();
|
||||
@ -500,14 +500,14 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示通行空间(车辆通行空间)
|
||||
/// 是否显示通行空间(物体通行空间)
|
||||
/// </summary>
|
||||
public bool ShowVehicleSpace
|
||||
public bool ShowObjectSpace
|
||||
{
|
||||
get { return _showVehicleSpace; }
|
||||
get { return _showObjectSpace; }
|
||||
set
|
||||
{
|
||||
_showVehicleSpace = value;
|
||||
_showObjectSpace = value;
|
||||
RefreshNormalPaths();
|
||||
}
|
||||
}
|
||||
@ -654,9 +654,9 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
// 再渲染通行空间(可以在路径线之上)
|
||||
if (_showVehicleSpace)
|
||||
if (_showObjectSpace)
|
||||
{
|
||||
// VehicleSpace 模式:使用车辆通行空间渲染(高高度长方体)
|
||||
// ObjectSpace 模式:使用物体通行空间渲染(高高度长方体)
|
||||
foreach (var pathLineMarker in visualization.PathLineMarkers)
|
||||
{
|
||||
RenderRibbonLineMarker(graphics, pathLineMarker);
|
||||
@ -1290,7 +1290,7 @@ namespace NavisworksTransport
|
||||
visualization.ControlLineMarkers.Clear();
|
||||
visualization.PathLineMarkers.Clear();
|
||||
visualization.TangentMarkers.Clear();
|
||||
visualization.VehicleSpaceMarkers.Clear();
|
||||
visualization.ObjectSpaceMarkers.Clear();
|
||||
|
||||
var points = visualization.PathRoute.Points;
|
||||
if (points.Count == 0) return;
|
||||
@ -1315,7 +1315,7 @@ namespace NavisworksTransport
|
||||
{
|
||||
// 空中路径:默认只显示控制点连线
|
||||
// 但如果启用了通行空间可视化,则构建路径连线以显示通行空间
|
||||
if (_showVehicleSpace)
|
||||
if (_showObjectSpace)
|
||||
{
|
||||
string aerialSubTypeName = visualization.PathRoute.PathType == NavisworksTransport.PathType.Rail ? "空轨" : "吊装";
|
||||
BuildPathLines(visualization, sortedPoints);
|
||||
@ -1406,7 +1406,7 @@ namespace NavisworksTransport
|
||||
Color lineColor;
|
||||
double lineOpacity;
|
||||
|
||||
if (_showVehicleSpace)
|
||||
if (_showObjectSpace)
|
||||
{
|
||||
// 通行空间模式:根据路径类型和段类型计算通行空间尺寸
|
||||
// _passage* 和 _object* 字段已经是模型单位(由 SetPassageSpaceParameters 转换)
|
||||
@ -1430,7 +1430,7 @@ namespace NavisworksTransport
|
||||
height = _passageNormalToPath;
|
||||
}
|
||||
|
||||
var renderStyle = GetRenderStyle(RenderStyleName.VehicleSpace);
|
||||
var renderStyle = GetRenderStyle(RenderStyleName.ObjectSpace);
|
||||
lineColor = renderStyle.Color;
|
||||
lineOpacity = renderStyle.Alpha;
|
||||
}
|
||||
@ -1456,7 +1456,7 @@ namespace NavisworksTransport
|
||||
|
||||
// 计算通行空间的垂直偏移(根据路径类型)
|
||||
double verticalOffset = 0;
|
||||
if (_showVehicleSpace)
|
||||
if (_showObjectSpace)
|
||||
{
|
||||
if (visualization.PathRoute.PathType == NavisworksTransport.PathType.Ground)
|
||||
{
|
||||
@ -1549,7 +1549,7 @@ namespace NavisworksTransport
|
||||
Point3D adjustedStartPoint;
|
||||
Point3D adjustedEndPoint;
|
||||
|
||||
if (_showVehicleSpace && Math.Abs(verticalOffset) > 0.001)
|
||||
if (_showObjectSpace && Math.Abs(verticalOffset) > 0.001)
|
||||
{
|
||||
// 通行空间模式且有垂直偏移时,沿着up向量方向平移
|
||||
adjustedStartPoint = new Point3D(
|
||||
@ -1571,9 +1571,9 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
// 🔥 地面/空轨路径水平段:起点和终点向路径方向延伸半个物体尺寸(仅通行空间)
|
||||
if (_showVehicleSpace)
|
||||
if (_showObjectSpace)
|
||||
{
|
||||
ExtendLineSegmentForVehicleSpace(ref adjustedStartPoint, ref adjustedEndPoint, _passageAlongPath);
|
||||
ExtendLineSegmentForObjectSpace(ref adjustedStartPoint, ref adjustedEndPoint, _passageAlongPath);
|
||||
}
|
||||
|
||||
var lineMarker = new LineMarker
|
||||
@ -1620,7 +1620,7 @@ namespace NavisworksTransport
|
||||
Point3D adjustedEndPoint;
|
||||
List<Point3D> adjustedSampledPoints;
|
||||
|
||||
if (_showVehicleSpace && Math.Abs(verticalOffset) > 0.001)
|
||||
if (_showObjectSpace && Math.Abs(verticalOffset) > 0.001)
|
||||
{
|
||||
// 通行空间模式且有垂直偏移时,沿着up向量方向平移
|
||||
adjustedStartPoint = new Point3D(
|
||||
@ -1657,9 +1657,9 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
// 🔥 圆弧段:起点和终点向路径方向延伸半个物体尺寸(仅通行空间)
|
||||
if (_showVehicleSpace)
|
||||
if (_showObjectSpace)
|
||||
{
|
||||
ExtendLineSegmentForVehicleSpace(ref adjustedStartPoint, ref adjustedEndPoint, _passageAlongPath);
|
||||
ExtendLineSegmentForObjectSpace(ref adjustedStartPoint, ref adjustedEndPoint, _passageAlongPath);
|
||||
}
|
||||
|
||||
var arcMarker = new LineMarker
|
||||
@ -1847,7 +1847,7 @@ namespace NavisworksTransport
|
||||
Point3D adjustedStartPoint;
|
||||
Point3D adjustedEndPoint;
|
||||
|
||||
if (_showVehicleSpace && Math.Abs(verticalOffset) > 0.001)
|
||||
if (_showObjectSpace && Math.Abs(verticalOffset) > 0.001)
|
||||
{
|
||||
// 通行空间模式且有垂直偏移时,沿着up向量方向平移
|
||||
adjustedStartPoint = new Point3D(
|
||||
@ -1869,7 +1869,7 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
// 🔥 通行空间包裹调整:水平段起点和终点延伸以完全包裹物体(仅通行空间)
|
||||
if (_showVehicleSpace && !isVerticalSegment)
|
||||
if (_showObjectSpace && !isVerticalSegment)
|
||||
{
|
||||
// 沿路径方向的物体尺寸(吊装路径根据是否转折90度选择)
|
||||
double alongPathSize = _passageAlongPath;
|
||||
@ -1877,7 +1877,7 @@ namespace NavisworksTransport
|
||||
{
|
||||
alongPathSize = isTurn90Horizontal ? _passageAcrossPath : _objectLength;
|
||||
}
|
||||
ExtendLineSegmentForVehicleSpace(ref adjustedStartPoint, ref adjustedEndPoint, alongPathSize);
|
||||
ExtendLineSegmentForObjectSpace(ref adjustedStartPoint, ref adjustedEndPoint, alongPathSize);
|
||||
}
|
||||
|
||||
var lineMarker = new LineMarker
|
||||
@ -1995,21 +1995,21 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建车辆通行空间标记
|
||||
/// 创建物体通行空间标记
|
||||
/// </summary>
|
||||
/// <param name="fromPoint">起点</param>
|
||||
/// <param name="toPoint">终点</param>
|
||||
/// <returns>车辆通行空间标记</returns>
|
||||
private VehicleSpaceMarker CreateVehicleSpaceMarker(PathPoint fromPoint, PathPoint toPoint)
|
||||
/// <returns>物体通行空间标记</returns>
|
||||
private ObjectSpaceMarker CreateObjectSpaceMarker(PathPoint fromPoint, PathPoint toPoint)
|
||||
{
|
||||
var style = GetRenderStyle(RenderStyleName.VehicleSpace);
|
||||
return new VehicleSpaceMarker
|
||||
var style = GetRenderStyle(RenderStyleName.ObjectSpace);
|
||||
return new ObjectSpaceMarker
|
||||
{
|
||||
StartPoint = fromPoint.Position,
|
||||
EndPoint = toPoint.Position,
|
||||
Width = _passageAcrossPath, // 直接使用模型单位
|
||||
Height = _passageNormalToPath, // 直接使用模型单位
|
||||
Color = style.Color, // 车辆通行空间颜色
|
||||
Color = style.Color, // 物体通行空间颜色
|
||||
Alpha = style.Alpha, // 透明度,统一管理
|
||||
FromIndex = fromPoint.Index,
|
||||
ToIndex = toPoint.Index
|
||||
@ -2102,11 +2102,11 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置车辆参数(从PathPlanningManager同步)
|
||||
/// 设置物体参数(从PathPlanningManager同步)
|
||||
/// </summary>
|
||||
/// <param name="vehicleLength">车辆长度(米)</param>
|
||||
/// <param name="vehicleWidth">车辆宽度(米)</param>
|
||||
/// <param name="vehicleHeight">车辆高度(米)</param>
|
||||
/// <param name="ObjectLength">物体长度(米)</param>
|
||||
/// <param name="ObjectWidth">物体宽度(米)</param>
|
||||
/// <param name="ObjectHeight">物体高度(米)</param>
|
||||
/// <param name="safetyMargin">安全间隙(米)</param>
|
||||
/// <param name="passageNormalToPathVertical">垂直段的高度(物体长度 + 2×安全间隙,模型单位)</param>
|
||||
/// <param name="passageNormalToPathHorizontal">水平段的高度(物体高度 + 2×安全间隙,模型单位)</param>
|
||||
@ -2125,7 +2125,7 @@ namespace NavisworksTransport
|
||||
_objectLength = passageNormalToPathVerticalInMeters * factor;
|
||||
_objectHeight = passageNormalToPathHorizontalInMeters * factor;
|
||||
|
||||
// 参数改变时刷新所有普通路径(因为RibbonLine模式也使用车辆宽度)
|
||||
// 参数改变时刷新所有普通路径(因为RibbonLine模式也使用物体宽度)
|
||||
RefreshNormalPaths();
|
||||
}
|
||||
|
||||
@ -2152,7 +2152,7 @@ namespace NavisworksTransport
|
||||
case RenderStyleName.Line:
|
||||
return new RenderStyle(Color.FromByteRGB(255, 152, 0), 0.8); // Material Orange连线,20%透明
|
||||
|
||||
case RenderStyleName.VehicleSpace:
|
||||
case RenderStyleName.ObjectSpace:
|
||||
{
|
||||
// 从配置读取通行空间透明度,默认为0.4(40%不透明,60%透明)
|
||||
double opacity = ConfigManager.Instance.Current.Visualization.PassageSpaceOpacity;
|
||||
@ -2759,7 +2759,7 @@ namespace NavisworksTransport
|
||||
lineMarker.SampledPoints != null &&
|
||||
lineMarker.SampledPoints.Count >= 2)
|
||||
{
|
||||
// 圆弧段:在每个采样点渲染完整的车辆长方体
|
||||
// 圆弧段:在每个采样点渲染完整的物体长方体
|
||||
RenderArcSegmentCuboids(graphics, lineMarker, width);
|
||||
}
|
||||
else
|
||||
@ -2779,8 +2779,8 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渲染圆弧段的车辆长方体
|
||||
/// 在每个采样点处渲染一个完整的车辆长方体,中心在采样点,向前后各延伸 L/2
|
||||
/// 渲染圆弧段的物体长方体
|
||||
/// 在每个采样点处渲染一个完整的物体长方体,中心在采样点,向前后各延伸 L/2
|
||||
/// </summary>
|
||||
/// <param name="graphics">图形上下文</param>
|
||||
/// <param name="lineMarker">连线标记(必须是圆弧段)</param>
|
||||
@ -2790,7 +2790,7 @@ namespace NavisworksTransport
|
||||
// 设置颜色和透明度
|
||||
graphics.Color(lineMarker.Color, lineMarker.Opacity);
|
||||
|
||||
// 在每个采样点处渲染完整的车辆长方体
|
||||
// 在每个采样点处渲染完整的物体长方体
|
||||
for (int i = 0; i < lineMarker.SampledPoints.Count; i++)
|
||||
{
|
||||
// 计算当前采样点的切线方向
|
||||
@ -2992,10 +2992,10 @@ namespace NavisworksTransport
|
||||
private void RenderLineMarker(Graphics graphics, LineMarker lineMarker)
|
||||
{
|
||||
// 🔥 路径线渲染逻辑:保持原有行为
|
||||
// 注意:ShowVehicleSpace 的通行空间使用 RenderRibbonLineMarker 单独渲染
|
||||
if (_visualizationMode == PathVisualizationMode.VehicleSpace || _visualizationMode == PathVisualizationMode.RibbonLine)
|
||||
// 注意:ShowObjectSpace 的通行空间使用 RenderRibbonLineMarker 单独渲染
|
||||
if (_visualizationMode == PathVisualizationMode.ObjectSpace || _visualizationMode == PathVisualizationMode.RibbonLine)
|
||||
{
|
||||
// VehicleSpace 或 RibbonLine 模式:使用长方体渲染
|
||||
// ObjectSpace 或 RibbonLine 模式:使用长方体渲染
|
||||
RenderRibbonLineMarker(graphics, lineMarker);
|
||||
}
|
||||
else
|
||||
@ -3039,14 +3039,14 @@ namespace NavisworksTransport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 延伸线段起点和终点以完全包裹物体(VehicleSpace模式)
|
||||
/// 延伸线段起点和终点以完全包裹物体(ObjectSpace模式)
|
||||
/// </summary>
|
||||
/// <param name="startPoint">起点(会被修改)</param>
|
||||
/// <param name="endPoint">终点(会被修改)</param>
|
||||
private void ExtendLineSegmentForVehicleSpace(ref Point3D startPoint, ref Point3D endPoint, double alongPathSize)
|
||||
private void ExtendLineSegmentForObjectSpace(ref Point3D startPoint, ref Point3D endPoint, double alongPathSize)
|
||||
{
|
||||
// 注意:调用此方法前应该检查 _showVehicleSpace
|
||||
if (!_showVehicleSpace)
|
||||
// 注意:调用此方法前应该检查 _showObjectSpace
|
||||
if (!_showObjectSpace)
|
||||
return;
|
||||
|
||||
var segDx = endPoint.X - startPoint.X;
|
||||
|
||||
@ -4,6 +4,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Autodesk.Navisworks.Api;
|
||||
using g4;
|
||||
using NavisworksTransport.Utils;
|
||||
|
||||
// 使用命名空间引用以避免类名冲突
|
||||
using ClashIntegration = NavisworksTransport.ClashDetectiveIntegration;
|
||||
@ -152,6 +153,7 @@ namespace NavisworksTransport.Core.Spatial
|
||||
|
||||
/// <summary>
|
||||
/// 范围查询:查找指定位置附近的对象
|
||||
/// 支持剖面盒精筛(如果剖面盒已启用)
|
||||
/// </summary>
|
||||
/// <param name="position">查询中心位置(Navisworks Point3D)</param>
|
||||
/// <param name="searchRadiusInModelUnits">查询半径(模型单位)</param>
|
||||
@ -175,7 +177,7 @@ namespace NavisworksTransport.Core.Spatial
|
||||
// 转换为 geometry4Sharp 的 Vector3d
|
||||
var centerVec = new Vector3d(position.X, position.Y, position.Z);
|
||||
|
||||
// 使用空间哈希网格进行范围查询(带精确距离检查)
|
||||
// 步骤1:使用空间哈希网格进行范围查询(快速粗筛)
|
||||
var nearbyObjects = _globalSpatialIndex.FindInRadiusExact(
|
||||
centerVec,
|
||||
searchRadiusInModelUnits,
|
||||
@ -197,7 +199,23 @@ namespace NavisworksTransport.Core.Spatial
|
||||
}
|
||||
);
|
||||
|
||||
// 排除指定对象
|
||||
// 步骤2:剖面盒精筛(如果启用)
|
||||
int beforeClipFilter = nearbyObjects.Count;
|
||||
if (SectionClipHelper.IsClipBoxEnabled)
|
||||
{
|
||||
nearbyObjects = nearbyObjects
|
||||
.Where(item => SectionClipHelper.IntersectsClipBox(item.BoundingBox()))
|
||||
.ToList();
|
||||
|
||||
int filteredCount = beforeClipFilter - nearbyObjects.Count;
|
||||
LogManager.Debug($"[空间查询] 剖面盒过滤: 粗筛{beforeClipFilter}个 → 精筛{nearbyObjects.Count}个,过滤{filteredCount}个({(beforeClipFilter > 0 ? filteredCount*100.0/beforeClipFilter : 0):F1}%)");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Debug($"[空间查询] 剖面盒未启用,使用全部{beforeClipFilter}个对象");
|
||||
}
|
||||
|
||||
// 步骤3:排除指定对象
|
||||
if (excludeObject != null)
|
||||
{
|
||||
nearbyObjects = nearbyObjects.Where(obj => !obj.Equals(excludeObject)).ToList();
|
||||
@ -240,6 +258,7 @@ namespace NavisworksTransport.Core.Spatial
|
||||
/// <summary>
|
||||
/// AABB范围查询:查找与指定AABB相交的对象
|
||||
/// 比球形查询更精确,避免球体扩大的无效范围
|
||||
/// 支持剖面盒精筛(如果剖面盒已启用)
|
||||
/// </summary>
|
||||
/// <param name="bounds">查询AABB(Navisworks BoundingBox3D)</param>
|
||||
/// <param name="excludeObject">要排除的对象</param>
|
||||
@ -256,10 +275,40 @@ namespace NavisworksTransport.Core.Spatial
|
||||
|
||||
try
|
||||
{
|
||||
// 直接使用AABB查询(更精确)
|
||||
// 步骤1:使用空间索引进行AABB查询(快速粗筛)
|
||||
var nearbyObjects = _globalSpatialIndex.FindInAABB(bounds);
|
||||
|
||||
// 排除指定对象
|
||||
// 步骤2:剖面盒精筛(如果启用)
|
||||
int beforeClipFilter = nearbyObjects.Count;
|
||||
if (SectionClipHelper.IsClipBoxEnabled)
|
||||
{
|
||||
int intersectCount = 0;
|
||||
int outsideCount = 0;
|
||||
nearbyObjects = nearbyObjects
|
||||
.Where(item => {
|
||||
bool intersects = SectionClipHelper.IntersectsClipBox(item.BoundingBox());
|
||||
if (intersects) intersectCount++;
|
||||
else outsideCount++;
|
||||
return intersects;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
int filteredCount = beforeClipFilter - nearbyObjects.Count;
|
||||
LogManager.Debug($"[AABB查询] 剖面盒过滤: 粗筛{beforeClipFilter}个 → 精筛{nearbyObjects.Count}个,过滤{filteredCount}个({(beforeClipFilter > 0 ? filteredCount*100.0/beforeClipFilter : 0):F1}%)");
|
||||
|
||||
// 如果全部过滤,输出警告并采样被过滤的对象
|
||||
if (nearbyObjects.Count == 0 && beforeClipFilter > 0)
|
||||
{
|
||||
SectionClipHelper.TryGetCurrentClipBox(out var clipBox);
|
||||
LogManager.Warning($"[AABB查询] 剖面盒过滤后无对象!剖面盒范围: X[{clipBox.Min.X:F2},{clipBox.Max.X:F2}], Y[{clipBox.Min.Y:F2},{clipBox.Max.Y:F2}], Z[{clipBox.Min.Z:F2},{clipBox.Max.Z:F2}]");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Debug($"[AABB查询] 剖面盒未启用,使用全部{beforeClipFilter}个对象");
|
||||
}
|
||||
|
||||
// 步骤3:排除指定对象
|
||||
if (excludeObject != null)
|
||||
{
|
||||
nearbyObjects = nearbyObjects.Where(obj => !obj.Equals(excludeObject)).ToList();
|
||||
|
||||
@ -7,18 +7,18 @@ using Autodesk.Navisworks.Api;
|
||||
namespace NavisworksTransport.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// 虚拟车辆管理器 - 负责创建和管理虚拟车辆几何体
|
||||
/// 通过追加预制的单位立方体NWC文件并缩放来创建指定尺寸的虚拟车辆
|
||||
/// 虚拟物体管理器 - 负责创建和管理虚拟物体几何体
|
||||
/// 通过追加预制的单位立方体NWC文件并缩放来创建指定尺寸的虚拟物体
|
||||
/// </summary>
|
||||
public class VirtualVehicleManager
|
||||
public class VirtualObjectManager
|
||||
{
|
||||
private static VirtualVehicleManager _instance;
|
||||
private static VirtualObjectManager _instance;
|
||||
private static readonly object _lock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 单例实例
|
||||
/// </summary>
|
||||
public static VirtualVehicleManager Instance
|
||||
public static VirtualObjectManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -28,7 +28,7 @@ namespace NavisworksTransport.Core
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new VirtualVehicleManager();
|
||||
_instance = new VirtualObjectManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -36,167 +36,167 @@ namespace NavisworksTransport.Core
|
||||
}
|
||||
}
|
||||
|
||||
private ModelItem _virtualVehicleModelItem;
|
||||
private Model _virtualVehicleModel;
|
||||
private bool _isVirtualVehicleActive;
|
||||
private ModelItem _virtualObjectModelItem;
|
||||
private Model _virtualObjectModel;
|
||||
private bool _isVirtualObjectActive;
|
||||
|
||||
// 🔥 新增:标记是否正在更新虚拟车辆,用于避免触发缓存重建
|
||||
private bool _isUpdatingVirtualVehicle = false;
|
||||
// 🔥 新增:标记是否正在更新虚拟物体,用于避免触发缓存重建
|
||||
private bool _isUpdatingVirtualObject = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否正在更新虚拟车辆(用于外部检测是否应该跳过缓存重建)
|
||||
/// 是否正在更新虚拟物体(用于外部检测是否应该跳过缓存重建)
|
||||
/// </summary>
|
||||
public bool IsUpdatingVirtualVehicle => _isUpdatingVirtualVehicle;
|
||||
public bool IsUpdatingVirtualObject => _isUpdatingVirtualObject;
|
||||
|
||||
// 🔥 记住虚拟车辆的尺寸变换参数(避免动态计算)
|
||||
// 🔥 记住虚拟物体的尺寸变换参数(避免动态计算)
|
||||
private double _currentLengthMeters = 0;
|
||||
private double _currentWidthMeters = 0;
|
||||
private double _currentHeightMeters = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 当前虚拟车辆ModelItem
|
||||
/// 当前虚拟物体ModelItem
|
||||
/// </summary>
|
||||
public ModelItem CurrentVirtualVehicle => _virtualVehicleModelItem;
|
||||
public ModelItem CurrentVirtualObject => _virtualObjectModelItem;
|
||||
|
||||
/// <summary>
|
||||
/// 虚拟车辆是否激活
|
||||
/// 虚拟物体是否激活
|
||||
/// </summary>
|
||||
public bool IsVirtualVehicleActive => _isVirtualVehicleActive;
|
||||
public bool IsVirtualObjectActive => _isVirtualObjectActive;
|
||||
|
||||
private VirtualVehicleManager()
|
||||
private VirtualObjectManager()
|
||||
{
|
||||
_isVirtualVehicleActive = false;
|
||||
_isVirtualObjectActive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示虚拟车辆
|
||||
/// 显示虚拟物体
|
||||
/// </summary>
|
||||
/// <param name="lengthMeters">长度(米)</param>
|
||||
/// <param name="widthMeters">宽度(米)</param>
|
||||
/// <param name="heightMeters">高度(米)</param>
|
||||
public void ShowVirtualVehicle(double lengthMeters, double widthMeters, double heightMeters)
|
||||
public void ShowVirtualObject(double lengthMeters, double widthMeters, double heightMeters)
|
||||
{
|
||||
// 🔥 设置标志,防止文档变化事件触发缓存重建
|
||||
_isUpdatingVirtualVehicle = true;
|
||||
_isUpdatingVirtualObject = true;
|
||||
|
||||
try
|
||||
{
|
||||
var doc = Application.ActiveDocument;
|
||||
|
||||
// 检查虚拟车辆模型是否已存在
|
||||
if (_virtualVehicleModel != null)
|
||||
// 检查虚拟物体模型是否已存在
|
||||
if (_virtualObjectModel != null)
|
||||
{
|
||||
int currentIndex = doc.Models.IndexOf(_virtualVehicleModel);
|
||||
int currentIndex = doc.Models.IndexOf(_virtualObjectModel);
|
||||
if (currentIndex >= 0)
|
||||
{
|
||||
// 模型存在,显示它并更新尺寸
|
||||
LogManager.Info($"虚拟车辆模型已存在(索引: {currentIndex}),显示并更新尺寸");
|
||||
LogManager.Info($"虚拟物体模型已存在(索引: {currentIndex}),显示并更新尺寸");
|
||||
|
||||
var modelItems = new ModelItemCollection { _virtualVehicleModelItem };
|
||||
var modelItems = new ModelItemCollection { _virtualObjectModelItem };
|
||||
doc.Models.SetHidden(modelItems, false);
|
||||
|
||||
// 获取实际的几何体项
|
||||
_virtualVehicleModelItem = _virtualVehicleModel.RootItem;
|
||||
var geometryItem = FindFirstGeometryItem(_virtualVehicleModelItem);
|
||||
if (geometryItem != null && !geometryItem.Equals(_virtualVehicleModelItem))
|
||||
_virtualObjectModelItem = _virtualObjectModel.RootItem;
|
||||
var geometryItem = FindFirstGeometryItem(_virtualObjectModelItem);
|
||||
if (geometryItem != null && !geometryItem.Equals(_virtualObjectModelItem))
|
||||
{
|
||||
_virtualVehicleModelItem = geometryItem;
|
||||
_virtualObjectModelItem = geometryItem;
|
||||
}
|
||||
|
||||
// 清除覆盖变换(之前动画移动和旋转的累积)
|
||||
modelItems.Clear();
|
||||
modelItems.Add(_virtualVehicleModelItem);
|
||||
modelItems.Add(_virtualObjectModelItem);
|
||||
doc.Models.ResetPermanentTransform(modelItems);
|
||||
|
||||
// 重置变换并缩放到目标尺寸
|
||||
ResetVirtualVehicleTransform();
|
||||
ScaleVirtualVehicle(lengthMeters, widthMeters, heightMeters);
|
||||
ResetVirtualObjectTransform();
|
||||
ScaleVirtualObject(lengthMeters, widthMeters, heightMeters);
|
||||
|
||||
_isVirtualVehicleActive = true;
|
||||
LogManager.Info($"虚拟车辆更新成功");
|
||||
_isVirtualObjectActive = true;
|
||||
LogManager.Info($"虚拟物体更新成功");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning($"已保存的虚拟车辆模型不在文档中,需要重新创建");
|
||||
LogManager.Warning($"已保存的虚拟物体模型不在文档中,需要重新创建");
|
||||
}
|
||||
}
|
||||
|
||||
// 模型不存在,创建新的
|
||||
CreateVirtualVehicleInternal(doc, lengthMeters, widthMeters, heightMeters);
|
||||
CreateVirtualObjectInternal(doc, lengthMeters, widthMeters, heightMeters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"显示虚拟车辆失败: {ex.Message}");
|
||||
LogManager.Error($"显示虚拟物体失败: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 🔥 清除标志
|
||||
_isUpdatingVirtualVehicle = false;
|
||||
_isUpdatingVirtualObject = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏虚拟车辆
|
||||
/// 隐藏虚拟物体
|
||||
/// </summary>
|
||||
public void HideVirtualVehicle()
|
||||
public void HideVirtualObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_virtualVehicleModelItem != null)
|
||||
if (_virtualObjectModelItem != null)
|
||||
{
|
||||
var doc = Application.ActiveDocument;
|
||||
var modelItems = new ModelItemCollection { _virtualVehicleModelItem };
|
||||
var modelItems = new ModelItemCollection { _virtualObjectModelItem };
|
||||
doc.Models.SetHidden(modelItems, true);
|
||||
|
||||
LogManager.Info($"已隐藏虚拟车辆模型");
|
||||
LogManager.Info($"已隐藏虚拟物体模型");
|
||||
}
|
||||
|
||||
// 隐藏时设置为非激活状态,但保留模型引用
|
||||
_isVirtualVehicleActive = false;
|
||||
_isVirtualObjectActive = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"隐藏虚拟车辆失败: {ex.Message}");
|
||||
_isVirtualVehicleActive = false;
|
||||
LogManager.Error($"隐藏虚拟物体失败: {ex.Message}");
|
||||
_isVirtualObjectActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建虚拟车辆(内部方法)
|
||||
/// 创建虚拟物体(内部方法)
|
||||
/// </summary>
|
||||
private void CreateVirtualVehicleInternal(Document doc, double lengthMeters, double widthMeters, double heightMeters)
|
||||
private void CreateVirtualObjectInternal(Document doc, double lengthMeters, double widthMeters, double heightMeters)
|
||||
{
|
||||
LogManager.Info($"=== 创建虚拟车辆 ===");
|
||||
LogManager.Info($"=== 创建虚拟物体 ===");
|
||||
LogManager.Info($"目标尺寸: {lengthMeters:F2}m × {widthMeters:F2}m × {heightMeters:F2}m");
|
||||
|
||||
// 加载新的虚拟车辆模型
|
||||
LoadNewVirtualVehicleModel(doc);
|
||||
// 加载新的虚拟物体模型
|
||||
LoadNewVirtualObjectModel(doc);
|
||||
|
||||
// 获取实际的几何体项
|
||||
_virtualVehicleModelItem = _virtualVehicleModel.RootItem;
|
||||
var geometryItem = FindFirstGeometryItem(_virtualVehicleModelItem);
|
||||
if (geometryItem != null && !geometryItem.Equals(_virtualVehicleModelItem))
|
||||
_virtualObjectModelItem = _virtualObjectModel.RootItem;
|
||||
var geometryItem = FindFirstGeometryItem(_virtualObjectModelItem);
|
||||
if (geometryItem != null && !geometryItem.Equals(_virtualObjectModelItem))
|
||||
{
|
||||
_virtualVehicleModelItem = geometryItem;
|
||||
_virtualObjectModelItem = geometryItem;
|
||||
}
|
||||
|
||||
// 重置变换并缩放到目标尺寸
|
||||
ResetVirtualVehicleTransform();
|
||||
ScaleVirtualVehicle(lengthMeters, widthMeters, heightMeters);
|
||||
ResetVirtualObjectTransform();
|
||||
ScaleVirtualObject(lengthMeters, widthMeters, heightMeters);
|
||||
|
||||
// 设置状态
|
||||
_isVirtualVehicleActive = true;
|
||||
_isVirtualObjectActive = true;
|
||||
|
||||
LogManager.Info($"虚拟车辆创建成功");
|
||||
LogManager.Info($"虚拟物体创建成功");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载新的虚拟车辆模型
|
||||
/// 加载新的虚拟物体模型
|
||||
/// </summary>
|
||||
private void LoadNewVirtualVehicleModel(Document doc)
|
||||
private void LoadNewVirtualObjectModel(Document doc)
|
||||
{
|
||||
LogManager.Info($"需要加载新的虚拟车辆模型");
|
||||
LogManager.Info($"需要加载新的虚拟物体模型");
|
||||
|
||||
// 1. 获取单位立方体文件路径
|
||||
var unitCubePath = GetUnitCubeFilePath();
|
||||
@ -227,19 +227,19 @@ namespace NavisworksTransport.Core
|
||||
}
|
||||
|
||||
// 保存模型引用(最后一个模型就是刚追加的)
|
||||
_virtualVehicleModel = doc.Models.Last();
|
||||
_virtualObjectModel = doc.Models.Last();
|
||||
|
||||
LogManager.Info($"虚拟车辆模型: {_virtualVehicleModel.FileName}");
|
||||
LogManager.Info($"虚拟车辆根项: {_virtualVehicleModel.RootItem.DisplayName}");
|
||||
LogManager.Info($"虚拟物体模型: {_virtualObjectModel.FileName}");
|
||||
LogManager.Info($"虚拟物体根项: {_virtualObjectModel.RootItem.DisplayName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// 重置虚拟车辆变换为单位矩阵(公开方法,供批处理使用)
|
||||
/// 重置虚拟物体变换为单位矩阵(公开方法,供批处理使用)
|
||||
/// </summary>
|
||||
public void ResetVirtualVehicleTransform()
|
||||
public void ResetVirtualObjectTransform()
|
||||
{
|
||||
if (_virtualVehicleModel == null) return;
|
||||
if (_virtualObjectModel == null) return;
|
||||
|
||||
var doc = Application.ActiveDocument;
|
||||
|
||||
@ -248,19 +248,19 @@ namespace NavisworksTransport.Core
|
||||
Transform3DComponents identityComponents = identityTransform.Factor();
|
||||
|
||||
// 应用单位变换
|
||||
Units currentUnits = _virtualVehicleModel.Units;
|
||||
doc.Models.SetModelUnitsAndTransform(_virtualVehicleModel, currentUnits, identityTransform, false);
|
||||
Units currentUnits = _virtualObjectModel.Units;
|
||||
doc.Models.SetModelUnitsAndTransform(_virtualObjectModel, currentUnits, identityTransform, false);
|
||||
|
||||
LogManager.Info("已重置虚拟车辆变换");
|
||||
LogManager.Info("已重置虚拟物体变换");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缩放虚拟车辆到目标尺寸
|
||||
/// 缩放虚拟物体到目标尺寸
|
||||
/// 使用DocumentModels.SetModelUnitsAndTransform方法进行模型级缩放
|
||||
/// </summary>
|
||||
private void ScaleVirtualVehicle(double lengthMeters, double widthMeters, double heightMeters)
|
||||
private void ScaleVirtualObject(double lengthMeters, double widthMeters, double heightMeters)
|
||||
{
|
||||
if (_virtualVehicleModel == null || _virtualVehicleModelItem == null) return;
|
||||
if (_virtualObjectModel == null || _virtualObjectModelItem == null) return;
|
||||
|
||||
var doc = Application.ActiveDocument;
|
||||
|
||||
@ -272,21 +272,21 @@ namespace NavisworksTransport.Core
|
||||
// 获取单位转换因子(米到模型单位)
|
||||
double metersToUnits = Utils.UnitsConverter.GetMetersToUnitsConversionFactor(doc.Units);
|
||||
|
||||
// 🔥 对于虚拟车辆,直接应用缩放比例(不动态读取当前尺寸)
|
||||
// 原因:虚拟车辆可能被旋转,导致包围盒尺寸不准确
|
||||
// 🔥 对于虚拟物体,直接应用缩放比例(不动态读取当前尺寸)
|
||||
// 原因:虚拟物体可能被旋转,导致包围盒尺寸不准确
|
||||
// 单位立方体是 0.01m × 0.01m × 0.01m
|
||||
// X方向 = 车辆长度(前进方向),Y方向 = 车辆宽度(侧面),Z方向 = 车辆高度
|
||||
// X方向 = 物体长度(前进方向),Y方向 = 物体宽度(侧面),Z方向 = 物体高度
|
||||
double baseSizeMeters = 0.01;
|
||||
double scaleX = lengthMeters / baseSizeMeters; // X方向 = 车辆长度(前进方向)
|
||||
double scaleY = widthMeters / baseSizeMeters; // Y方向 = 车辆宽度(侧面)
|
||||
double scaleZ = heightMeters / baseSizeMeters; // Z方向 = 车辆高度
|
||||
double scaleX = lengthMeters / baseSizeMeters; // X方向 = 物体长度(前进方向)
|
||||
double scaleY = widthMeters / baseSizeMeters; // Y方向 = 物体宽度(侧面)
|
||||
double scaleZ = heightMeters / baseSizeMeters; // Z方向 = 物体高度
|
||||
|
||||
LogManager.Info($"目标尺寸: 长度={lengthMeters:F2}m, 宽度={widthMeters:F2}m, 高度={heightMeters:F2}m");
|
||||
LogManager.Info($"缩放比例: X(长度)={scaleX:F2}, Y(宽度)={scaleY:F2}, Z(高度)={scaleZ:F2}");
|
||||
|
||||
// 使用Transform3DComponents进行缩放
|
||||
// 获取当前模型的变换并分解
|
||||
Transform3D currentTransform = _virtualVehicleModel.Transform;
|
||||
Transform3D currentTransform = _virtualObjectModel.Transform;
|
||||
Transform3DComponents transformComponents = currentTransform.Factor();
|
||||
|
||||
// 获取当前值
|
||||
@ -304,13 +304,13 @@ namespace NavisworksTransport.Core
|
||||
Transform3D newTransform = transformComponents.Combine();
|
||||
|
||||
// 获取当前模型单位
|
||||
Units currentUnits = _virtualVehicleModel.Units;
|
||||
Units currentUnits = _virtualObjectModel.Units;
|
||||
|
||||
// 应用新的变换
|
||||
doc.Models.SetModelUnitsAndTransform(_virtualVehicleModel, currentUnits, newTransform, false);
|
||||
doc.Models.SetModelUnitsAndTransform(_virtualObjectModel, currentUnits, newTransform, false);
|
||||
|
||||
// 验证缩放结果
|
||||
var newBoundingBox = _virtualVehicleModelItem.BoundingBox();
|
||||
var newBoundingBox = _virtualObjectModelItem.BoundingBox();
|
||||
double newLength = newBoundingBox.Max.X - newBoundingBox.Min.X;
|
||||
double newWidth = newBoundingBox.Max.Y - newBoundingBox.Min.Y;
|
||||
double newHeight = newBoundingBox.Max.Z - newBoundingBox.Min.Z;
|
||||
@ -323,18 +323,18 @@ namespace NavisworksTransport.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除虚拟车辆(使用 TryRemoveFile 真正删除模型)
|
||||
/// 移除虚拟物体(使用 TryRemoveFile 真正删除模型)
|
||||
/// </summary>
|
||||
public void RemoveVirtualVehicle()
|
||||
public void RemoveVirtualObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = Application.ActiveDocument;
|
||||
|
||||
if (_virtualVehicleModel != null)
|
||||
if (_virtualObjectModel != null)
|
||||
{
|
||||
// 动态查找模型索引
|
||||
int currentIndex = doc.Models.IndexOf(_virtualVehicleModel);
|
||||
int currentIndex = doc.Models.IndexOf(_virtualObjectModel);
|
||||
|
||||
if (currentIndex >= 0)
|
||||
{
|
||||
@ -343,30 +343,30 @@ namespace NavisworksTransport.Core
|
||||
|
||||
if (removed)
|
||||
{
|
||||
LogManager.Info($"已删除虚拟车辆模型(索引: {currentIndex})");
|
||||
LogManager.Info($"已删除虚拟物体模型(索引: {currentIndex})");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning($"删除虚拟车辆模型失败(索引: {currentIndex})");
|
||||
LogManager.Warning($"删除虚拟物体模型失败(索引: {currentIndex})");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning($"虚拟车辆模型不在文档中,无法删除");
|
||||
LogManager.Warning($"虚拟物体模型不在文档中,无法删除");
|
||||
}
|
||||
}
|
||||
|
||||
// 清理引用
|
||||
_virtualVehicleModel = null;
|
||||
_virtualVehicleModelItem = null;
|
||||
_isVirtualVehicleActive = false;
|
||||
_virtualObjectModel = null;
|
||||
_virtualObjectModelItem = null;
|
||||
_isVirtualObjectActive = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"删除虚拟车辆失败: {ex.Message}");
|
||||
_virtualVehicleModel = null;
|
||||
_virtualVehicleModelItem = null;
|
||||
_isVirtualVehicleActive = false;
|
||||
LogManager.Error($"删除虚拟物体失败: {ex.Message}");
|
||||
_virtualObjectModel = null;
|
||||
_virtualObjectModelItem = null;
|
||||
_isVirtualObjectActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,7 +431,7 @@ namespace NavisworksTransport.Core
|
||||
/// </summary>
|
||||
public void Cleanup()
|
||||
{
|
||||
RemoveVirtualVehicle();
|
||||
RemoveVirtualObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,14 +123,14 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// <summary>
|
||||
/// 真3D路径规划(使用通道覆盖数据、高度约束和路径策略)
|
||||
/// </summary>
|
||||
public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, PathStrategy strategy = PathStrategy.Shortest)
|
||||
public PathFindingResult FindPath(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double objectHeight, PathStrategy strategy = PathStrategy.Shortest)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info("[3D路径规划] 开始执行");
|
||||
|
||||
// 构建3D图
|
||||
var graph3D = BuildGraphWithStrategy(gridMap, channelCoverage, vehicleHeight, start, end, strategy);
|
||||
var graph3D = BuildGraphWithStrategy(gridMap, channelCoverage, objectHeight, start, end, strategy);
|
||||
|
||||
// 执行A*搜索
|
||||
var pathResult = ExecuteAStarOnGraph(start, end, gridMap, graph3D);
|
||||
@ -159,7 +159,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// <summary>
|
||||
/// 构建3D图(每个(x,y,layerIndex)作为独立节点)
|
||||
/// </summary>
|
||||
private Graph3DResult BuildGraph3D(GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, Point3D startPos, Point3D endPos, SpeedCalculator speedCalculator = null)
|
||||
private Graph3DResult BuildGraph3D(GridMap gridMap, ChannelCoverage channelCoverage, double objectHeight, Point3D startPos, Point3D endPos, SpeedCalculator speedCalculator = null)
|
||||
{
|
||||
LogManager.Info("[3D图构建] 开始构建真3D图");
|
||||
|
||||
@ -200,7 +200,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
continue;
|
||||
}
|
||||
|
||||
if (layer.PassableHeight.GetSpan() < vehicleHeight)
|
||||
if (layer.PassableHeight.GetSpan() < objectHeight)
|
||||
continue;
|
||||
|
||||
// 使用2D位置(用于A*启发式)
|
||||
@ -239,7 +239,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
for (int li = 0; li < cell.HeightLayers.Count; li++)
|
||||
{
|
||||
var currentLayer = cell.HeightLayers[li];
|
||||
if (currentLayer.PassableHeight.GetSpan() < vehicleHeight)
|
||||
if (currentLayer.PassableHeight.GetSpan() < objectHeight)
|
||||
continue;
|
||||
|
||||
if (!nodes.TryGetValue((x, y, li), out var currentNode))
|
||||
@ -263,7 +263,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
for (int nli = 0; nli < neighborCell.HeightLayers.Count; nli++)
|
||||
{
|
||||
var neighborLayer = neighborCell.HeightLayers[nli];
|
||||
if (neighborLayer.PassableHeight.GetSpan() < vehicleHeight)
|
||||
if (neighborLayer.PassableHeight.GetSpan() < objectHeight)
|
||||
continue;
|
||||
|
||||
double heightDiff = Math.Abs(neighborLayer.Z - currentZ);
|
||||
@ -331,8 +331,8 @@ namespace NavisworksTransport.PathPlanning
|
||||
layer1.Type != CategoryAttributeManager.LogisticsElementType.电梯)
|
||||
continue;
|
||||
|
||||
if (layer1.PassableHeight.GetSpan() < vehicleHeight ||
|
||||
layer2.PassableHeight.GetSpan() < vehicleHeight)
|
||||
if (layer1.PassableHeight.GetSpan() < objectHeight ||
|
||||
layer2.PassableHeight.GetSpan() < objectHeight)
|
||||
continue;
|
||||
|
||||
double heightDiff = Math.Abs(layer2.Z - layer1.Z);
|
||||
@ -390,7 +390,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// <summary>
|
||||
/// 根据策略构建图
|
||||
/// </summary>
|
||||
private Graph3DResult BuildGraphWithStrategy(GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, Point3D startPos, Point3D endPos, PathStrategy strategy)
|
||||
private Graph3DResult BuildGraphWithStrategy(GridMap gridMap, ChannelCoverage channelCoverage, double objectHeight, Point3D startPos, Point3D endPos, PathStrategy strategy)
|
||||
{
|
||||
SpeedCalculator speedCalc = null;
|
||||
|
||||
@ -415,7 +415,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
var currentPos = new GridPoint2D(cx, cy);
|
||||
|
||||
// 计算沿该方向能够直走的距离
|
||||
int straightDistance = CalculateStraightDistance(currentPos, direction, gridMap, vehicleHeight);
|
||||
int straightDistance = CalculateStraightDistance(currentPos, direction, gridMap, objectHeight);
|
||||
|
||||
// 直走距离越长,速度加成越高(最多+30 km/h)
|
||||
float bonusSpeed = Math.Min(straightDistance * 0.5f, 30.0f);
|
||||
@ -458,7 +458,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
break;
|
||||
}
|
||||
|
||||
return BuildGraph3D(gridMap, channelCoverage, vehicleHeight, startPos, endPos, speedCalc);
|
||||
return BuildGraph3D(gridMap, channelCoverage, objectHeight, startPos, endPos, speedCalc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -723,7 +723,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// <summary>
|
||||
/// 2.5D路径规划(使用通道覆盖数据、高度约束和路径策略)[已废弃,保留作为备份]
|
||||
/// </summary>
|
||||
private PathFindingResult FindPath_Legacy_2_5D(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, PathStrategy strategy = PathStrategy.Shortest)
|
||||
private PathFindingResult FindPath_Legacy_2_5D(Point3D start, Point3D end, GridMap gridMap, ChannelCoverage channelCoverage, double objectHeight, PathStrategy strategy = PathStrategy.Shortest)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -735,19 +735,19 @@ namespace NavisworksTransport.PathPlanning
|
||||
|
||||
// 1. 检查起点和终点的高度约束
|
||||
var startGridPos = gridMap.WorldToGrid(start);
|
||||
if (!IsPointPassableAtHeight(startGridPos, start, gridMap, vehicleHeight))
|
||||
if (!IsPointPassableAtHeight(startGridPos, start, gridMap, objectHeight))
|
||||
{
|
||||
LogManager.Warning("[2.5D路径规划] 起点位置不满足高度约束");
|
||||
}
|
||||
|
||||
var endGridPos = gridMap.WorldToGrid(end);
|
||||
if (!IsPointPassableAtHeight(endGridPos, end, gridMap, vehicleHeight))
|
||||
if (!IsPointPassableAtHeight(endGridPos, end, gridMap, objectHeight))
|
||||
{
|
||||
LogManager.Warning("[2.5D路径规划] 终点位置不满足高度约束");
|
||||
}
|
||||
|
||||
// 2. 根据策略选择合适的网格转换方法(返回A*网格和激活层字典)
|
||||
var (astarGrid, activeLayerZ) = ConvertToAStarGridWithStrategy(gridMap, channelCoverage, vehicleHeight, start, end, strategy);
|
||||
var (astarGrid, activeLayerZ) = ConvertToAStarGridWithStrategy(gridMap, channelCoverage, objectHeight, start, end, strategy);
|
||||
|
||||
// 3. 执行A*算法
|
||||
var pathResult = ExecuteAStarAlgorithm(start, end, gridMap, astarGrid);
|
||||
@ -794,13 +794,13 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="channelCoverage">通道覆盖数据</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <returns>A*算法网格</returns>
|
||||
private (Grid grid, Dictionary<GridPoint2D, double> activeLayerZ) ConvertToAStarGridWith2_5D(GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, Point3D startPos, Point3D endPos)
|
||||
private (Grid grid, Dictionary<GridPoint2D, double> activeLayerZ) ConvertToAStarGridWith2_5D(GridMap gridMap, ChannelCoverage channelCoverage, double objectHeight, Point3D startPos, Point3D endPos)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info($"[A*转换-2.5D] 开始转换网格格式: {gridMap.Width}x{gridMap.Height},车辆高度: {vehicleHeight}m");
|
||||
LogManager.Info($"[A*转换-2.5D] 开始转换网格格式: {gridMap.Width}x{gridMap.Height},运动物体高度: {objectHeight}m");
|
||||
|
||||
// 初始化激活层字典
|
||||
var activeLayerZ = new Dictionary<GridPoint2D, double>();
|
||||
@ -871,8 +871,8 @@ namespace NavisworksTransport.PathPlanning
|
||||
totalNonWalkableCells++;
|
||||
}
|
||||
|
||||
// 检查是否有满足车辆高度的层
|
||||
if (!HasCompatibleLayer(cell, vehicleHeight))
|
||||
// 检查是否有满足运动物体高度的层
|
||||
if (!HasCompatibleLayer(cell, objectHeight))
|
||||
{
|
||||
if (cell.HasAnyWalkableLayer())
|
||||
{
|
||||
@ -882,7 +882,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
var layerInfo = cell.HeightLayers != null && cell.HeightLayers.Count > 0
|
||||
? $"有{cell.HeightLayers.Count}个高度层"
|
||||
: "无高度层";
|
||||
LogManager.Info($"[A*高度约束] 单元格({x},{y})被高度约束排除:车辆高度{vehicleHeight:F2}模型单位,{layerInfo}");
|
||||
LogManager.Info($"[A*高度约束] 单元格({x},{y})被高度约束排除:运动物体高度{objectHeight:F2}模型单位,{layerInfo}");
|
||||
}
|
||||
else if (heightConstrainedCells == 11)
|
||||
{
|
||||
@ -893,7 +893,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
|
||||
// 为当前单元格选择最优高度层
|
||||
var currentZ = SelectBestLayerForTarget(cell.HeightLayers, targetZ, vehicleHeight);
|
||||
var currentZ = SelectBestLayerForTarget(cell.HeightLayers, targetZ, objectHeight);
|
||||
if (!currentZ.HasValue)
|
||||
continue;
|
||||
|
||||
@ -908,7 +908,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (x + 1 < gridMap.Width)
|
||||
{
|
||||
var rightCell = gridMap.Cells[x + 1, y];
|
||||
var rightZ = SelectBestLayerForTarget(rightCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var rightZ = SelectBestLayerForTarget(rightCell.HeightLayers, targetZ, objectHeight);
|
||||
if (rightZ.HasValue)
|
||||
{
|
||||
var rightPos = new GridPosition(x + 1, y);
|
||||
@ -935,7 +935,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (y + 1 < gridMap.Height)
|
||||
{
|
||||
var bottomCell = gridMap.Cells[x, y + 1];
|
||||
var bottomZ = SelectBestLayerForTarget(bottomCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var bottomZ = SelectBestLayerForTarget(bottomCell.HeightLayers, targetZ, objectHeight);
|
||||
if (bottomZ.HasValue)
|
||||
{
|
||||
var bottomPos = new GridPosition(x, y + 1);
|
||||
@ -954,7 +954,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (x - 1 >= 0)
|
||||
{
|
||||
var leftCell = gridMap.Cells[x - 1, y];
|
||||
var leftZ = SelectBestLayerForTarget(leftCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var leftZ = SelectBestLayerForTarget(leftCell.HeightLayers, targetZ, objectHeight);
|
||||
if (leftZ.HasValue)
|
||||
{
|
||||
var leftPos = new GridPosition(x - 1, y);
|
||||
@ -973,7 +973,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (y - 1 >= 0)
|
||||
{
|
||||
var topCell = gridMap.Cells[x, y - 1];
|
||||
var topZ = SelectBestLayerForTarget(topCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var topZ = SelectBestLayerForTarget(topCell.HeightLayers, targetZ, objectHeight);
|
||||
if (topZ.HasValue)
|
||||
{
|
||||
var topPos = new GridPosition(x, y - 1);
|
||||
@ -1013,30 +1013,30 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="channelCoverage">通道覆盖数据</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <param name="startPos">起点坐标</param>
|
||||
/// <param name="endPos">终点坐标</param>
|
||||
/// <param name="strategy">路径规划策略</param>
|
||||
/// <returns>A*网格和激活层字典的元组</returns>
|
||||
private (Grid grid, Dictionary<GridPoint2D, double> activeLayerZ) ConvertToAStarGridWithStrategy(GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, Point3D startPos, Point3D endPos, PathStrategy strategy)
|
||||
private (Grid grid, Dictionary<GridPoint2D, double> activeLayerZ) ConvertToAStarGridWithStrategy(GridMap gridMap, ChannelCoverage channelCoverage, double objectHeight, Point3D startPos, Point3D endPos, PathStrategy strategy)
|
||||
{
|
||||
switch (strategy)
|
||||
{
|
||||
case PathStrategy.Shortest:
|
||||
LogManager.Info($"[策略路由] 使用最短路径策略");
|
||||
return ConvertToAStarGridWith2_5D(gridMap, channelCoverage, vehicleHeight, startPos, endPos);
|
||||
return ConvertToAStarGridWith2_5D(gridMap, channelCoverage, objectHeight, startPos, endPos);
|
||||
|
||||
case PathStrategy.Straightest:
|
||||
LogManager.Info($"[策略路由] 使用直线优先策略");
|
||||
return ConvertToAStarGridStraightest(gridMap, channelCoverage, vehicleHeight, startPos, endPos);
|
||||
return ConvertToAStarGridStraightest(gridMap, channelCoverage, objectHeight, startPos, endPos);
|
||||
|
||||
case PathStrategy.SafestCenter:
|
||||
LogManager.Info($"[策略路由] 使用安全优先策略");
|
||||
return ConvertToAStarGridSafestCenter(gridMap, channelCoverage, vehicleHeight, startPos, endPos);
|
||||
return ConvertToAStarGridSafestCenter(gridMap, channelCoverage, objectHeight, startPos, endPos);
|
||||
|
||||
default:
|
||||
LogManager.Warning($"[策略路由] 未知策略 {strategy},使用默认最短路径");
|
||||
return ConvertToAStarGridWith2_5D(gridMap, channelCoverage, vehicleHeight, startPos, endPos);
|
||||
return ConvertToAStarGridWith2_5D(gridMap, channelCoverage, objectHeight, startPos, endPos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1046,11 +1046,11 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="channelCoverage">通道覆盖数据</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <param name="startPos">起点坐标</param>
|
||||
/// <param name="endPos">终点坐标</param>
|
||||
/// <returns>A*网格</returns>
|
||||
private (Grid grid, Dictionary<GridPoint2D, double> activeLayerZ) ConvertToAStarGridStraightest(GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, Point3D startPos, Point3D endPos)
|
||||
private (Grid grid, Dictionary<GridPoint2D, double> activeLayerZ) ConvertToAStarGridStraightest(GridMap gridMap, ChannelCoverage channelCoverage, double objectHeight, Point3D startPos, Point3D endPos)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -1097,7 +1097,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
var cell = gridMap.Cells[x, y];
|
||||
|
||||
// 检查是否有兼容的高度层
|
||||
if (!HasCompatibleLayer(cell, vehicleHeight))
|
||||
if (!HasCompatibleLayer(cell, objectHeight))
|
||||
{
|
||||
if (cell.HasAnyWalkableLayer())
|
||||
{
|
||||
@ -1107,7 +1107,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
|
||||
// 选择当前网格的最佳高度层
|
||||
var currentZ = SelectBestLayerForTarget(cell.HeightLayers, targetZ, vehicleHeight);
|
||||
var currentZ = SelectBestLayerForTarget(cell.HeightLayers, targetZ, objectHeight);
|
||||
if (!currentZ.HasValue)
|
||||
{
|
||||
continue;
|
||||
@ -1126,10 +1126,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var rightCell = gridMap.Cells[x + 1, y];
|
||||
|
||||
// 检查右侧网格是否有兼容的高度层
|
||||
if (HasCompatibleLayer(rightCell, vehicleHeight))
|
||||
if (HasCompatibleLayer(rightCell, objectHeight))
|
||||
{
|
||||
// 选择右侧网格的最佳高度层
|
||||
var rightZ = SelectBestLayerForTarget(rightCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var rightZ = SelectBestLayerForTarget(rightCell.HeightLayers, targetZ, objectHeight);
|
||||
if (rightZ.HasValue)
|
||||
{
|
||||
var rightPos = new GridPosition(x + 1, y);
|
||||
@ -1139,7 +1139,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
activeLayerZ[rightGridPos] = rightZ.Value;
|
||||
|
||||
// 计算沿右方向的直线距离
|
||||
var rightDistance = CalculateStraightDistance(gridPos, new GridPoint2D(1, 0), gridMap, vehicleHeight);
|
||||
var rightDistance = CalculateStraightDistance(gridPos, new GridPoint2D(1, 0), gridMap, objectHeight);
|
||||
|
||||
// 计算基础速度(基于直线距离)
|
||||
float baseSpeed = 5.0f;
|
||||
@ -1165,10 +1165,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var bottomCell = gridMap.Cells[x, y + 1];
|
||||
|
||||
// 检查下方网格是否有兼容的高度层
|
||||
if (HasCompatibleLayer(bottomCell, vehicleHeight))
|
||||
if (HasCompatibleLayer(bottomCell, objectHeight))
|
||||
{
|
||||
// 选择下方网格的最佳高度层
|
||||
var bottomZ = SelectBestLayerForTarget(bottomCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var bottomZ = SelectBestLayerForTarget(bottomCell.HeightLayers, targetZ, objectHeight);
|
||||
if (bottomZ.HasValue)
|
||||
{
|
||||
var bottomPos = new GridPosition(x, y + 1);
|
||||
@ -1178,7 +1178,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
activeLayerZ[bottomGridPos] = bottomZ.Value;
|
||||
|
||||
// 计算沿下方向的直线距离
|
||||
var downDistance = CalculateStraightDistance(gridPos, new GridPoint2D(0, 1), gridMap, vehicleHeight);
|
||||
var downDistance = CalculateStraightDistance(gridPos, new GridPoint2D(0, 1), gridMap, objectHeight);
|
||||
|
||||
// 计算基础速度(基于直线距离)
|
||||
float baseSpeed = 5.0f;
|
||||
@ -1204,10 +1204,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var leftCell = gridMap.Cells[x - 1, y];
|
||||
|
||||
// 检查左侧网格是否有兼容的高度层
|
||||
if (HasCompatibleLayer(leftCell, vehicleHeight))
|
||||
if (HasCompatibleLayer(leftCell, objectHeight))
|
||||
{
|
||||
// 选择左侧网格的最佳高度层
|
||||
var leftZ = SelectBestLayerForTarget(leftCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var leftZ = SelectBestLayerForTarget(leftCell.HeightLayers, targetZ, objectHeight);
|
||||
if (leftZ.HasValue)
|
||||
{
|
||||
var leftPos = new GridPosition(x - 1, y);
|
||||
@ -1217,7 +1217,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
activeLayerZ[leftGridPos] = leftZ.Value;
|
||||
|
||||
// 计算沿左方向的直线距离
|
||||
var leftDistance = CalculateStraightDistance(gridPos, new GridPoint2D(-1, 0), gridMap, vehicleHeight);
|
||||
var leftDistance = CalculateStraightDistance(gridPos, new GridPoint2D(-1, 0), gridMap, objectHeight);
|
||||
|
||||
// 计算基础速度(基于直线距离)
|
||||
float baseSpeed = 5.0f;
|
||||
@ -1243,10 +1243,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var topCell = gridMap.Cells[x, y - 1];
|
||||
|
||||
// 检查上方网格是否有兼容的高度层
|
||||
if (HasCompatibleLayer(topCell, vehicleHeight))
|
||||
if (HasCompatibleLayer(topCell, objectHeight))
|
||||
{
|
||||
// 选择上方网格的最佳高度层
|
||||
var topZ = SelectBestLayerForTarget(topCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var topZ = SelectBestLayerForTarget(topCell.HeightLayers, targetZ, objectHeight);
|
||||
if (topZ.HasValue)
|
||||
{
|
||||
var topPos = new GridPosition(x, y - 1);
|
||||
@ -1256,7 +1256,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
activeLayerZ[topGridPos] = topZ.Value;
|
||||
|
||||
// 计算沿上方向的直线距离
|
||||
var upDistance = CalculateStraightDistance(gridPos, new GridPoint2D(0, -1), gridMap, vehicleHeight);
|
||||
var upDistance = CalculateStraightDistance(gridPos, new GridPoint2D(0, -1), gridMap, objectHeight);
|
||||
|
||||
// 计算基础速度(基于直线距离)
|
||||
float baseSpeed = 5.0f;
|
||||
@ -1281,9 +1281,9 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (x + 1 < gridMap.Width && y + 1 < gridMap.Height)
|
||||
{
|
||||
var diagonalCell = gridMap.Cells[x + 1, y + 1];
|
||||
if (HasCompatibleLayer(diagonalCell, vehicleHeight))
|
||||
if (HasCompatibleLayer(diagonalCell, objectHeight))
|
||||
{
|
||||
var diagonalZ = SelectBestLayerForTarget(diagonalCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var diagonalZ = SelectBestLayerForTarget(diagonalCell.HeightLayers, targetZ, objectHeight);
|
||||
if (diagonalZ.HasValue)
|
||||
{
|
||||
var diagonalPos = new GridPosition(x + 1, y + 1);
|
||||
@ -1317,19 +1317,19 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// 检查单元格是否满足高度约束
|
||||
/// </summary>
|
||||
/// <param name="cell">网格单元格</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <returns>是否可通行</returns>
|
||||
private bool IsPassableWithHeight(GridCell cell, double vehicleHeight)
|
||||
private bool IsPassableWithHeight(GridCell cell, double objectHeight)
|
||||
{
|
||||
if (!cell.HasAnyWalkableLayer())
|
||||
return false;
|
||||
|
||||
// 检查是否有任何高度层满足车辆高度要求
|
||||
// 检查是否有任何高度层满足运动物体高度要求
|
||||
if (cell.HeightLayers != null && cell.HeightLayers.Count > 0)
|
||||
{
|
||||
foreach (var layer in cell.HeightLayers)
|
||||
{
|
||||
if (layer.PassableHeight.GetSpan() >= vehicleHeight)
|
||||
if (layer.PassableHeight.GetSpan() >= objectHeight)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -1339,12 +1339,12 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查单元格是否有满足车辆高度的高度层
|
||||
/// 检查单元格是否有满足运动物体高度的高度层
|
||||
/// </summary>
|
||||
/// <param name="cell">网格单元格</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <returns>是否有兼容的高度层</returns>
|
||||
private bool HasCompatibleLayer(GridCell cell, double vehicleHeight)
|
||||
private bool HasCompatibleLayer(GridCell cell, double objectHeight)
|
||||
{
|
||||
if (!cell.HasAnyWalkableLayer())
|
||||
return false;
|
||||
@ -1354,7 +1354,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
|
||||
foreach (var layer in cell.HeightLayers)
|
||||
{
|
||||
if (layer.PassableHeight.GetSpan() >= vehicleHeight)
|
||||
if (layer.PassableHeight.GetSpan() >= objectHeight)
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1362,13 +1362,13 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从高度层列表中选择最接近目标高度且满足车辆高度的层
|
||||
/// 从高度层列表中选择最接近目标高度且满足运动物体高度的层
|
||||
/// </summary>
|
||||
/// <param name="layers">高度层列表</param>
|
||||
/// <param name="targetZ">目标高度(米)</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <returns>选中的高度层Z坐标,如果没有合适的返回null</returns>
|
||||
private double? SelectBestLayerForTarget(List<HeightLayer> layers, double targetZ, double vehicleHeight)
|
||||
private double? SelectBestLayerForTarget(List<HeightLayer> layers, double targetZ, double objectHeight)
|
||||
{
|
||||
if (layers == null || layers.Count == 0)
|
||||
return null;
|
||||
@ -1378,8 +1378,8 @@ namespace NavisworksTransport.PathPlanning
|
||||
|
||||
foreach (var layer in layers)
|
||||
{
|
||||
// 必须满足车辆高度
|
||||
if (layer.PassableHeight.GetSpan() < vehicleHeight)
|
||||
// 必须满足运动物体高度
|
||||
if (layer.PassableHeight.GetSpan() < objectHeight)
|
||||
continue;
|
||||
|
||||
// 选择最接近目标高度的层
|
||||
@ -1414,16 +1414,16 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// <param name="startPos">起始网格位置</param>
|
||||
/// <param name="direction">方向 (1,0)=右, (0,1)=下, (-1,0)=左, (0,-1)=上</param>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <returns>直线距离(网格单位)</returns>
|
||||
private int CalculateStraightDistance(GridPoint2D startPos, GridPoint2D direction,
|
||||
GridMap gridMap, double vehicleHeight)
|
||||
GridMap gridMap, double objectHeight)
|
||||
{
|
||||
int distance = 0;
|
||||
var currentPos = new GridPoint2D(startPos.X + direction.X, startPos.Y + direction.Y);
|
||||
|
||||
// 沿方向前进,直到遇到障碍
|
||||
while (IsValidAndPassable(currentPos, gridMap, vehicleHeight))
|
||||
while (IsValidAndPassable(currentPos, gridMap, objectHeight))
|
||||
{
|
||||
distance++;
|
||||
currentPos = new GridPoint2D(currentPos.X + direction.X, currentPos.Y + direction.Y);
|
||||
@ -1440,9 +1440,9 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="pos">网格位置</param>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <returns>是否有效且可通行</returns>
|
||||
private bool IsValidAndPassable(GridPoint2D pos, GridMap gridMap, double vehicleHeight)
|
||||
private bool IsValidAndPassable(GridPoint2D pos, GridMap gridMap, double objectHeight)
|
||||
{
|
||||
// 检查边界
|
||||
if (pos.X < 0 || pos.X >= gridMap.Width || pos.Y < 0 || pos.Y >= gridMap.Height)
|
||||
@ -1450,7 +1450,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
|
||||
// 检查可通行性
|
||||
var cell = gridMap.Cells[pos.X, pos.Y];
|
||||
return IsPassableWithHeight(cell, vehicleHeight);
|
||||
return IsPassableWithHeight(cell, objectHeight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -2034,9 +2034,9 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// <param name="gridPos">网格坐标</param>
|
||||
/// <param name="point">检查点(世界坐标)</param>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <returns>是否可通行</returns>
|
||||
private bool IsPointPassableAtHeight(GridPoint2D gridPos, Point3D point, GridMap gridMap, double vehicleHeight)
|
||||
private bool IsPointPassableAtHeight(GridPoint2D gridPos, Point3D point, GridMap gridMap, double objectHeight)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -2062,19 +2062,19 @@ namespace NavisworksTransport.PathPlanning
|
||||
// 检查高度层约束
|
||||
if (cell.HeightLayers != null && cell.HeightLayers.Count > 0)
|
||||
{
|
||||
// 查找包含指定Z坐标且满足车辆高度的层
|
||||
// 查找包含指定Z坐标且满足运动物体高度的层
|
||||
var matchingLayer = gridMap.FindLayerContainingZ(gridPos, point.Z, tolerance: 0.5);
|
||||
|
||||
if (matchingLayer.HasValue)
|
||||
{
|
||||
bool heightOk = matchingLayer.Value.PassableHeight.GetSpan() >= vehicleHeight;
|
||||
bool heightOk = matchingLayer.Value.PassableHeight.GetSpan() >= objectHeight;
|
||||
if (heightOk)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Warning($"[高度检查] ❌ 找到匹配Z={point.Z:F2}的层Z={matchingLayer.Value.Z:F2},但高度不足:车辆高度{vehicleHeight:F2},层高度跨度{matchingLayer.Value.PassableHeight.GetSpan():F2}");
|
||||
LogManager.Warning($"[高度检查] ❌ 找到匹配Z={point.Z:F2}的层Z={matchingLayer.Value.Z:F2},但高度不足:运动物体高度{objectHeight:F2},层高度跨度{matchingLayer.Value.PassableHeight.GetSpan():F2}");
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -2099,11 +2099,11 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="pathWithGridCoords">路径点和对应的网格坐标</param>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
/// <param name="originalStart">用户指定的原始起点(保留原始Z坐标)</param>
|
||||
/// <param name="originalEnd">用户指定的原始终点(保留原始Z坐标)</param>
|
||||
/// <returns>调整后的路径</returns>
|
||||
private List<Point3D> ApplyGridHeightConstraints(List<(Point3D point, GridPoint2D gridPos)> pathWithGridCoords, GridMap gridMap, double vehicleHeight, Point3D originalStart, Point3D originalEnd)
|
||||
private List<Point3D> ApplyGridHeightConstraints(List<(Point3D point, GridPoint2D gridPos)> pathWithGridCoords, GridMap gridMap, double objectHeight, Point3D originalStart, Point3D originalEnd)
|
||||
{
|
||||
LogManager.Info($"[智能选层] 开始为路径点选择最优高度层,路径点数: {pathWithGridCoords.Count}");
|
||||
|
||||
@ -2148,7 +2148,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
// 起点和终点:锁定到包含其Z坐标的层
|
||||
if (i == 0)
|
||||
{
|
||||
var selectedLayer = SelectBestLayer(cell.HeightLayers, startZ, vehicleHeight, startZ, endZ, i, pathWithGridCoords.Count, true);
|
||||
var selectedLayer = SelectBestLayer(cell.HeightLayers, startZ, objectHeight, startZ, endZ, i, pathWithGridCoords.Count, true);
|
||||
if (selectedLayer.HasValue)
|
||||
{
|
||||
adjustedPath.Add(new Point3D(point.X, point.Y, selectedLayer.Value.Z));
|
||||
@ -2161,7 +2161,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
else if (i == pathWithGridCoords.Count - 1)
|
||||
{
|
||||
var selectedLayer = SelectBestLayer(cell.HeightLayers, endZ, vehicleHeight, startZ, endZ, i, pathWithGridCoords.Count, true);
|
||||
var selectedLayer = SelectBestLayer(cell.HeightLayers, endZ, objectHeight, startZ, endZ, i, pathWithGridCoords.Count, true);
|
||||
if (selectedLayer.HasValue)
|
||||
{
|
||||
adjustedPath.Add(new Point3D(point.X, point.Y, selectedLayer.Value.Z));
|
||||
@ -2176,7 +2176,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
{
|
||||
// 中间点:根据高度趋势选择最佳层
|
||||
var prevZ = adjustedPath[i - 1].Z;
|
||||
var selectedLayer = SelectBestLayer(cell.HeightLayers, prevZ, vehicleHeight, startZ, endZ, i, pathWithGridCoords.Count, false);
|
||||
var selectedLayer = SelectBestLayer(cell.HeightLayers, prevZ, objectHeight, startZ, endZ, i, pathWithGridCoords.Count, false);
|
||||
|
||||
if (selectedLayer.HasValue)
|
||||
{
|
||||
@ -2260,14 +2260,14 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="layers">可用的高度层列表</param>
|
||||
/// <param name="referenceZ">参考Z坐标(起点/终点为目标Z,中间点为前一点Z)</param>
|
||||
/// <param name="vehicleHeight">车辆高度</param>
|
||||
/// <param name="objectHeight">运动物体高度</param>
|
||||
/// <param name="startZ">路径起点Z</param>
|
||||
/// <param name="endZ">路径终点Z</param>
|
||||
/// <param name="currentIndex">当前点索引</param>
|
||||
/// <param name="totalPoints">总点数</param>
|
||||
/// <param name="exactMatch">是否精确匹配(起点/终点使用)</param>
|
||||
/// <returns>选中的高度层,如果没有合适的返回null</returns>
|
||||
private HeightLayer? SelectBestLayer(List<HeightLayer> layers, double referenceZ, double vehicleHeight,
|
||||
private HeightLayer? SelectBestLayer(List<HeightLayer> layers, double referenceZ, double objectHeight,
|
||||
double startZ, double endZ, int currentIndex, int totalPoints, bool exactMatch)
|
||||
{
|
||||
if (layers == null || layers.Count == 0)
|
||||
@ -2277,7 +2277,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
if (layers.Count == 1)
|
||||
{
|
||||
var layer = layers[0];
|
||||
if (layer.PassableHeight.GetSpan() >= vehicleHeight)
|
||||
if (layer.PassableHeight.GetSpan() >= objectHeight)
|
||||
return layer;
|
||||
return null;
|
||||
}
|
||||
@ -2307,13 +2307,13 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
}
|
||||
|
||||
// 选择最接近目标Z且满足车辆高度要求的层
|
||||
// 选择最接近目标Z且满足运动物体高度要求的层
|
||||
HeightLayer? bestLayer = null;
|
||||
double minDistance = double.MaxValue;
|
||||
|
||||
foreach (var layer in layers)
|
||||
{
|
||||
if (layer.PassableHeight.GetSpan() < vehicleHeight)
|
||||
if (layer.PassableHeight.GetSpan() < objectHeight)
|
||||
continue;
|
||||
|
||||
double distance = Math.Abs(layer.Z - targetZ);
|
||||
@ -2439,8 +2439,8 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="pathWithGridCoords">路径点和对应的网格坐标</param>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="vehicleHeight">车辆高度(模型单位)</param>
|
||||
private void ValidatePathHeightConstraints(List<(Point3D point, GridPoint2D gridPos)> pathWithGridCoords, GridMap gridMap, double vehicleHeight)
|
||||
/// <param name="objectHeight">运动物体高度(模型单位)</param>
|
||||
private void ValidatePathHeightConstraints(List<(Point3D point, GridPoint2D gridPos)> pathWithGridCoords, GridMap gridMap, double objectHeight)
|
||||
{
|
||||
LogManager.Info($"[路径高度验证] 开始验证 {pathWithGridCoords.Count} 个路径点的高度约束");
|
||||
|
||||
@ -2466,7 +2466,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
|
||||
// 进行高度约束检查
|
||||
bool isPassable = IsPointPassableAtHeight(gridPos, point, gridMap, vehicleHeight);
|
||||
bool isPassable = IsPointPassableAtHeight(gridPos, point, gridMap, objectHeight);
|
||||
if (isPassable)
|
||||
{
|
||||
passedPoints++;
|
||||
@ -2595,7 +2595,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// 安全优先的A*网格转换方法
|
||||
/// 🔥 重写:参照局部直线优先算法的成功模式,重新构建网格连接
|
||||
/// </summary>
|
||||
private (Grid grid, Dictionary<GridPoint2D, double> activeLayerZ) ConvertToAStarGridSafestCenter(GridMap gridMap, ChannelCoverage channelCoverage, double vehicleHeight, Point3D startPos, Point3D endPos)
|
||||
private (Grid grid, Dictionary<GridPoint2D, double> activeLayerZ) ConvertToAStarGridSafestCenter(GridMap gridMap, ChannelCoverage channelCoverage, double objectHeight, Point3D startPos, Point3D endPos)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -2648,7 +2648,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
var cell = gridMap.Cells[x, y];
|
||||
|
||||
// 检查是否有兼容的高度层
|
||||
if (!HasCompatibleLayer(cell, vehicleHeight))
|
||||
if (!HasCompatibleLayer(cell, objectHeight))
|
||||
{
|
||||
if (cell.HasAnyWalkableLayer())
|
||||
{
|
||||
@ -2658,7 +2658,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
}
|
||||
|
||||
// 选择当前网格的最佳高度层
|
||||
var currentZ = SelectBestLayerForTarget(cell.HeightLayers, targetZ, vehicleHeight);
|
||||
var currentZ = SelectBestLayerForTarget(cell.HeightLayers, targetZ, objectHeight);
|
||||
if (!currentZ.HasValue)
|
||||
{
|
||||
continue;
|
||||
@ -2678,10 +2678,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var rightCell = gridMap.Cells[x + 1, y];
|
||||
|
||||
// 检查右侧网格是否有兼容的高度层
|
||||
if (HasCompatibleLayer(rightCell, vehicleHeight))
|
||||
if (HasCompatibleLayer(rightCell, objectHeight))
|
||||
{
|
||||
// 选择右侧网格的最佳高度层
|
||||
var rightZ = SelectBestLayerForTarget(rightCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var rightZ = SelectBestLayerForTarget(rightCell.HeightLayers, targetZ, objectHeight);
|
||||
if (rightZ.HasValue)
|
||||
{
|
||||
var rightPos = new GridPosition(x + 1, y);
|
||||
@ -2720,10 +2720,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var bottomCell = gridMap.Cells[x, y + 1];
|
||||
|
||||
// 检查下方网格是否有兼容的高度层
|
||||
if (HasCompatibleLayer(bottomCell, vehicleHeight))
|
||||
if (HasCompatibleLayer(bottomCell, objectHeight))
|
||||
{
|
||||
// 选择下方网格的最佳高度层
|
||||
var bottomZ = SelectBestLayerForTarget(bottomCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var bottomZ = SelectBestLayerForTarget(bottomCell.HeightLayers, targetZ, objectHeight);
|
||||
if (bottomZ.HasValue)
|
||||
{
|
||||
var bottomPos = new GridPosition(x, y + 1);
|
||||
@ -2762,10 +2762,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var leftCell = gridMap.Cells[x - 1, y];
|
||||
|
||||
// 检查左侧网格是否有兼容的高度层
|
||||
if (HasCompatibleLayer(leftCell, vehicleHeight))
|
||||
if (HasCompatibleLayer(leftCell, objectHeight))
|
||||
{
|
||||
// 选择左侧网格的最佳高度层
|
||||
var leftZ = SelectBestLayerForTarget(leftCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var leftZ = SelectBestLayerForTarget(leftCell.HeightLayers, targetZ, objectHeight);
|
||||
if (leftZ.HasValue)
|
||||
{
|
||||
var leftPos = new GridPosition(x - 1, y);
|
||||
@ -2804,10 +2804,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
var topCell = gridMap.Cells[x, y - 1];
|
||||
|
||||
// 检查上方网格是否有兼容的高度层
|
||||
if (HasCompatibleLayer(topCell, vehicleHeight))
|
||||
if (HasCompatibleLayer(topCell, objectHeight))
|
||||
{
|
||||
// 选择上方网格的最佳高度层
|
||||
var topZ = SelectBestLayerForTarget(topCell.HeightLayers, targetZ, vehicleHeight);
|
||||
var topZ = SelectBestLayerForTarget(topCell.HeightLayers, targetZ, objectHeight);
|
||||
if (topZ.HasValue)
|
||||
{
|
||||
var topPos = new GridPosition(x, y - 1);
|
||||
|
||||
@ -8,7 +8,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
{
|
||||
/// <summary>
|
||||
/// GridMap缓存键,用于标识唯一的GridMap生成配置
|
||||
/// 基于所有物流属性构件、车辆尺寸、网格尺寸等关键参数
|
||||
/// 基于所有物流属性构件、运动物体尺寸、网格尺寸等关键参数
|
||||
/// </summary>
|
||||
public class GridMapCacheKey : IEquatable<GridMapCacheKey>
|
||||
{
|
||||
@ -28,9 +28,9 @@ namespace NavisworksTransport.PathPlanning
|
||||
public double CellSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 车辆半径(米)
|
||||
/// 运动物体半径(米)
|
||||
/// </summary>
|
||||
public double VehicleRadius { get; set; }
|
||||
public double ObjectRadius { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 安全间隙(米)
|
||||
@ -38,22 +38,22 @@ namespace NavisworksTransport.PathPlanning
|
||||
public double SafetyMargin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 车辆高度(米)
|
||||
/// 运动物体高度(米)
|
||||
/// </summary>
|
||||
public double VehicleHeight { get; set; }
|
||||
public double ObjectHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public GridMapCacheKey(string logisticsDataHash, string boundsHash, double cellSize,
|
||||
double vehicleRadius, double safetyMargin, double vehicleHeight)
|
||||
double objectRadius, double safetyMargin, double objectHeight)
|
||||
{
|
||||
LogisticsDataHash = logisticsDataHash ?? throw new ArgumentNullException(nameof(logisticsDataHash));
|
||||
BoundsHash = boundsHash ?? throw new ArgumentNullException(nameof(boundsHash));
|
||||
CellSize = cellSize;
|
||||
VehicleRadius = vehicleRadius;
|
||||
ObjectRadius = objectRadius;
|
||||
SafetyMargin = safetyMargin;
|
||||
VehicleHeight = vehicleHeight;
|
||||
ObjectHeight = objectHeight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -67,9 +67,9 @@ namespace NavisworksTransport.PathPlanning
|
||||
return LogisticsDataHash == other.LogisticsDataHash &&
|
||||
BoundsHash == other.BoundsHash &&
|
||||
Math.Abs(CellSize - other.CellSize) < 1e-6 &&
|
||||
Math.Abs(VehicleRadius - other.VehicleRadius) < 1e-6 &&
|
||||
Math.Abs(ObjectRadius - other.ObjectRadius) < 1e-6 &&
|
||||
Math.Abs(SafetyMargin - other.SafetyMargin) < 1e-6 &&
|
||||
Math.Abs(VehicleHeight - other.VehicleHeight) < 1e-6;
|
||||
Math.Abs(ObjectHeight - other.ObjectHeight) < 1e-6;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -91,9 +91,9 @@ namespace NavisworksTransport.PathPlanning
|
||||
hash = hash * 23 + (LogisticsDataHash?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (BoundsHash?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + CellSize.GetHashCode();
|
||||
hash = hash * 23 + VehicleRadius.GetHashCode();
|
||||
hash = hash * 23 + ObjectRadius.GetHashCode();
|
||||
hash = hash * 23 + SafetyMargin.GetHashCode();
|
||||
hash = hash * 23 + VehicleHeight.GetHashCode();
|
||||
hash = hash * 23 + ObjectHeight.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@ -111,7 +111,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
"NULL";
|
||||
|
||||
return $"GridMapKey[Logistics={logisticsPreview}, Bounds={boundsPreview}, " +
|
||||
$"Cell={CellSize:F2}, VR={VehicleRadius:F1}m, SM={SafetyMargin:F1}m, VH={VehicleHeight:F1}m]";
|
||||
$"Cell={CellSize:F2}, OR={ObjectRadius:F1}m, SM={SafetyMargin:F1}m, OH={ObjectHeight:F1}m]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -119,19 +119,19 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="bounds">边界范围</param>
|
||||
/// <param name="cellSize">网格大小</param>
|
||||
/// <param name="vehicleRadius">车辆半径(米)</param>
|
||||
/// <param name="objectRadius">运动物体半径(米)</param>
|
||||
/// <param name="safetyMargin">安全间隙(米)</param>
|
||||
/// <param name="vehicleHeight">车辆高度(米)</param>
|
||||
/// <param name="objectHeight">运动物体高度(米)</param>
|
||||
/// <returns>缓存键</returns>
|
||||
public static GridMapCacheKey CreateFrom(BoundingBox3D bounds,
|
||||
double cellSize, double vehicleRadius,
|
||||
double safetyMargin, double vehicleHeight)
|
||||
double cellSize, double objectRadius,
|
||||
double safetyMargin, double objectHeight)
|
||||
{
|
||||
var logisticsDataHash = ComputeLogisticsDataHash();
|
||||
var boundsHash = ComputeBoundsHash(bounds);
|
||||
|
||||
return new GridMapCacheKey(logisticsDataHash, boundsHash, cellSize,
|
||||
vehicleRadius, safetyMargin, vehicleHeight);
|
||||
objectRadius, safetyMargin, objectHeight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -58,35 +58,35 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// <param name="document">Navisworks文档</param>
|
||||
/// <param name="bounds">扫描边界</param>
|
||||
/// <param name="cellSize">网格单元大小(米)</param>
|
||||
/// <param name="vehicleRadius">车辆半径(米)</param>
|
||||
/// <param name="objectRadius">运动物体半径(米)</param>
|
||||
/// <param name="safetyMargin">安全间隙(米)</param>
|
||||
/// <param name="planningStartPoint">规划起点</param>
|
||||
/// <param name="planningEndPoint">规划终点</param>
|
||||
/// <param name="vehicleHeight">车辆高度(米)</param>
|
||||
/// <param name="objectHeight">运动物体高度(米)</param>
|
||||
/// <returns>生成的网格地图</returns>
|
||||
public GridMap GenerateFromBIM(BoundingBox3D bounds, double cellSize, double vehicleRadius, double safetyMargin, Point3D planningStartPoint, Point3D planningEndPoint, double vehicleHeight)
|
||||
public GridMap GenerateFromBIM(BoundingBox3D bounds, double cellSize, double objectRadius, double safetyMargin, Point3D planningStartPoint, Point3D planningEndPoint, double objectHeight)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 第一步:统一转换所有米制参数为模型单位
|
||||
double metersToModelUnitsConversionFactor = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
|
||||
double cellSizeInModelUnits = cellSize * metersToModelUnitsConversionFactor;
|
||||
double vehicleRadiusInModelUnits = vehicleRadius * metersToModelUnitsConversionFactor;
|
||||
double objectRadiusInModelUnits = objectRadius * metersToModelUnitsConversionFactor;
|
||||
double safetyMarginInModelUnits = safetyMargin * metersToModelUnitsConversionFactor;
|
||||
double vehicleHeightInModelUnits = vehicleHeight * metersToModelUnitsConversionFactor;
|
||||
double scanHeightInModelUnits = vehicleHeightInModelUnits + safetyMarginInModelUnits; // 扫描高度 = 车辆高度 + 安全间隙
|
||||
double totalInflationRadiusInModelUnits = vehicleRadiusInModelUnits + safetyMarginInModelUnits; // 膨胀半径 = 车辆半径 + 安全间隙
|
||||
double objectHeightInModelUnits = objectHeight * metersToModelUnitsConversionFactor;
|
||||
double scanHeightInModelUnits = objectHeightInModelUnits + safetyMarginInModelUnits; // 扫描高度 = 运动物体高度 + 安全间隙
|
||||
double totalInflationRadiusInModelUnits = objectRadiusInModelUnits + safetyMarginInModelUnits; // 膨胀半径 = 运动物体半径 + 安全间隙
|
||||
|
||||
LogManager.Info($"【生成网格地图】参数单位转换完成 (转换系数: {metersToModelUnitsConversionFactor:F2}):");
|
||||
LogManager.Info($" 网格大小: {cellSize}米 → {cellSizeInModelUnits:F2}模型单位");
|
||||
LogManager.Info($" 车辆半径: {vehicleRadius}米 → {vehicleRadiusInModelUnits:F2}模型单位");
|
||||
LogManager.Info($" 运动物体半径: {objectRadius}米 → {objectRadiusInModelUnits:F2}模型单位");
|
||||
LogManager.Info($" 安全间隙: {safetyMargin}米 → {safetyMarginInModelUnits:F2}模型单位");
|
||||
LogManager.Info($" 车辆高度: {vehicleHeight}米 → {vehicleHeightInModelUnits:F2}模型单位");
|
||||
LogManager.Info($" 运动物体高度: {objectHeight}米 → {objectHeightInModelUnits:F2}模型单位");
|
||||
LogManager.Info($" 扫描高度: {scanHeightInModelUnits:F2}模型单位");
|
||||
LogManager.Info($" 膨胀半径: {totalInflationRadiusInModelUnits:F2}模型单位");
|
||||
|
||||
// 生成缓存键(使用转换后的模型单位参数确保一致性)
|
||||
var cacheKey = GridMapCacheKey.CreateFrom(bounds, cellSizeInModelUnits, vehicleRadiusInModelUnits, safetyMarginInModelUnits, vehicleHeightInModelUnits);
|
||||
var cacheKey = GridMapCacheKey.CreateFrom(bounds, cellSizeInModelUnits, objectRadiusInModelUnits, safetyMarginInModelUnits, objectHeightInModelUnits);
|
||||
|
||||
// 尝试从缓存获取
|
||||
var cachedGridMap = GlobalGridMapCache.Instance.Get(cacheKey, 5000); // 预估生成需要5秒
|
||||
@ -163,10 +163,10 @@ namespace NavisworksTransport.PathPlanning
|
||||
LogManager.Info($"【阶段2.7完成】边界层标记后网格统计: {channelCoverage.GridMap.GetStatistics()}");
|
||||
|
||||
// 3. 应用车辆尺寸膨胀
|
||||
if (vehicleRadius > 0 || safetyMargin > 0)
|
||||
if (objectRadius > 0 || safetyMargin > 0)
|
||||
{
|
||||
LogManager.Info("【生成网格地图】步骤3: 应用车辆膨胀");
|
||||
ApplyVehicleInflation(channelCoverage.GridMap, totalInflationRadiusInModelUnits);
|
||||
ApplyObjectInflation(channelCoverage.GridMap, totalInflationRadiusInModelUnits);
|
||||
LogManager.Info($"【生成网格地图】车辆膨胀完成,膨胀半径: {totalInflationRadiusInModelUnits:F2}模型单位");
|
||||
LogManager.Info($"【阶段3完成】车辆膨胀后网格统计: {channelCoverage.GridMap.GetStatistics()}");
|
||||
}
|
||||
@ -834,19 +834,19 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// 在障碍物周围扩展不可通行区域,考虑车辆尺寸
|
||||
/// </summary>
|
||||
/// <param name="gridMap">网格地图</param>
|
||||
/// <param name="vehicleRadiusInModelUnits">车辆半径(模型单位)</param>
|
||||
private void ApplyVehicleInflation(GridMap gridMap, double vehicleRadiusInModelUnits)
|
||||
/// <param name="objectRadiusInModelUnits">运动物体半径(模型单位)</param>
|
||||
private void ApplyObjectInflation(GridMap gridMap, double objectRadiusInModelUnits)
|
||||
{
|
||||
if (vehicleRadiusInModelUnits <= 0) return;
|
||||
if (objectRadiusInModelUnits <= 0) return;
|
||||
|
||||
try
|
||||
{
|
||||
// 计算膨胀半径(网格单元格数)
|
||||
int inflationRadius = (int)Math.Ceiling(vehicleRadiusInModelUnits / gridMap.CellSize);
|
||||
int inflationRadius = (int)Math.Ceiling(objectRadiusInModelUnits / gridMap.CellSize);
|
||||
LogManager.Info($"[高效膨胀] 膨胀半径: {inflationRadius}个网格单元");
|
||||
|
||||
// 使用高效的距离变换算法
|
||||
ApplyVehicleInflation(gridMap, inflationRadius);
|
||||
ApplyObjectInflation(gridMap, inflationRadius);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -859,7 +859,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// 多层膨胀算法 - 分两次处理:障碍物膨胀 + 边界膨胀
|
||||
/// 核心原则:障碍物从外围膨胀(不含本身),边界从边界本身膨胀(包含边界)
|
||||
/// </summary>
|
||||
private void ApplyVehicleInflation(GridMap gridMap, int inflationRadius)
|
||||
private void ApplyObjectInflation(GridMap gridMap, int inflationRadius)
|
||||
{
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
|
||||
@ -1313,7 +1313,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
var walkableGridCount = channelCoverage.WalkableGridCount;
|
||||
var walkableHeightRange = walkableMaxZ - walkableMinZ;
|
||||
LogManager.Info($"[高性能障碍物处理] 可通行网格高度信息 - 最低点: {walkableMinZ:F2}, 最高点: {walkableMaxZ:F2}");
|
||||
LogManager.Info($"[高性能障碍物处理] 可通行网格数量: {walkableGridCount}, 高度范围: {walkableHeightRange:F2}, 加车辆高度后扫描范围: [{walkableMinZ:F2}, {walkableMaxZ + scanHeightInModelUnits:F2}]");
|
||||
LogManager.Info($"[高性能障碍物处理] 可通行网格数量: {walkableGridCount}, 高度范围: {walkableHeightRange:F2}, 加运动物体高度后扫描范围: [{walkableMinZ:F2}, {walkableMaxZ + scanHeightInModelUnits:F2}]");
|
||||
|
||||
// 阶段4:网格覆盖计算(并行几何计算)- 使用50%CPU核心优化 + 基于通道的精确高度检查
|
||||
LogManager.Info("[高性能障碍物处理] 阶段4: 并行网格覆盖计算 + 基于通道高度的精确高度检查");
|
||||
@ -1337,7 +1337,7 @@ namespace NavisworksTransport.PathPlanning
|
||||
var centerCell = gridMap.Cells[centerGridPos.X, centerGridPos.Y];
|
||||
|
||||
// 使用可通行网格高度范围计算扫描范围
|
||||
// 扫描范围:从可通行网格最低点开始,到可通行网格最高点+车辆高度+安全间隙
|
||||
// 扫描范围:从可通行网格最低点开始,到可通行网格最高点+运动物体高度+安全间隙
|
||||
var scanMin = walkableMinZ;
|
||||
var scanMax = walkableMaxZ + scanHeightInModelUnits;
|
||||
|
||||
|
||||
@ -47,14 +47,14 @@ namespace NavisworksTransport.PathPlanning
|
||||
public bool EnableCollisionCheck { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 车辆长度(米,未来扩展)
|
||||
/// 物体长度(米,未来扩展)
|
||||
/// </summary>
|
||||
public double VehicleLength { get; set; }
|
||||
public double ObjectLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 车辆宽度(米,未来扩展)
|
||||
/// 物体宽度(米,未来扩展)
|
||||
/// </summary>
|
||||
public double VehicleWidth { get; set; }
|
||||
public double ObjectWidth { get; set; }
|
||||
}
|
||||
|
||||
private readonly OptimizationConfig _config;
|
||||
|
||||
@ -93,15 +93,15 @@ namespace NavisworksTransport.PathPlanning
|
||||
/// </summary>
|
||||
/// <param name="bounds">网格边界(世界坐标,模型单位)</param>
|
||||
/// <param name="voxelSizeMeters">体素尺寸(米)</param>
|
||||
/// <param name="vehicleRadiusMeters">车辆半径(米),用于安全间隙</param>
|
||||
/// <param name="vehicleHeightMeters">车辆高度(米)</param>
|
||||
/// <param name="objectRadiusMeters">车辆半径(米),用于安全间隙</param>
|
||||
/// <param name="objectHeightMeters">车辆高度(米)</param>
|
||||
/// <param name="obstacleItems">障碍物模型元素列表</param>
|
||||
/// <returns>生成的体素网格</returns>
|
||||
public VoxelGrid GenerateFromBIMWithSDF(
|
||||
BoundingBox3D bounds,
|
||||
double voxelSizeMeters,
|
||||
double vehicleRadiusMeters,
|
||||
double vehicleHeightMeters,
|
||||
double objectRadiusMeters,
|
||||
double objectHeightMeters,
|
||||
IEnumerable<ModelItem> obstacleItems)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
@ -112,13 +112,13 @@ namespace NavisworksTransport.PathPlanning
|
||||
Autodesk.Navisworks.Api.Application.ActiveDocument.Units);
|
||||
|
||||
double voxelSizeInModelUnits = voxelSizeMeters * metersToModelUnits;
|
||||
double vehicleRadiusInModelUnits = vehicleRadiusMeters * metersToModelUnits;
|
||||
double vehicleHeightInModelUnits = vehicleHeightMeters * metersToModelUnits;
|
||||
double safetyMarginInModelUnits = vehicleRadiusInModelUnits; // 安全间隙 = 车辆半径
|
||||
double objectRadiusInModelUnits = objectRadiusMeters * metersToModelUnits;
|
||||
double objectHeightInModelUnits = objectHeightMeters * metersToModelUnits;
|
||||
double safetyMarginInModelUnits = objectRadiusInModelUnits; // 安全间隙 = 车辆半径
|
||||
|
||||
LogManager.Info($"单位转换系数: {metersToModelUnits:F4}");
|
||||
LogManager.Info($"体素尺寸: {voxelSizeMeters}米 = {voxelSizeInModelUnits:F2}模型单位");
|
||||
LogManager.Info($"安全间隙: {vehicleRadiusMeters}米 = {safetyMarginInModelUnits:F2}模型单位");
|
||||
LogManager.Info($"安全间隙: {objectRadiusMeters}米 = {safetyMarginInModelUnits:F2}模型单位");
|
||||
|
||||
// 第二步:创建体素网格
|
||||
var voxelGrid = new VoxelGrid(bounds, voxelSizeInModelUnits);
|
||||
@ -286,12 +286,12 @@ namespace NavisworksTransport.PathPlanning
|
||||
LogManager.Info($"标记统计: 障碍物={obstacleCount:N0}, 可通行={passableCount:N0}, 边界={boundaryCount:N0}");
|
||||
|
||||
// 第六步:障碍物膨胀(可选)
|
||||
if (vehicleRadiusMeters > 0)
|
||||
if (objectRadiusMeters > 0)
|
||||
{
|
||||
LogManager.Info("开始障碍物膨胀...");
|
||||
var inflationStopwatch = Stopwatch.StartNew();
|
||||
|
||||
int inflatedCount = voxelGrid.InflateObstacles(vehicleRadiusMeters, metersToModelUnits);
|
||||
int inflatedCount = voxelGrid.InflateObstacles(objectRadiusMeters, metersToModelUnits);
|
||||
|
||||
inflationStopwatch.Stop();
|
||||
LogManager.Info($"障碍物膨胀完成,耗时: {inflationStopwatch.ElapsedMilliseconds} ms");
|
||||
|
||||
@ -313,12 +313,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private bool _canGenerateAnimation = false;
|
||||
|
||||
// 虚拟车辆相关字段
|
||||
private bool _useVirtualVehicle = false; // 使用虚拟车辆
|
||||
private double _virtualVehicleLength; // 虚拟车辆长度(米)
|
||||
private double _virtualVehicleWidth; // 虚拟车辆宽度(米)
|
||||
private double _virtualVehicleHeight; // 虚拟车辆高度(米)
|
||||
private bool _useVirtualObject = false; // 使用虚拟车辆
|
||||
private double _virtualObjectLength; // 虚拟车辆长度(米)
|
||||
private double _virtualObjectWidth; // 虚拟车辆宽度(米)
|
||||
private double _virtualObjectHeight; // 虚拟车辆高度(米)
|
||||
private double _safetyMargin; // 检测间隙(米),从路径编辑同步
|
||||
|
||||
// 剖面盒优化相关字段
|
||||
private bool _useSectionClip = true; // 使用剖面盒优化(默认启用,用于性能对比测试)
|
||||
|
||||
// 角度修正相关字段
|
||||
private double _objectRotationCorrection; // 物体角度修正值(度,顺时针)
|
||||
|
||||
@ -613,14 +616,29 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// 是否使用选择的模型物体
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// 是否使用虚拟车辆
|
||||
/// 是否使用剖面盒优化(用于性能对比测试)
|
||||
/// </summary>
|
||||
public bool UseVirtualVehicle
|
||||
public bool UseSectionClip
|
||||
{
|
||||
get => _useVirtualVehicle;
|
||||
get => _useSectionClip;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _useVirtualVehicle, value))
|
||||
if (SetProperty(ref _useSectionClip, value))
|
||||
{
|
||||
LogManager.Info($"[剖面盒] 优化开关已{(value ? "启用" : "禁用")}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用虚拟车辆
|
||||
/// </summary>
|
||||
public bool UseVirtualObject
|
||||
{
|
||||
get => _useVirtualObject;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _useVirtualObject, value))
|
||||
{
|
||||
// ✨ 模式切换清理:切换到虚拟车辆模式时,移除选择物体的动画数据
|
||||
if (value)
|
||||
@ -630,7 +648,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
// 只有在当前动画对象不是虚拟车辆时才执行重置
|
||||
if (_pathAnimationManager != null &&
|
||||
_pathAnimationManager.AnimatedObject != null &&
|
||||
!VirtualVehicleManager.Instance.IsVirtualVehicleActive)
|
||||
!VirtualObjectManager.Instance.IsVirtualObjectActive)
|
||||
{
|
||||
_pathAnimationManager.RestoreObjectToCADPosition();
|
||||
_pathAnimationManager.ClearAnimationResults(); // 清理手动选择物体留下的动画数据
|
||||
@ -639,8 +657,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
// 显示虚拟车辆
|
||||
LogManager.Info("正在显示虚拟车辆...");
|
||||
VirtualVehicleManager.Instance.ShowVirtualVehicle(
|
||||
VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight);
|
||||
VirtualObjectManager.Instance.ShowVirtualObject(
|
||||
VirtualObjectLength, VirtualObjectWidth, VirtualObjectHeight);
|
||||
|
||||
// 重置角度修正值(虚拟车辆重新选择时重置)
|
||||
ObjectRotationCorrection = 0.0;
|
||||
@ -663,7 +681,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
try
|
||||
{
|
||||
// 不删除虚拟车辆,只隐藏它
|
||||
VirtualVehicleManager.Instance.HideVirtualVehicle();
|
||||
VirtualObjectManager.Instance.HideVirtualObject();
|
||||
_pathAnimationManager?.ClearAnimationResults(); // 清理虚拟车辆留下的动画数据
|
||||
LogManager.Info("已切换到手动选择模式,自动隐藏虚拟车辆并清理动画数据");
|
||||
}
|
||||
@ -680,28 +698,28 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// <summary>
|
||||
/// 虚拟车辆长度(米)- 只读,从路径编辑同步
|
||||
/// </summary>
|
||||
public double VirtualVehicleLength
|
||||
public double VirtualObjectLength
|
||||
{
|
||||
get => _virtualVehicleLength;
|
||||
private set => SetProperty(ref _virtualVehicleLength, value);
|
||||
get => _virtualObjectLength;
|
||||
private set => SetProperty(ref _virtualObjectLength, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 虚拟车辆宽度(米)- 只读,从路径编辑同步
|
||||
/// </summary>
|
||||
public double VirtualVehicleWidth
|
||||
public double VirtualObjectWidth
|
||||
{
|
||||
get => _virtualVehicleWidth;
|
||||
private set => SetProperty(ref _virtualVehicleWidth, value);
|
||||
get => _virtualObjectWidth;
|
||||
private set => SetProperty(ref _virtualObjectWidth, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 虚拟车辆高度(米)- 只读,从路径编辑同步
|
||||
/// </summary>
|
||||
public double VirtualVehicleHeight
|
||||
public double VirtualObjectHeight
|
||||
{
|
||||
get => _virtualVehicleHeight;
|
||||
private set => SetProperty(ref _virtualVehicleHeight, value);
|
||||
get => _virtualObjectHeight;
|
||||
private set => SetProperty(ref _virtualObjectHeight, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -724,18 +742,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// 设置虚拟车辆参数(由主ViewModel调用)
|
||||
/// 参数单位:米
|
||||
/// </summary>
|
||||
public void SetVirtualVehicleParameters(double length, double width, double height, double safetyMargin)
|
||||
public void SetVirtualObjectParameters(double length, double width, double height, double safetyMargin)
|
||||
{
|
||||
LogManager.Info($"[AnimationControlViewModel] SetVirtualVehicleParameters被调用: length={length:F4}, width={width:F4}, height={height:F4}, safetyMargin={safetyMargin:F4}");
|
||||
VirtualVehicleLength = length;
|
||||
VirtualVehicleWidth = width;
|
||||
VirtualVehicleHeight = height;
|
||||
LogManager.Info($"[AnimationControlViewModel] SetVirtualObjectParameters被调用: length={length:F4}, width={width:F4}, height={height:F4}, safetyMargin={safetyMargin:F4}");
|
||||
VirtualObjectLength = length;
|
||||
VirtualObjectWidth = width;
|
||||
VirtualObjectHeight = height;
|
||||
_safetyMargin = safetyMargin;
|
||||
|
||||
LogManager.Info($"[AnimationControlViewModel] 虚拟车辆参数已更新: {length:F1}米 × {width:F1}米 × {height:F1}米, 检测间隙: {safetyMargin:F2}米, _safetyMargin={_safetyMargin:F4}");
|
||||
|
||||
// 如果当前使用虚拟车辆模式,更新生成动画的可用状态
|
||||
if (UseVirtualVehicle)
|
||||
if (UseVirtualObject)
|
||||
{
|
||||
UpdateCanGenerateAnimation();
|
||||
// 更新通行空间可视化
|
||||
@ -1053,9 +1071,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
_detectionTolerance = config.Animation.DetectionToleranceMeters;
|
||||
|
||||
// 🔥 从配置加载虚拟车辆尺寸(与路径编辑保持一致,使用米单位接口)
|
||||
VirtualVehicleLength = config.PathEditing.VehicleLengthMeters;
|
||||
VirtualVehicleWidth = config.PathEditing.VehicleWidthMeters;
|
||||
VirtualVehicleHeight = config.PathEditing.VehicleHeightMeters;
|
||||
VirtualObjectLength = config.PathEditing.ObjectLengthMeters;
|
||||
VirtualObjectWidth = config.PathEditing.ObjectWidthMeters;
|
||||
VirtualObjectHeight = config.PathEditing.ObjectHeightMeters;
|
||||
|
||||
// 设置动画按钮的初始状态
|
||||
UpdateAnimationButtonStates();
|
||||
@ -1134,12 +1152,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
var config = ConfigManager.Instance.Current;
|
||||
|
||||
// 更新车辆参数
|
||||
VirtualVehicleLength = config.PathEditing.VehicleLengthMeters;
|
||||
VirtualVehicleWidth = config.PathEditing.VehicleWidthMeters;
|
||||
VirtualVehicleHeight = config.PathEditing.VehicleHeightMeters;
|
||||
VirtualObjectLength = config.PathEditing.ObjectLengthMeters;
|
||||
VirtualObjectWidth = config.PathEditing.ObjectWidthMeters;
|
||||
VirtualObjectHeight = config.PathEditing.ObjectHeightMeters;
|
||||
_safetyMargin = config.PathEditing.SafetyMarginMeters;
|
||||
|
||||
LogManager.Info($"车辆参数已更新 - 尺寸:{VirtualVehicleLength:F1}x{VirtualVehicleWidth:F1}x{VirtualVehicleHeight:F1}米, 安全间隙:{_safetyMargin:F2}米");
|
||||
LogManager.Info($"车辆参数已更新 - 尺寸:{VirtualObjectLength:F1}x{VirtualObjectWidth:F1}x{VirtualObjectHeight:F1}米, 安全间隙:{_safetyMargin:F2}米");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -3089,7 +3107,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// <summary>
|
||||
/// 获取运动物体的 PathId 信息
|
||||
/// </summary>
|
||||
private (int ModelIndex, string PathId) GetVehiclePathIdInfo()
|
||||
private (int ModelIndex, string PathId) GetObjectPathIdInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -3258,7 +3276,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
Mouse.OverrideCursor = Cursors.Wait;
|
||||
|
||||
UpdateMainStatus("正在生成动画...", -1, true);
|
||||
LogManager.Info($"开始生成动画 - 模式: {(UseVirtualVehicle ? "虚拟车辆" : "选择物体")}");
|
||||
LogManager.Info($"开始生成动画 - 模式: {(UseVirtualObject ? "虚拟车辆" : "选择物体")}");
|
||||
|
||||
var cacheStartTime = DateTime.Now;
|
||||
|
||||
@ -3277,7 +3295,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
// 🔥 预计算动画对象的排除列表(仅在非虚拟车辆、非手工模式下)
|
||||
if (!manualModeEnabled && !UseVirtualVehicle)
|
||||
if (!manualModeEnabled && !UseVirtualObject)
|
||||
{
|
||||
UpdateMainStatus("正在分析动画对象...", -1, true);
|
||||
|
||||
@ -3313,18 +3331,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
ModelItem animatedObject = null;
|
||||
|
||||
if (UseVirtualVehicle)
|
||||
if (UseVirtualObject)
|
||||
{
|
||||
// 使用虚拟车辆:总是调用 ShowVirtualVehicle 来更新尺寸
|
||||
// 使用虚拟车辆:总是调用 ShowVirtualObject 来更新尺寸
|
||||
LogManager.Info("[ExecuteGenerateAnimation] 显示并更新虚拟车辆...");
|
||||
UpdateMainStatus("正在显示虚拟车辆...", -1, true);
|
||||
|
||||
VirtualVehicleManager.Instance.ShowVirtualVehicle(
|
||||
VirtualVehicleLength,
|
||||
VirtualVehicleWidth,
|
||||
VirtualVehicleHeight
|
||||
VirtualObjectManager.Instance.ShowVirtualObject(
|
||||
VirtualObjectLength,
|
||||
VirtualObjectWidth,
|
||||
VirtualObjectHeight
|
||||
);
|
||||
animatedObject = VirtualVehicleManager.Instance.CurrentVirtualVehicle;
|
||||
animatedObject = VirtualObjectManager.Instance.CurrentVirtualObject;
|
||||
|
||||
if (animatedObject == null)
|
||||
{
|
||||
@ -3337,7 +3355,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
if (CurrentPathRoute != null && CurrentPathRoute.Points != null)
|
||||
{
|
||||
var points = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList();
|
||||
_pathAnimationManager?.MoveVehicleToPathStart(animatedObject, points);
|
||||
_pathAnimationManager?.MoveObjectToPathStart(animatedObject, points);
|
||||
LogManager.Info("[ExecuteGenerateAnimation] 虚拟车辆已移到路径起点");
|
||||
}
|
||||
|
||||
@ -3380,23 +3398,26 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
// 准备车辆尺寸参数(从米转换为模型单位)
|
||||
var metersToModelUnits = Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
|
||||
double vLength = UseVirtualVehicle ? VirtualVehicleLength * metersToModelUnits : 0;
|
||||
double vWidth = UseVirtualVehicle ? VirtualVehicleWidth * metersToModelUnits : 0;
|
||||
double vHeight = UseVirtualVehicle ? VirtualVehicleHeight * metersToModelUnits : 0;
|
||||
double vLength = UseVirtualObject ? VirtualObjectLength * metersToModelUnits : 0;
|
||||
double vWidth = UseVirtualObject ? VirtualObjectWidth * metersToModelUnits : 0;
|
||||
double vHeight = UseVirtualObject ? VirtualObjectHeight * metersToModelUnits : 0;
|
||||
double safetyMargin = _safetyMargin * metersToModelUnits;
|
||||
|
||||
LogManager.Info($"[ExecuteGenerateAnimation] 准备调用CreateAnimation: UseVirtualVehicle={UseVirtualVehicle}, 车辆尺寸: {vLength:F2}×{vWidth:F2}×{vHeight:F2}模型单位, 安全间隙: {safetyMargin:F4}模型单位 (_safetyMargin={_safetyMargin:F4}米)");
|
||||
LogManager.Info($"[ExecuteGenerateAnimation] 准备调用CreateAnimation: UseVirtualObject={UseVirtualObject}, 车辆尺寸: {vLength:F2}×{vWidth:F2}×{vHeight:F2}模型单位, 安全间隙: {safetyMargin:F4}模型单位 (_safetyMargin={_safetyMargin:F4}米)");
|
||||
|
||||
_pathAnimationManager.CreateAnimation(animatedObject, pathPoints, AnimationDuration, CurrentPathRoute.Name, CurrentPathRoute.Id, UseVirtualVehicle,
|
||||
// 设置剖面盒优化开关
|
||||
_pathAnimationManager.SetUseSectionClip(UseSectionClip);
|
||||
|
||||
_pathAnimationManager.CreateAnimation(animatedObject, pathPoints, AnimationDuration, CurrentPathRoute.Name, CurrentPathRoute.Id, UseVirtualObject,
|
||||
vLength, vWidth, vHeight, safetyMargin);
|
||||
|
||||
var totalElapsed = (DateTime.Now - cacheStartTime).TotalMilliseconds;
|
||||
LogManager.Info($"[动画生成] 动画生成完成,总耗时: {totalElapsed:F1}ms");
|
||||
LogManager.Info($"动画生成成功: 物体={animatedObject.DisplayName}, 路径={CurrentPathRoute.Name}");
|
||||
|
||||
if (UseVirtualVehicle)
|
||||
if (UseVirtualObject)
|
||||
{
|
||||
LogManager.Info($"虚拟车辆尺寸: {VirtualVehicleLength:F1}×{VirtualVehicleWidth:F1}×{VirtualVehicleHeight:F1}m");
|
||||
LogManager.Info($"虚拟车辆尺寸: {VirtualObjectLength:F1}×{VirtualObjectWidth:F1}×{VirtualObjectHeight:F1}m");
|
||||
}
|
||||
|
||||
if (IsManualCollisionTargetEnabled)
|
||||
@ -3458,10 +3479,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
double baseLength, baseWidth;
|
||||
|
||||
if (UseVirtualVehicle)
|
||||
if (UseVirtualObject)
|
||||
{
|
||||
baseLength = VirtualVehicleLength;
|
||||
baseWidth = VirtualVehicleWidth;
|
||||
baseLength = VirtualObjectLength;
|
||||
baseWidth = VirtualObjectWidth;
|
||||
}
|
||||
else if (SelectedAnimatedObject != null)
|
||||
{
|
||||
@ -3526,18 +3547,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
// 使用从路径编辑同步过来的检测间隙
|
||||
double safetyMargin = _safetyMargin;
|
||||
|
||||
if (UseVirtualVehicle)
|
||||
if (UseVirtualObject)
|
||||
{
|
||||
// 虚拟车辆的xyz定义:X方向 = 长度(前进方向),Y方向 = 宽度(侧面),Z方向 = 高度
|
||||
if (CurrentPathRoute.PathType == NavisworksTransport.PathType.Rail || CurrentPathRoute.PathType == NavisworksTransport.PathType.Hoisting)
|
||||
{
|
||||
// 空中路径(空轨或吊装):高度上下都加间隙
|
||||
passageAcrossPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = VirtualVehicleHeight + 2 * safetyMargin; // Z方向(高度)+ 2*间隙(法线方向)
|
||||
passageNormalToPath = VirtualObjectHeight + 2 * safetyMargin; // Z方向(高度)+ 2*间隙(法线方向)
|
||||
passageAlongPath = effectiveLength; // 旋转后长度(沿路径方向)
|
||||
// 吊装路径分段参数
|
||||
passageNormalToPathVertical = effectiveLength + 2 * safetyMargin; // 垂直段:物体长度 + 2*间隙
|
||||
passageNormalToPathHorizontal = VirtualVehicleHeight + 2 * safetyMargin; // 水平段:物体高度 + 2*间隙
|
||||
passageNormalToPathHorizontal = VirtualObjectHeight + 2 * safetyMargin; // 水平段:物体高度 + 2*间隙
|
||||
LogManager.Debug($"[通行空间可视化] 空中路径使用虚拟车辆尺寸: 有效长度={effectiveLength:F2}m, 有效宽度={effectiveWidth:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
}
|
||||
else if (CurrentPathRoute.PathType == NavisworksTransport.PathType.Ground)
|
||||
@ -3545,7 +3566,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
// 地面路径:物体的长度方向(X轴,前进方向)朝向路径方向
|
||||
// 通行空间沿路径方向 = X方向尺寸(长度),垂直于路径方向 = Y方向尺寸(宽度),高度上方加间隙(下方不需要,因为有地面)
|
||||
passageAcrossPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = VirtualVehicleHeight + safetyMargin; // Z方向(高度)+ 间隙(法线方向,只有上方)
|
||||
passageNormalToPath = VirtualObjectHeight + safetyMargin; // Z方向(高度)+ 间隙(法线方向,只有上方)
|
||||
passageAlongPath = effectiveLength; // 旋转后长度(沿路径方向)
|
||||
// 地面路径不需要分段参数
|
||||
passageNormalToPathVertical = passageNormalToPath;
|
||||
@ -3557,7 +3578,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
// 空轨路径:物体的长度方向(X轴,前进方向)朝向路径方向
|
||||
// 通行空间沿路径方向 = X方向尺寸(长度),垂直于路径方向 = Y方向尺寸(宽度),高度上下都加间隙(在空中)
|
||||
passageAcrossPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = VirtualVehicleHeight + 2 * safetyMargin; // Z方向(高度)+ 2*间隙(法线方向,上下都加)
|
||||
passageNormalToPath = VirtualObjectHeight + 2 * safetyMargin; // Z方向(高度)+ 2*间隙(法线方向,上下都加)
|
||||
passageAlongPath = effectiveLength; // 旋转后长度(沿路径方向)
|
||||
// 空轨路径不需要分段参数
|
||||
passageNormalToPathVertical = passageNormalToPath;
|
||||
@ -3631,16 +3652,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
LogManager.Debug($"[通行空间可视化] 已设置通行空间参数: 沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m, 安全间隙={safetyMargin:F2}m");
|
||||
|
||||
// 根据路径类型决定是否切换到车辆通行空间模式
|
||||
bool enableVehicleSpace = false;
|
||||
bool enableObjectSpace = false;
|
||||
switch (CurrentPathRoute.PathType)
|
||||
{
|
||||
case NavisworksTransport.PathType.Rail:
|
||||
case NavisworksTransport.PathType.Hoisting:
|
||||
enableVehicleSpace = true;
|
||||
enableObjectSpace = true;
|
||||
LogManager.Debug($"[通行空间可视化] 路径类型={CurrentPathRoute.PathType}(空中路径),切换到车辆通行空间模式");
|
||||
break;
|
||||
case NavisworksTransport.PathType.Ground:
|
||||
enableVehicleSpace = false;
|
||||
enableObjectSpace = false;
|
||||
LogManager.Debug($"[通行空间可视化] 路径类型={CurrentPathRoute.PathType},不切换到车辆通行空间模式");
|
||||
break;
|
||||
default:
|
||||
@ -3649,9 +3670,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
// 切换到车辆通行空间模式(如果需要)
|
||||
if (enableVehicleSpace)
|
||||
if (enableObjectSpace)
|
||||
{
|
||||
renderPlugin.VisualizationMode = PathVisualizationMode.VehicleSpace;
|
||||
renderPlugin.VisualizationMode = PathVisualizationMode.ObjectSpace;
|
||||
LogManager.Debug("[通行空间可视化] 已切换到车辆通行空间模式");
|
||||
}
|
||||
|
||||
@ -3697,12 +3718,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
var hasPath = CurrentPathRoute != null && CurrentPathRoute.Points.Count >= 2;
|
||||
|
||||
bool hasValidObject;
|
||||
if (UseVirtualVehicle)
|
||||
if (UseVirtualObject)
|
||||
{
|
||||
// 使用虚拟车辆时,只需要有效的车辆尺寸
|
||||
hasValidObject = VirtualVehicleLength > 0 &&
|
||||
VirtualVehicleWidth > 0 &&
|
||||
VirtualVehicleHeight > 0;
|
||||
hasValidObject = VirtualObjectLength > 0 &&
|
||||
VirtualObjectWidth > 0 &&
|
||||
VirtualObjectHeight > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3722,11 +3743,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
else if (!hasPath && !hasValidObject)
|
||||
{
|
||||
UpdateMainStatus(UseVirtualVehicle ? "请选择动画路径" : "请选择移动物体和动画路径");
|
||||
UpdateMainStatus(UseVirtualObject ? "请选择动画路径" : "请选择移动物体和动画路径");
|
||||
}
|
||||
else if (!hasValidObject)
|
||||
{
|
||||
UpdateMainStatus(UseVirtualVehicle ? "虚拟车辆参数无效" : "请选择移动物体");
|
||||
UpdateMainStatus(UseVirtualObject ? "虚拟车辆参数无效" : "请选择移动物体");
|
||||
}
|
||||
else if (!hasPath)
|
||||
{
|
||||
@ -4356,10 +4377,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
DetectionToleranceMeters = _detectionTolerance,
|
||||
|
||||
// 运动物体配置
|
||||
IsVirtualVehicle = UseVirtualVehicle,
|
||||
VirtualVehicleLength = VirtualVehicleLength,
|
||||
VirtualVehicleWidth = VirtualVehicleWidth,
|
||||
VirtualVehicleHeight = VirtualVehicleHeight,
|
||||
IsVirtualObject = UseVirtualObject,
|
||||
VirtualObjectLength = VirtualObjectLength,
|
||||
VirtualObjectWidth = VirtualObjectWidth,
|
||||
VirtualObjectHeight = VirtualObjectHeight,
|
||||
|
||||
// 被检测项配置
|
||||
DetectAllObjects = !IsManualCollisionTargetEnabled,
|
||||
@ -4380,10 +4401,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
var itemId = await batchQueueManager.AddQueueItemAsync(queueItem);
|
||||
|
||||
// 存储运动物体到 ModelItemReferences 表
|
||||
if (!UseVirtualVehicle && SelectedAnimatedObject != null)
|
||||
if (!UseVirtualObject && SelectedAnimatedObject != null)
|
||||
{
|
||||
LogManager.Info($"[批处理] 准备存储运动物体: {SelectedAnimatedObject.DisplayName}");
|
||||
var pathIdInfo = GetVehiclePathIdInfo();
|
||||
var pathIdInfo = GetObjectPathIdInfo();
|
||||
LogManager.Info($"[批处理] 运动物体 PathId: ModelIndex={pathIdInfo.ModelIndex}, PathId={pathIdInfo.PathId}");
|
||||
|
||||
// 只要 PathId 不为空就认为是有效的(ModelIndex=0 表示主模型,也是有效的)
|
||||
@ -4413,7 +4434,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info($"[批处理] 跳过存储运动物体: UseVirtualVehicle={UseVirtualVehicle}, SelectedAnimatedObject 是否为 null={SelectedAnimatedObject == null}");
|
||||
LogManager.Info($"[批处理] 跳过存储运动物体: UseVirtualObject={UseVirtualObject}, SelectedAnimatedObject 是否为 null={SelectedAnimatedObject == null}");
|
||||
}
|
||||
|
||||
// 存储手工指定的碰撞检测目标到 ModelItemReferences 表
|
||||
@ -4441,7 +4462,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
LogManager.Info($"[批处理] 已创建队列项: {CurrentPathRoute.Name}, " +
|
||||
$"虚拟车辆: {queueItem.IsVirtualVehicle}, " +
|
||||
$"虚拟车辆: {queueItem.IsVirtualObject}, " +
|
||||
$"帧率: {queueItem.FrameRate}, " +
|
||||
$"时长: {queueItem.DurationSeconds:F2}秒, " +
|
||||
$"角度修正: {queueItem.ObjectRotationCorrection:F1}°, " +
|
||||
|
||||
@ -99,7 +99,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
private bool _showPathLines = true;
|
||||
private bool _showVehicleSpace = false;
|
||||
private bool _showObjectSpace = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示路径线/地面连线
|
||||
@ -123,17 +123,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// <summary>
|
||||
/// 是否显示通行空间
|
||||
/// </summary>
|
||||
public bool ShowVehicleSpace
|
||||
public bool ShowObjectSpace
|
||||
{
|
||||
get => _showVehicleSpace;
|
||||
get => _showObjectSpace;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _showVehicleSpace, value))
|
||||
if (SetProperty(ref _showObjectSpace, value))
|
||||
{
|
||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||
if (renderPlugin != null)
|
||||
{
|
||||
renderPlugin.ShowVehicleSpace = value;
|
||||
renderPlugin.ShowObjectSpace = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,9 +148,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
if (renderPlugin != null)
|
||||
{
|
||||
_showPathLines = renderPlugin.ShowPathLines;
|
||||
_showVehicleSpace = renderPlugin.ShowVehicleSpace;
|
||||
_showObjectSpace = renderPlugin.ShowObjectSpace;
|
||||
OnPropertyChanged(nameof(ShowPathLines));
|
||||
OnPropertyChanged(nameof(ShowVehicleSpace));
|
||||
OnPropertyChanged(nameof(ShowObjectSpace));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,9 +68,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private bool _isSelectingEndPoint = false;
|
||||
|
||||
// 车辆参数 - 改为三个独立参数(从配置初始化)
|
||||
private double _vehicleLength; // 车辆长度(米)
|
||||
private double _vehicleWidth; // 车辆宽度(米)
|
||||
private double _vehicleHeight; // 车辆高度(米)
|
||||
private double _ObjectLength; // 车辆长度(米)
|
||||
private double _ObjectWidth; // 车辆宽度(米)
|
||||
private double _ObjectHeight; // 车辆高度(米)
|
||||
private double _safetyMargin; // 安全间隙(米)
|
||||
|
||||
// 网格大小参数(从配置初始化)
|
||||
@ -86,11 +86,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
// 三种渲染模式独立开关
|
||||
private bool _showControlVisualization = true; // 默认显示控制点连线
|
||||
private bool _showPathLines = true; // 默认显示路径线(地面连线)
|
||||
private bool _showVehicleSpace = false; // 默认不显示通行空间
|
||||
// 兼容旧代码的互斥属性(已废弃,使用独立开关)
|
||||
private bool _isStandardLineMode = false;
|
||||
private bool _isRibbonLineMode = true;
|
||||
private bool _isVehicleSpaceMode = false;
|
||||
private bool _showObjectSpace = false; // 默认不显示通行空间
|
||||
|
||||
// 路径策略参数
|
||||
private PathStrategyOption _selectedPathStrategy;
|
||||
@ -242,7 +238,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
// 0. 先同步车辆参数到渲染插件
|
||||
SyncVehicleParametersToRenderPlugin();
|
||||
SyncObjectParametersToRenderPlugin();
|
||||
|
||||
// 检查是否在编辑状态
|
||||
bool isInEditMode = _pathPlanningManager?.IsInEditableState ?? false;
|
||||
@ -330,40 +326,40 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
|
||||
public double VehicleLength
|
||||
public double ObjectLength
|
||||
{
|
||||
get => _vehicleLength;
|
||||
get => _ObjectLength;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _vehicleLength, value))
|
||||
if (SetProperty(ref _ObjectLength, value))
|
||||
{
|
||||
SyncVehicleParametersToRenderPlugin();
|
||||
SyncObjectParametersToRenderPlugin();
|
||||
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double VehicleWidth
|
||||
public double ObjectWidth
|
||||
{
|
||||
get => _vehicleWidth;
|
||||
get => _ObjectWidth;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _vehicleWidth, value))
|
||||
if (SetProperty(ref _ObjectWidth, value))
|
||||
{
|
||||
SyncVehicleParametersToRenderPlugin();
|
||||
SyncObjectParametersToRenderPlugin();
|
||||
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public double VehicleHeight
|
||||
public double ObjectHeight
|
||||
{
|
||||
get => _vehicleHeight;
|
||||
get => _ObjectHeight;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _vehicleHeight, value))
|
||||
if (SetProperty(ref _ObjectHeight, value))
|
||||
{
|
||||
SyncVehicleParametersToRenderPlugin();
|
||||
SyncObjectParametersToRenderPlugin();
|
||||
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
|
||||
}
|
||||
}
|
||||
@ -378,7 +374,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
var roundedValue = Math.Round(value, 2);
|
||||
if (SetProperty(ref _safetyMargin, roundedValue))
|
||||
{
|
||||
SyncVehicleParametersToRenderPlugin();
|
||||
SyncObjectParametersToRenderPlugin();
|
||||
OnPropertyChanged(nameof(CanExecuteAutoPlanPath));
|
||||
}
|
||||
}
|
||||
@ -558,12 +554,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// <summary>
|
||||
/// 是否显示通行空间(独立开关)
|
||||
/// </summary>
|
||||
public bool ShowVehicleSpace
|
||||
public bool ShowObjectSpace
|
||||
{
|
||||
get => _showVehicleSpace;
|
||||
get => _showObjectSpace;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _showVehicleSpace, value))
|
||||
if (SetProperty(ref _showObjectSpace, value))
|
||||
{
|
||||
OnPathVisualizationModeChanged();
|
||||
}
|
||||
@ -589,24 +585,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// </summary>
|
||||
public bool IsStandardLineMode
|
||||
{
|
||||
get => _showPathLines && !_showVehicleSpace;
|
||||
get => _showPathLines && !_showObjectSpace;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
ShowPathLines = true;
|
||||
ShowVehicleSpace = false;
|
||||
ShowObjectSpace = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用车辆通行空间模式(向后兼容,等同于 ShowVehicleSpace)
|
||||
/// 是否使用车辆通行空间模式(向后兼容,等同于 ShowObjectSpace)
|
||||
/// </summary>
|
||||
public bool IsVehicleSpaceMode
|
||||
public bool IsObjectSpaceMode
|
||||
{
|
||||
get => _showVehicleSpace;
|
||||
set => ShowVehicleSpace = value;
|
||||
get => _showObjectSpace;
|
||||
set => ShowObjectSpace = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -711,7 +707,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
#region Can Execute属性
|
||||
|
||||
public bool CanExecuteAutoPlanPath => _hasStartPoint && _hasEndPoint &&
|
||||
VehicleLength > 0 && VehicleWidth > 0 && VehicleHeight > 0 &&
|
||||
ObjectLength > 0 && ObjectWidth > 0 && ObjectHeight > 0 &&
|
||||
SafetyMargin >= 0;
|
||||
|
||||
public bool CanExecuteNewPath => !IsSelectingStartPoint && !IsSelectingEndPoint;
|
||||
@ -780,7 +776,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
// 初始化车辆参数同步(在PathPointRenderPlugin实例不为空时才同步)
|
||||
// 如果PathPointRenderPlugin尚未初始化,将在属性变更时自动同步
|
||||
SyncVehicleParametersToRenderPlugin();
|
||||
SyncObjectParametersToRenderPlugin();
|
||||
|
||||
// 注意:不在这里订阅PathPlanningManager事件,
|
||||
// 因为PathPlanningManager还没有设置,事件订阅在PathPlanningManager属性setter中处理
|
||||
@ -841,12 +837,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
// 从 PathEditing 配置加载所有参数(使用米单位接口)
|
||||
_gridSize = config.PathEditing.CellSizeMeters;
|
||||
_vehicleLength = config.PathEditing.VehicleLengthMeters;
|
||||
_vehicleWidth = config.PathEditing.VehicleWidthMeters;
|
||||
_vehicleHeight = config.PathEditing.VehicleHeightMeters;
|
||||
_ObjectLength = config.PathEditing.ObjectLengthMeters;
|
||||
_ObjectWidth = config.PathEditing.ObjectWidthMeters;
|
||||
_ObjectHeight = config.PathEditing.ObjectHeightMeters;
|
||||
_safetyMargin = config.PathEditing.SafetyMarginMeters;
|
||||
|
||||
LogManager.Info($"从配置加载参数 - 车辆: {_vehicleLength:F1}x{_vehicleWidth:F1}x{_vehicleHeight:F1}米, 安全间隙: {_safetyMargin:F2}米, 网格: {_gridSize:F1}米");
|
||||
LogManager.Info($"从配置加载参数 - 车辆: {_ObjectLength:F1}x{_ObjectWidth:F1}x{_ObjectHeight:F1}米, 安全间隙: {_safetyMargin:F2}米, 网格: {_gridSize:F1}米");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -910,19 +906,19 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
// 触发属性变更通知,更新UI
|
||||
OnPropertiesChanged(
|
||||
nameof(VehicleLength),
|
||||
nameof(VehicleWidth),
|
||||
nameof(VehicleHeight),
|
||||
nameof(ObjectLength),
|
||||
nameof(ObjectWidth),
|
||||
nameof(ObjectHeight),
|
||||
nameof(SafetyMargin),
|
||||
nameof(GridSize)
|
||||
);
|
||||
|
||||
// 同步车辆参数到渲染插件
|
||||
SyncVehicleParametersToRenderPlugin();
|
||||
SyncObjectParametersToRenderPlugin();
|
||||
|
||||
// 更新状态栏
|
||||
string source = eventArgs.IsExternalChange ? "外部修改" : "内部更新";
|
||||
UpdateMainStatus($"配置已更新 ({source}) - 车辆参数: {VehicleLength:F1}x{VehicleWidth:F1}x{VehicleHeight:F1}米");
|
||||
UpdateMainStatus($"配置已更新 ({source}) - 车辆参数: {ObjectLength:F1}x{ObjectWidth:F1}x{ObjectHeight:F1}米");
|
||||
|
||||
LogManager.Info($"PathEditing 配置参数已更新完成 - 来源: {source}");
|
||||
}
|
||||
@ -1639,10 +1635,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
LogManager.Info($"终点: ({_endPoint3D.X:F2}, {_endPoint3D.Y:F2}, {_endPoint3D.Z:F2})");
|
||||
|
||||
// 计算车辆半径:基于长度和宽度的较大值的一半,高度暂时不参与半径计算
|
||||
var vehicleRadius = Math.Max(VehicleLength, VehicleWidth) / 2.0;
|
||||
var ObjectRadius = Math.Max(ObjectLength, ObjectWidth) / 2.0;
|
||||
|
||||
LogManager.Info($"车辆参数: 长{VehicleLength:F1}m × 宽{VehicleWidth:F1}m × 高{VehicleHeight:F1}m");
|
||||
LogManager.Info($"计算得出车辆半径: {vehicleRadius:F2}m (基于长宽较大值的一半)");
|
||||
LogManager.Info($"车辆参数: 长{ObjectLength:F1}m × 宽{ObjectWidth:F1}m × 高{ObjectHeight:F1}m");
|
||||
LogManager.Info($"计算得出车辆半径: {ObjectRadius:F2}m (基于长宽较大值的一半)");
|
||||
|
||||
// 确定网格大小:如果启用手动设置则使用用户设置的值,否则使用-1(自动选择)
|
||||
var gridSize = IsGridSizeManuallyEnabled ? GridSize : -1;
|
||||
@ -1654,7 +1650,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
LogManager.Info($"路径策略: {SelectedPathStrategy?.DisplayName ?? "最短路径"}");
|
||||
|
||||
// 在STA线程中执行Navisworks API调用
|
||||
var pathRoute = await _pathPlanningManager?.AutoPlanPath(startPathPoint, endPathPoint, vehicleRadius, SafetyMargin, gridSize, VehicleHeight, selectedStrategy);
|
||||
var pathRoute = await _pathPlanningManager?.AutoPlanPath(startPathPoint, endPathPoint, ObjectRadius, SafetyMargin, gridSize, ObjectHeight, selectedStrategy);
|
||||
|
||||
if (pathRoute != null && pathRoute.Points.Count > 0)
|
||||
{
|
||||
@ -2778,7 +2774,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// <summary>
|
||||
/// 同步车辆参数到渲染插件
|
||||
/// </summary>
|
||||
private void SyncVehicleParametersToRenderPlugin()
|
||||
private void SyncObjectParametersToRenderPlugin()
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -2800,30 +2796,30 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
if (pathType == PathType.Rail)
|
||||
{
|
||||
// 空轨路径:车辆水平悬挂,垂直于路径的截面包含车辆的宽度和高度
|
||||
passageAcrossPath = VehicleWidth + 2 * SafetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = VehicleHeight + 2 * SafetyMargin; // Z方向(高度)+ 2*间隙(法线方向)
|
||||
passageAlongPath = VehicleLength; // X方向(长度)(沿路径方向)
|
||||
passageAcrossPath = ObjectWidth + 2 * SafetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = ObjectHeight + 2 * SafetyMargin; // Z方向(高度)+ 2*间隙(法线方向)
|
||||
passageAlongPath = ObjectLength; // X方向(长度)(沿路径方向)
|
||||
}
|
||||
else if (pathType == PathType.Hoisting)
|
||||
{
|
||||
// 吊装路径:车辆垂直悬挂,垂直于路径的截面包含车辆的长度和宽度
|
||||
passageAcrossPath = VehicleWidth + 2 * SafetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = VehicleLength + 2 * SafetyMargin; // X方向(长度)+ 2*间隙(法线方向)
|
||||
passageAlongPath = VehicleHeight; // Z方向(高度)(沿路径方向)
|
||||
passageAcrossPath = ObjectWidth + 2 * SafetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = ObjectLength + 2 * SafetyMargin; // X方向(长度)+ 2*间隙(法线方向)
|
||||
passageAlongPath = ObjectHeight; // Z方向(高度)(沿路径方向)
|
||||
}
|
||||
else // Ground
|
||||
{
|
||||
// 地面路径:高度只有上方加间隙
|
||||
passageAcrossPath = VehicleWidth + 2 * SafetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = VehicleHeight + SafetyMargin; // Z方向(高度)+ 间隙(法线方向,只有上方)
|
||||
passageAlongPath = VehicleLength; // X方向(长度)(沿路径方向)
|
||||
passageAcrossPath = ObjectWidth + 2 * SafetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = ObjectHeight + SafetyMargin; // Z方向(高度)+ 间隙(法线方向,只有上方)
|
||||
passageAlongPath = ObjectLength; // X方向(长度)(沿路径方向)
|
||||
}
|
||||
|
||||
// 设置通行空间参数到渲染插件
|
||||
// passageNormalToPathVertical: 垂直段的高度(物体长度 + 2×安全间隙)
|
||||
// passageNormalToPathHorizontal: 水平段的高度(物体高度 + 2×安全间隙)
|
||||
double passageNormalToPathVertical = VehicleLength + 2 * SafetyMargin;
|
||||
double passageNormalToPathHorizontal = VehicleHeight + 2 * SafetyMargin;
|
||||
double passageNormalToPathVertical = ObjectLength + 2 * SafetyMargin;
|
||||
double passageNormalToPathHorizontal = ObjectHeight + 2 * SafetyMargin;
|
||||
PathPointRenderPlugin.Instance.SetPassageSpaceParameters(
|
||||
passageAcrossPath,
|
||||
passageNormalToPath,
|
||||
@ -2943,14 +2939,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
case PathType.Hoisting:
|
||||
// 空中路径:通行空间 + 控制点,不能使用路径线
|
||||
ShowPathLines = false;
|
||||
ShowVehicleSpace = true;
|
||||
ShowObjectSpace = true;
|
||||
LogManager.Debug($"[路径编辑] 路径类型={pathType}(空中路径),默认模式:控制点+通行空间");
|
||||
break;
|
||||
|
||||
case PathType.Ground:
|
||||
// 地面路径:路径线 + 控制点,不使用通行空间
|
||||
ShowPathLines = true;
|
||||
ShowVehicleSpace = false;
|
||||
ShowObjectSpace = false;
|
||||
LogManager.Debug($"[路径编辑] 路径类型={pathType}(地面路径),默认模式:控制点+路径线");
|
||||
break;
|
||||
|
||||
@ -2959,7 +2955,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
LogManager.Info($"[路径编辑] 已根据路径类型自动设置可视化模式:控制点={ShowControlVisualization}, 路径线={ShowPathLines}, 通行空间={ShowVehicleSpace}");
|
||||
LogManager.Info($"[路径编辑] 已根据路径类型自动设置可视化模式:控制点={ShowControlVisualization}, 路径线={ShowPathLines}, 通行空间={ShowObjectSpace}");
|
||||
|
||||
// 🔥 触发可视化状态变更事件,通知状态栏刷新按钮
|
||||
_pathPlanningManager?.RaiseVisualizationStateChanged();
|
||||
@ -2982,14 +2978,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
// 使用新的独立开关设置渲染插件
|
||||
renderPlugin.ShowPathLines = ShowPathLines;
|
||||
renderPlugin.ShowVehicleSpace = ShowVehicleSpace;
|
||||
renderPlugin.ShowObjectSpace = ShowObjectSpace;
|
||||
|
||||
string modeName = "";
|
||||
if (ShowPathLines && ShowVehicleSpace)
|
||||
if (ShowPathLines && ShowObjectSpace)
|
||||
modeName = "路径线 + 通行空间";
|
||||
else if (ShowPathLines)
|
||||
modeName = "路径线";
|
||||
else if (ShowVehicleSpace)
|
||||
else if (ShowObjectSpace)
|
||||
modeName = "通行空间";
|
||||
else
|
||||
modeName = "无路径可视化";
|
||||
@ -3806,7 +3802,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
/// <summary>
|
||||
/// 车辆参数类 - 用于传递车辆尺寸信息给路径规划算法
|
||||
/// </summary>
|
||||
public class VehicleParameters
|
||||
public class ObjectParameters
|
||||
{
|
||||
public double Length { get; set; }
|
||||
public double Width { get; set; }
|
||||
|
||||
@ -1268,8 +1268,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
document,
|
||||
cellSize: cellSizeMeters, // 使用系统配置的体素大小
|
||||
samplingRate: 1, // 采样率 1(显示所有体素)
|
||||
vehicleRadius: 0.6, // 车辆半径 0.6米(必须 >= 体素大小才能看到膨胀效果)
|
||||
vehicleHeight: 1.8 // 车辆高度 1.8米
|
||||
objectRadius: 0.6, // 物体半径 0.6米(必须 >= 体素大小才能看到膨胀效果)
|
||||
objectHeight: 1.8 // 物体高度 1.8米
|
||||
);
|
||||
|
||||
var result = await testCommand.ExecuteAsync();
|
||||
@ -1359,8 +1359,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
var testCommand = new VoxelPathFindingTestCommand(
|
||||
document,
|
||||
cellSize: cellSizeMeters, // 体素大小(米)
|
||||
vehicleRadius: 0.6, // 车辆半径 0.6米
|
||||
vehicleHeight: 1.8, // 车辆高度 1.8米
|
||||
objectRadius: 0.6, // 物体半径 0.6米
|
||||
objectHeight: 1.8, // 物体高度 1.8米
|
||||
startPoint: startPoint, // 起点
|
||||
endPoint: endPoint // 终点
|
||||
);
|
||||
|
||||
@ -322,7 +322,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
GroupName="ObjectSource"
|
||||
VerticalAlignment="Center"/>
|
||||
<RadioButton Content="使用虚拟车辆"
|
||||
IsChecked="{Binding UseVirtualVehicle}"
|
||||
IsChecked="{Binding UseVirtualObject}"
|
||||
GroupName="ObjectSource"
|
||||
VerticalAlignment="Center"
|
||||
Margin="10,0,0,0"/>
|
||||
@ -330,7 +330,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
|
||||
<!-- 方式1:选择模型物体 -->
|
||||
<Grid Margin="0,5,0,0"
|
||||
Visibility="{Binding UseVirtualVehicle, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Inverse}">
|
||||
Visibility="{Binding UseVirtualObject, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Inverse}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
@ -361,7 +361,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
|
||||
<!-- 方式2:虚拟车辆 -->
|
||||
<Grid Margin="0,5,0,0"
|
||||
Visibility="{Binding UseVirtualVehicle, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
Visibility="{Binding UseVirtualObject, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
@ -375,11 +375,11 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
Foreground="#FF2B579A"
|
||||
Background="#FFF5F5F5">
|
||||
<Run Text="长 "/>
|
||||
<Run Text="{Binding VirtualVehicleLength, StringFormat=F1, Mode=OneWay}"/>
|
||||
<Run Text="{Binding VirtualObjectLength, StringFormat=F1, Mode=OneWay}"/>
|
||||
<Run Text="m × 宽 "/>
|
||||
<Run Text="{Binding VirtualVehicleWidth, StringFormat=F1, Mode=OneWay}"/>
|
||||
<Run Text="{Binding VirtualObjectWidth, StringFormat=F1, Mode=OneWay}"/>
|
||||
<Run Text="m × 高 "/>
|
||||
<Run Text="{Binding VirtualVehicleHeight, StringFormat=F1, Mode=OneWay}"/>
|
||||
<Run Text="{Binding VirtualObjectHeight, StringFormat=F1, Mode=OneWay}"/>
|
||||
<Run Text="m"/>
|
||||
</TextBlock>
|
||||
<Button Grid.Column="2"
|
||||
@ -394,7 +394,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
Style="{StaticResource StatusTextStyle}"
|
||||
Foreground="#FF666666"
|
||||
Margin="5,0,0,5"
|
||||
Visibility="{Binding UseVirtualVehicle, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
Visibility="{Binding UseVirtualObject, Converter={StaticResource BoolToVisibilityConverter}}"/>
|
||||
|
||||
<!-- 选择路径 -->
|
||||
<Grid Margin="0,5,0,0">
|
||||
@ -427,7 +427,12 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
<Button Content="添加到批处理"
|
||||
Command="{Binding AddToBatchQueueCommand}"
|
||||
IsEnabled="{Binding CanGenerateAnimation}"
|
||||
Style="{StaticResource ActionButtonStyle}"/>
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
Margin="0,0,10,0"/>
|
||||
<CheckBox Content="使用剖面盒优化"
|
||||
IsChecked="{Binding UseSectionClip}"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip="启用剖面盒可大幅提升大型模型的碰撞检测性能(用于性能对比测试)"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 生成状态提示 -->
|
||||
|
||||
@ -132,12 +132,12 @@ NavisworksTransport 主控制面板 - 采用与其他视图一致的Navisworks 2
|
||||
<TextBlock Text="LN" FontSize="9" FontWeight="Bold"
|
||||
Foreground="{Binding ShowPathLines, Converter={StaticResource BoolToBrushConverter}, ConverterParameter=Blue}"/>
|
||||
</ToggleButton>
|
||||
<ToggleButton IsChecked="{Binding ShowVehicleSpace}"
|
||||
<ToggleButton IsChecked="{Binding ShowObjectSpace}"
|
||||
ToolTip="通行空间"
|
||||
Width="28" Height="24"
|
||||
Margin="2,0">
|
||||
<TextBlock Text="SP" FontSize="9" FontWeight="Bold"
|
||||
Foreground="{Binding ShowVehicleSpace, Converter={StaticResource BoolToBrushConverter}, ConverterParameter=Orange}"/>
|
||||
Foreground="{Binding ShowObjectSpace, Converter={StaticResource BoolToBrushConverter}, ConverterParameter=Orange}"/>
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@ -169,10 +169,10 @@ namespace NavisworksTransport.UI.WPF
|
||||
LogManager.Info("AnimationControlView初始化完成 - 已设置PathPlanningManager");
|
||||
}
|
||||
|
||||
// 初始化时同步车辆参数
|
||||
SyncVehicleParametersToAnimationView();
|
||||
// 初始化时同步物体参数
|
||||
SyncObjectParametersToAnimationView();
|
||||
|
||||
LogManager.Info("AnimationControlView初始化完成 - 支持统一状态栏和虚拟车辆");
|
||||
LogManager.Info("AnimationControlView初始化完成 - 支持统一状态栏和虚拟物体");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -464,13 +464,13 @@ namespace NavisworksTransport.UI.WPF
|
||||
SyncCurrentPathToAnimationView();
|
||||
LogManager.Info("PathEditingView路径选择已变化,同步到动画控制视图");
|
||||
}
|
||||
// 当车辆参数变化时,同步到AnimationControlView
|
||||
else if (e.PropertyName == nameof(PathEditingViewModel.VehicleLength) ||
|
||||
e.PropertyName == nameof(PathEditingViewModel.VehicleWidth) ||
|
||||
e.PropertyName == nameof(PathEditingViewModel.VehicleHeight) ||
|
||||
// 当物体参数变化时,同步到AnimationControlView
|
||||
else if (e.PropertyName == nameof(PathEditingViewModel.ObjectLength) ||
|
||||
e.PropertyName == nameof(PathEditingViewModel.ObjectWidth) ||
|
||||
e.PropertyName == nameof(PathEditingViewModel.ObjectHeight) ||
|
||||
e.PropertyName == nameof(PathEditingViewModel.SafetyMargin))
|
||||
{
|
||||
SyncVehicleParametersToAnimationView();
|
||||
SyncObjectParametersToAnimationView();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -480,27 +480,27 @@ namespace NavisworksTransport.UI.WPF
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步车辆参数到动画控制视图
|
||||
/// 同步物体参数到动画控制视图
|
||||
/// </summary>
|
||||
private void SyncVehicleParametersToAnimationView()
|
||||
private void SyncObjectParametersToAnimationView()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (AnimationControlView?.ViewModel != null && PathEditingView?.ViewModel != null)
|
||||
{
|
||||
var pathEditingVM = PathEditingView.ViewModel;
|
||||
AnimationControlView.ViewModel.SetVirtualVehicleParameters(
|
||||
pathEditingVM.VehicleLength,
|
||||
pathEditingVM.VehicleWidth,
|
||||
pathEditingVM.VehicleHeight,
|
||||
AnimationControlView.ViewModel.SetVirtualObjectParameters(
|
||||
pathEditingVM.ObjectLength,
|
||||
pathEditingVM.ObjectWidth,
|
||||
pathEditingVM.ObjectHeight,
|
||||
pathEditingVM.SafetyMargin
|
||||
);
|
||||
LogManager.Debug($"车辆参数已同步到动画控制视图: {pathEditingVM.VehicleLength:F1}×{pathEditingVM.VehicleWidth:F1}×{pathEditingVM.VehicleHeight:F1}m, 检测间隙: {pathEditingVM.SafetyMargin:F2}m");
|
||||
LogManager.Debug($"物体参数已同步到动画控制视图: {pathEditingVM.ObjectLength:F1}×{pathEditingVM.ObjectWidth:F1}×{pathEditingVM.ObjectHeight:F1}m, 检测间隙: {pathEditingVM.SafetyMargin:F2}m");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"同步车辆参数到动画控制视图失败: {ex.Message}");
|
||||
LogManager.Error($"同步物体参数到动画控制视图失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
<StackPanel>
|
||||
<Label Content="物流类型" Style="{StaticResource SectionHeaderStyle}"/>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<RadioButton Name="rbVirtualVehicle" Content="使用虚拟物体" Margin="0,0,20,0" Checked="rbVirtualVehicle_Checked"/>
|
||||
<RadioButton Name="rbVirtualObject" Content="使用虚拟物体" Margin="0,0,20,0" Checked="rbVirtualObject_Checked"/>
|
||||
<RadioButton Name="rbRealObject" Content="使用真实物体" Checked="rbRealObject_Checked"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
@ -51,7 +51,7 @@
|
||||
|
||||
<!-- 虚拟物体参数 -->
|
||||
<Border Grid.Row="1" BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Padding="12" Margin="0,0,0,10"
|
||||
Name="borderVirtualVehicle">
|
||||
Name="borderVirtualObject">
|
||||
<StackPanel>
|
||||
<Label Content="虚拟物体尺寸(米)" Style="{StaticResource SectionHeaderStyle}"/>
|
||||
<Grid Margin="0,10,0,0">
|
||||
@ -67,15 +67,15 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="长度(X轴):" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Name="txtVehicleLength" Text="1.0" Margin="0,0,5,5"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Name="txtObjectLength" Text="1.0" Margin="0,0,5,5"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="2" Text="米" VerticalAlignment="Center" Margin="0,0,0,5"/>
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="宽度(Y轴):" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Name="txtVehicleWidth" Text="1.0" Margin="0,0,5,5"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Name="txtObjectWidth" Text="1.0" Margin="0,0,5,5"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" Text="米" VerticalAlignment="Center" Margin="0,0,0,5"/>
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="高度(Z轴):" VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Name="txtVehicleHeight" Text="2.0" Margin="0,0,5,5"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Name="txtObjectHeight" Text="2.0" Margin="0,0,5,5"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="2" Text="米" VerticalAlignment="Center" Margin="0,0,0,5"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
@ -25,12 +25,12 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
|
||||
// 从系统配置读取虚拟车辆默认值
|
||||
var systemConfig = ConfigManager.Instance.Current;
|
||||
txtVehicleLength.Text = systemConfig.PathEditing.VehicleLengthMeters.ToString("F2");
|
||||
txtVehicleWidth.Text = systemConfig.PathEditing.VehicleWidthMeters.ToString("F2");
|
||||
txtVehicleHeight.Text = systemConfig.PathEditing.VehicleHeightMeters.ToString("F2");
|
||||
txtObjectLength.Text = systemConfig.PathEditing.ObjectLengthMeters.ToString("F2");
|
||||
txtObjectWidth.Text = systemConfig.PathEditing.ObjectWidthMeters.ToString("F2");
|
||||
txtObjectHeight.Text = systemConfig.PathEditing.ObjectHeightMeters.ToString("F2");
|
||||
|
||||
// 设置初始状态(在 InitializeComponent 之后,避免触发 Checked 事件)
|
||||
rbVirtualVehicle.IsChecked = true;
|
||||
rbVirtualObject.IsChecked = true;
|
||||
|
||||
// 如果有现有配置,加载它(会覆盖上面的默认值)
|
||||
if (existingConfig != null)
|
||||
@ -46,10 +46,10 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
{
|
||||
var result = new PathConfigResult
|
||||
{
|
||||
IsVirtualVehicle = rbVirtualVehicle.IsChecked == true,
|
||||
VirtualVehicleLength = double.Parse(txtVehicleLength.Text),
|
||||
VirtualVehicleWidth = double.Parse(txtVehicleWidth.Text),
|
||||
VirtualVehicleHeight = double.Parse(txtVehicleHeight.Text),
|
||||
IsVirtualObject = rbVirtualObject.IsChecked == true,
|
||||
VirtualObjectLength = double.Parse(txtObjectLength.Text),
|
||||
VirtualObjectWidth = double.Parse(txtObjectWidth.Text),
|
||||
VirtualObjectHeight = double.Parse(txtObjectHeight.Text),
|
||||
MovingObjectId = _selectedObject?.ToString(),
|
||||
MovingObjectName = _selectedObject?.DisplayName,
|
||||
DetectionItems = _detectionItems.Select(i => i.ToString()).ToList(),
|
||||
@ -77,9 +77,9 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
{
|
||||
if (config == null) return;
|
||||
|
||||
txtVehicleLength.Text = config.VirtualVehicleLength.ToString("F2");
|
||||
txtVehicleWidth.Text = config.VirtualVehicleWidth.ToString("F2");
|
||||
txtVehicleHeight.Text = config.VirtualVehicleHeight.ToString("F2");
|
||||
txtObjectLength.Text = config.VirtualObjectLength.ToString("F2");
|
||||
txtObjectWidth.Text = config.VirtualObjectWidth.ToString("F2");
|
||||
txtObjectHeight.Text = config.VirtualObjectHeight.ToString("F2");
|
||||
txtFrameRate.Text = config.FrameRate.ToString();
|
||||
txtDuration.Text = config.DurationSeconds.ToString("F2");
|
||||
txtDetectionGap.Text = config.DetectionToleranceMeters.ToString("F2");
|
||||
@ -88,9 +88,9 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
/// <summary>
|
||||
/// 虚拟车辆选中
|
||||
/// </summary>
|
||||
private void rbVirtualVehicle_Checked(object sender, RoutedEventArgs e)
|
||||
private void rbVirtualObject_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
borderVirtualVehicle.Visibility = Visibility.Visible;
|
||||
borderVirtualObject.Visibility = Visibility.Visible;
|
||||
borderRealObject.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
/// </summary>
|
||||
private void rbRealObject_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
borderVirtualVehicle.Visibility = Visibility.Collapsed;
|
||||
borderVirtualObject.Visibility = Visibility.Collapsed;
|
||||
borderRealObject.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
@ -208,21 +208,21 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
try
|
||||
{
|
||||
// 验证虚拟车辆参数
|
||||
if (rbVirtualVehicle.IsChecked == true)
|
||||
if (rbVirtualObject.IsChecked == true)
|
||||
{
|
||||
if (!double.TryParse(txtVehicleLength.Text, out var length) || length <= 0)
|
||||
if (!double.TryParse(txtObjectLength.Text, out var length) || length <= 0)
|
||||
{
|
||||
MessageBox.Show("请输入有效的车辆长度", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!double.TryParse(txtVehicleWidth.Text, out var width) || width <= 0)
|
||||
if (!double.TryParse(txtObjectWidth.Text, out var width) || width <= 0)
|
||||
{
|
||||
MessageBox.Show("请输入有效的车辆宽度", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!double.TryParse(txtVehicleHeight.Text, out var height) || height <= 0)
|
||||
if (!double.TryParse(txtObjectHeight.Text, out var height) || height <= 0)
|
||||
{
|
||||
MessageBox.Show("请输入有效的车辆高度", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
@ -282,10 +282,10 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
/// </summary>
|
||||
public class PathConfigResult
|
||||
{
|
||||
public bool IsVirtualVehicle { get; set; }
|
||||
public double VirtualVehicleLength { get; set; }
|
||||
public double VirtualVehicleWidth { get; set; }
|
||||
public double VirtualVehicleHeight { get; set; }
|
||||
public bool IsVirtualObject { get; set; }
|
||||
public double VirtualObjectLength { get; set; }
|
||||
public double VirtualObjectWidth { get; set; }
|
||||
public double VirtualObjectHeight { get; set; }
|
||||
public string MovingObjectId { get; set; }
|
||||
public string MovingObjectName { get; set; }
|
||||
public List<string> DetectionItems { get; set; }
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管理一致的Navisworks 2026风格
|
||||
|
||||
功能说明:
|
||||
1. 自动路径规划:起终点选择、车辆尺寸参数(长宽高)、安全间隙设置
|
||||
1. 自动路径规划:起终点选择、运动物体尺寸参数(长宽高)、安全间隙设置
|
||||
2. 路径列表:新建、删除、重命名路径,显示路径状态
|
||||
3. 路径编辑:开始编辑、结束编辑、清空路径、路径点管理
|
||||
4. 路径文件管理:导入、导出全部、导出选中路径操作和状态显示
|
||||
@ -65,7 +65,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 车辆参数设置 - 改为三个独立参数 -->
|
||||
<!-- 运动物体参数设置 - 改为三个独立参数 -->
|
||||
<Grid Margin="0,5,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
@ -80,24 +80,24 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 车辆长度 -->
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="车辆长度:" Style="{StaticResource ParameterLabelStyle}"/>
|
||||
<!-- 运动物体长度 -->
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="运动物体长度:" Style="{StaticResource ParameterLabelStyle}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1"
|
||||
Text="{Binding VehicleLength, StringFormat=0.0###}"
|
||||
Text="{Binding ObjectLength, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Grid.Row="0" Grid.Column="2" Content="米" Style="{StaticResource UnitLabelStyle}"/>
|
||||
|
||||
<!-- 车辆宽度 -->
|
||||
<Label Grid.Row="0" Grid.Column="3" Content="车辆宽度:" Style="{StaticResource ParameterLabelStyle}"/>
|
||||
<!-- 运动物体宽度 -->
|
||||
<Label Grid.Row="0" Grid.Column="3" Content="运动物体宽度:" Style="{StaticResource ParameterLabelStyle}"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="4"
|
||||
Text="{Binding VehicleWidth, StringFormat=0.0###}"
|
||||
Text="{Binding ObjectWidth, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Grid.Row="0" Grid.Column="5" Content="米" Style="{StaticResource UnitLabelStyle}"/>
|
||||
|
||||
<!-- 车辆高度 -->
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="车辆高度:" Style="{StaticResource ParameterLabelStyle}"/>
|
||||
<!-- 运动物体高度 -->
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="运动物体高度:" Style="{StaticResource ParameterLabelStyle}"/>
|
||||
<TextBox Grid.Row="1" Grid.Column="1"
|
||||
Text="{Binding VehicleHeight, StringFormat=0.0###}"
|
||||
Text="{Binding ObjectHeight, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Grid.Row="1" Grid.Column="2" Content="米" Style="{StaticResource UnitLabelStyle}"/>
|
||||
|
||||
@ -463,7 +463,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
|
||||
ToolTip="显示路径线/地面连线(仅地面路径可用)"/>
|
||||
<!-- 通行空间开关 -->
|
||||
<CheckBox Content="通行空间"
|
||||
IsChecked="{Binding ShowVehicleSpace}"
|
||||
IsChecked="{Binding ShowObjectSpace}"
|
||||
VerticalAlignment="Center"
|
||||
ToolTip="显示通行空间(矩形通道)"/>
|
||||
</StackPanel>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user