重构碰撞检测参数,替换为检测容差;更新相关配置和UI显示,确保一致性

This commit is contained in:
tian 2026-01-26 00:25:05 +08:00
parent b4a73e2081
commit c117e0d0c3
24 changed files with 434 additions and 278 deletions

View File

@ -37,8 +37,8 @@ frame_rate = 30
# 动画持续时间(秒)
duration_seconds = 10.0
# 检测间隙(米)
detection_gap_meters = 0.05
# 检测容差(米)- 用于ClashDetective精确检测
detection_tolerance_meters = 0.05
# 空间索引格子大小(米)
spatial_index_cell_size = 1.0

View File

@ -76,7 +76,7 @@
│ │
│ // 执行碰撞检测 │
│ var collisions = ClashDetectiveIntegration.Instance.DetectCollisions( │
│ _animatedObject, null, _detectionGap); │
│ _animatedObject, null, _detectionTolerance:F4); │
│ │
│ // 创建帧数据 │
│ var frame = new AnimationFrame │

View File

@ -85,7 +85,7 @@ namespace NavisworksTransport.Commands
public string PathName { get; set; }
public int FrameRate { get; set; }
public double Duration { get; set; }
public double DetectionGap { get; set; }
public double DetectionTolerance { get; set; }
// 新增:截图信息
public string ScreenshotPath { get; set; }
@ -163,7 +163,7 @@ namespace NavisworksTransport.Commands
{
result.FrameRate = animationManager.AnimationFrameRate;
result.Duration = animationManager.AnimationDuration;
result.DetectionGap = animationManager.DetectionGap;
result.DetectionTolerance = animationManager.DetectionTolerance;
// PathName需要从动画管理器获取
result.PathName = animationManager.PathName ?? "未知路径";
}

View File

@ -131,8 +131,8 @@ namespace NavisworksTransport.Core.Animation
private int _animationFrameRate; // 动画帧率默认30FPS
private double _collisionDetectionAccuracy; // 检测精度(内部存储:模型单位/帧)
private double _movementSpeed; // 运动速度(仅用于显示,单位:米/秒)
private double _detectionGap; // 检测间隙(内部存储:模型单位
private double _precomputedDetectionGap; // 预计算时使用的扩大检测间隙(内部存储:模型单位
private double _detectionTolerance; // 检测容差从UI设置
private double _safetyMargin; // 安全间隙模型单位从CreateAnimation传入
private string _pathName; // 路径名称
private string _currentRouteId; // 当前路由ID
@ -185,11 +185,7 @@ namespace NavisworksTransport.Core.Animation
var config = ConfigManager.Instance.Current;
_animationFrameRate = config.Animation.FrameRate;
_animationDuration = config.Animation.DurationSeconds;
var detectionGapMeters = config.Animation.DetectionGapMeters;
_detectionGap = UnitsConverter.ConvertFromMeters(detectionGapMeters);
_precomputedDetectionGap = _detectionGap;
// 初始化动画模式
_frameInterval = 1000.0 / _animationFrameRate; // 计算帧间隔
_lastFrameTime = DateTime.MinValue;
@ -260,29 +256,53 @@ namespace NavisworksTransport.Core.Animation
try
{
var doc = NavisApplication.ActiveDocument;
if (doc == null || _animatedObject == null) return;
if (doc == null) return;
var modelItems = new ModelItemCollection { _animatedObject };
// 🔥 支持虚拟车辆的恢复
ModelItem objectToRestore = null;
bool isVirtual = _isVirtualVehicle;
if (isVirtual)
{
objectToRestore = VirtualVehicleManager.Instance.CurrentVirtualVehicle;
if (objectToRestore == null)
{
LogManager.Warning("[归位] 虚拟车辆未激活,跳过恢复");
return;
}
}
else
{
objectToRestore = _animatedObject;
if (objectToRestore == null)
{
LogManager.Warning("[归位] 没有动画对象,跳过恢复");
return;
}
}
var modelItems = new ModelItemCollection { objectToRestore };
// 1. 彻底清除 Navisworks 中的所有覆盖变换,强制恢复到设计文件定义的原始状态
doc.Models.ResetPermanentTransform(modelItems);
// 2. 重置内部跟踪变量(同步到 CAD 原始状态)
// 注意ResetPermanentTransform 后物体的 Transform 属性会自动变回 CAD 原始值
_currentYaw = ModelItemTransformHelper.GetYawFromTransform(_animatedObject.Transform);
// 2. 重置内部跟踪变量(同步到原始状态)
// 注意ResetPermanentTransform 后物体的 Transform 属性会自动变回原始值
_currentYaw = ModelItemTransformHelper.GetYawFromTransform(objectToRestore.Transform);
var originalBoundingBox = _animatedObject.BoundingBox();
var originalBoundingBox = objectToRestore.BoundingBox();
_currentPosition = new Point3D(
originalBoundingBox.Center.X,
originalBoundingBox.Center.Y,
originalBoundingBox.Min.Z
);
LogManager.Info($"[归位] 物体 {_animatedObject.DisplayName} 已彻底恢复到 CAD 原始位置, yaw={_currentYaw:F3}");
string objectName = isVirtual ? "虚拟车辆" : objectToRestore.DisplayName;
LogManager.Info($"[归位] {objectName} 已彻底恢复到原始位置, yaw={_currentYaw:F3}");
}
catch (Exception ex)
{
LogManager.Error($"[归位] 恢复物体到 CAD 位置失败: {ex.Message}");
LogManager.Error($"[归位] 恢复物体到原始位置失败: {ex.Message}");
}
}
@ -320,11 +340,23 @@ namespace NavisworksTransport.Core.Animation
/// <summary>
/// 设置动画参数(批处理专用)
/// </summary>
public void SetAnimationParameters(int frameRate, double duration, double detectionGap)
public void SetAnimationParameters(int frameRate, double duration, double detectionTolerance)
{
_animationFrameRate = frameRate;
_animationDuration = duration;
_precomputedDetectionGap = detectionGap;
// 注意:预计算使用安全间隙,不使用检测容差
}
/// <summary>
/// 检测容差(米)- 用于ClashDetective精确检测
/// </summary>
public double DetectionTolerance
{
get
{
var config = ConfigManager.Instance.Current;
return config.Animation.DetectionToleranceMeters;
}
}
/// <summary>
@ -431,6 +463,14 @@ namespace NavisworksTransport.Core.Animation
{
try
{
// 🔥 重要先恢复物体到原始状态CAD位置和原始朝向确保每次计算都从相同的状态开始
// 这样可以避免之前旋转导致的包围盒尺寸计算不准确的问题
if (_animatedObject != null)
{
RestoreObjectToCADPosition();
LogManager.Info($"[移动到起点] 已恢复物体到原始状态");
}
// 如果提供了参数,更新内部状态
if (animatedObject != null)
{
@ -523,6 +563,28 @@ namespace NavisworksTransport.Core.Animation
}
LogManager.Info($"物体已初始化到路径起点并对齐朝向: pos=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2}), yaw={yaw:F3}rad, 路径类型={pathTypeName}");
// 打印实际物体的位置和方向
if (_animatedObject != null)
{
var bbox = _animatedObject.BoundingBox();
var actualCenter = bbox.Center;
var actualYaw = ModelItemTransformHelper.GetYawFromTransform(_animatedObject.Transform);
LogManager.Info($"实际物体位置: X={actualCenter.X:F2}, Y={actualCenter.Y:F2}, Z={actualCenter.Z:F2}");
LogManager.Info($"实际物体朝向: {actualYaw * 180 / Math.PI:F2}度");
}
else if (_isVirtualVehicle)
{
var virtualVehicle = VirtualVehicleManager.Instance.CurrentVirtualVehicle;
if (virtualVehicle != null)
{
var bbox = virtualVehicle.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}度");
}
}
}
catch (Exception ex)
{
@ -539,6 +601,14 @@ namespace NavisworksTransport.Core.Animation
{
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);
LogManager.Info("[预计算] 物体已移动到路径起点");
}
int totalFrames = (int)(_animationDuration * _animationFrameRate);
// 🔥 判断路径类型空中路径使用Points地面路径使用Edges
@ -620,6 +690,9 @@ namespace NavisworksTransport.Core.Animation
var manualTargetsSnapshot = new List<ModelItem>();
bool manualOverrideActive = _manualCollisionOverrideEnabled && _manualCollisionTargets != null && _manualCollisionTargets.Count > 0;
// 获取配置
var config = ConfigManager.Instance.Current;
if (manualOverrideActive)
{
manualTargetsSnapshot = _manualCollisionTargets
@ -647,8 +720,8 @@ namespace NavisworksTransport.Core.Animation
spatialIndexManager = SpatialIndexManager.Instance;
// 使用动画专用的空间索引格子大小配置
double cellSizeInModelUnits = UnitsConverter.ConvertFromMeters(ConfigManager.Instance.Current.Animation.SpatialIndexCellSize);
// 使用动画专用的空间索引格子大小配置 - 使用模型单位接口
double cellSizeInModelUnits = config.Animation.SpatialIndexCellSize;
LogManager.Info($"[空间索引] 格子大小: {cellSizeInModelUnits:F2}模型单位 (动画配置)");
@ -672,8 +745,9 @@ namespace NavisworksTransport.Core.Animation
// 原因:车辆在通道上水平移动,主要检测侧面碰撞
double maxHorizontalDimension = Math.Max(boundingBoxSize.X, boundingBoxSize.Y);
searchRadiusInModelUnits = maxHorizontalDimension + _precomputedDetectionGap;
LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位 (基于最大水平尺寸: {maxHorizontalDimension:F2})");
// 🔥 使用安全间隙计算空间查询半径 - _safetyMargin 已是模型单位
searchRadiusInModelUnits = maxHorizontalDimension + _safetyMargin;
LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位 (基于最大水平尺寸: {maxHorizontalDimension:F2}, 安全间隙: {_safetyMargin:F4}模型单位)");
}
// 3. 生成每一帧
@ -857,11 +931,12 @@ namespace NavisworksTransport.Core.Animation
// 使用包围盒距离检测方法
double distance = BoundingBoxGeometryUtils.CalculateDistance(virtualBoundingBox, colliderBox);
bool intersects = distance <= _precomputedDetectionGap;
var safetyMarginInModelUnits = UnitsConverter.ConvertFromMeters(_safetyMargin);
bool intersects = distance <= safetyMarginInModelUnits;
if (intersects)
{
LogManager.Debug($"帧 {i} 检测到碰撞: {_animatedObject.DisplayName} <-> {collider.DisplayName}, 距离: {distance:F4},阈值: {_precomputedDetectionGap:F4}");
LogManager.Debug($"帧 {i} 检测到碰撞: {_animatedObject.DisplayName} <-> {collider.DisplayName}, 距离: {distance:F4},阈值: {safetyMarginInModelUnits:F4}");
LogManager.Debug($"移动物体位置: {framePosition.X:F2},{framePosition.Y:F2},{framePosition.Z:F2}");
LogManager.Debug($"被撞物体位置:{GetObjectPosition(collider).X:F2},{GetObjectPosition(collider).Y:F2},{GetObjectPosition(collider).Z:F2}");
@ -1454,9 +1529,10 @@ namespace NavisworksTransport.Core.Animation
try
{
// 🔥 使用用户设置的检测容差(米)
ClashDetectiveIntegration.Instance.CreateAllAnimationCollisionTests(
_allCollisionResults,
_detectionGap,
_detectionTolerance,
_pathName,
_currentRouteId,
_animatedObject,
@ -1465,7 +1541,8 @@ namespace NavisworksTransport.Core.Animation
_animationDuration,
_virtualVehicleLength,
_virtualVehicleWidth,
_virtualVehicleHeight
_virtualVehicleHeight,
_pathPoints
);
}
finally
@ -2390,23 +2467,12 @@ namespace NavisworksTransport.Core.Animation
}
/// <summary>
/// 设置检测间隙(参数单位:米)
/// 设置检测容差(参数单位:米)
/// </summary>
public void SetDetectionGap(double gapInMeters)
public void SetDetectionTolerance(double toleranceInMeters)
{
// 转换为模型单位存储
var gapInModelUnits = UnitsConverter.ConvertFromMeters(Math.Max(0.0, gapInMeters));
var roundedGapInModelUnits = Math.Round(gapInModelUnits, 4); // 模型单位保留更多精度
// 只在值真正改变时才更新和记录日志
if (Math.Abs(_detectionGap - roundedGapInModelUnits) > 0.0001)
{
_detectionGap = roundedGapInModelUnits;
LogManager.Info($"检测间隙设置为: {gapInMeters:F2}米");
// 预计算检测间隙与检测间隙相同
_precomputedDetectionGap = _detectionGap;
}
_detectionTolerance = Math.Max(0.0, toleranceInMeters);
LogManager.Info($"检测容差设置为: {_detectionTolerance:F2}米仅用于ClashDetective");
}
/// <summary>
@ -2476,9 +2542,7 @@ namespace NavisworksTransport.Core.Animation
{
get
{
// 将内部模型单位转换为米制单位
var modelUnitsToMeters = UnitsConverter.GetUnitsToMetersConversionFactor();
return _detectionGap * modelUnitsToMeters;
return _detectionTolerance;
}
}
@ -2514,14 +2578,15 @@ namespace NavisworksTransport.Core.Animation
/// <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 virtualVehicleLength = 0, double virtualVehicleWidth = 0, double virtualVehicleHeight = 0, double safetyMargin = 0)
{
_pathName = pathName;
_currentRouteId = routeId;
_isVirtualVehicle = isVirtualVehicle; // 设置是否使用虚拟车辆
_virtualVehicleLength = virtualVehicleLength;
_virtualVehicleWidth = virtualVehicleWidth;
_virtualVehicleHeight = virtualVehicleHeight;
_virtualVehicleLength = virtualVehicleLength; // 模型单位
_virtualVehicleWidth = virtualVehicleWidth; // 模型单位
_virtualVehicleHeight = virtualVehicleHeight; // 模型单位
_safetyMargin = safetyMargin; // 模型单位
_pathPoints = pathPoints;
_animatedObject = animatedObject;
@ -2824,7 +2889,7 @@ namespace NavisworksTransport.Core.Animation
// 包含动画参数(确保参数改变时重新检测)
sb.Append($"Duration:{_animationDuration:F2}s");
sb.Append($"|FrameRate:{_animationFrameRate}");
sb.Append($"|DetectionGap:{_detectionGap:F4}");
sb.Append($"|DetectionTolerance:{_detectionTolerance:F4}");
sb.Append("|");
// 包含虚拟车辆尺寸(确保车辆尺寸改变时重新检测)

View File

@ -202,6 +202,13 @@ namespace NavisworksTransport.Core
{
animatedObject = FindModelItemById(item.VehicleObjectId);
isVirtualVehicle = false;
if (animatedObject == null)
{
throw new InvalidOperationException("未找到指定的运动物体");
}
LogManager.Info($"[批处理] 使用真实物体: {animatedObject.DisplayName}");
}
else if (isVirtualVehicle)
{
@ -230,23 +237,19 @@ namespace NavisworksTransport.Core
// 在主线程执行Navisworks API调用
var frames = await UIStateManager.Instance.ExecuteUIUpdateAsync(() =>
{
// 🔥 重要:预计算前必须将车辆移动到起点位置,确保变换状态与实际动画播放时一致
var animationManager = PathAnimationManager.GetInstance();
animationManager.MoveVehicleToPathStart(animatedObject, pathRoute.Points.Select(p => p.Position).ToList());
// 预计算动画帧和碰撞
var config = new CollisionDetectionConfig
{
FrameRate = item.FrameRate,
DurationSeconds = item.DurationSeconds,
DetectionGapMeters = item.DetectionGapMeters,
DetectionToleranceMeters = item.DetectionToleranceMeters,
VirtualVehicleLength = item.VirtualVehicleLength,
VirtualVehicleWidth = item.VirtualVehicleWidth,
VirtualVehicleHeight = item.VirtualVehicleHeight,
CollisionDetectionEnabled = true,
ReportGenerationEnabled = true
};
return _executor._processor.PrecomputeFrames(
pathRoute,
animatedObject,
@ -256,7 +259,7 @@ namespace NavisworksTransport.Core
config.VirtualVehicleHeight,
config.FrameRate,
config.DurationSeconds,
config.DetectionGapMeters,
config.DetectionToleranceMeters,
null
);
});
@ -268,34 +271,62 @@ namespace NavisworksTransport.Core
}
// 提取碰撞结果
var collisions = frames.SelectMany(f => f.Collisions).ToList();
// 创建并运行ClashDetective测试直接在主线程执行避免异步切换导致的Navisworks Native对象生命周期问题
var testName = _executor._processor.CreateAndRunClashDetectiveTest(
collisions,
item.DetectionGapMeters,
pathRoute.Name,
pathRoute.Id,
animatedObject,
isVirtualVehicle,
item.FrameRate,
item.DurationSeconds,
item.VirtualVehicleLength,
item.VirtualVehicleWidth,
item.VirtualVehicleHeight
);
// 🔥 使用 ClashDetective 确认的碰撞数,而不是预计算的碰撞数
item.CollisionCount = ClashDetectiveIntegration.Instance.ClashDetectiveCollisionCount;
// 保存测试名称
item.ClashDetectiveTestName = testName;
var collisions = frames.SelectMany(f => f.Collisions).ToList();
// 创建并运行ClashDetective测试直接在主线程执行避免异步切换导致的Navisworks Native对象生命周期问题
// 传入 pathPoints 参数,让 ClashDetective 测试完成后自动恢复到路径起点
var pathPoints = pathRoute.Points.Select(p => p.Position).ToList();
var testName = _executor._processor.CreateAndRunClashDetectiveTest(
collisions,
item.DetectionToleranceMeters,
pathRoute.Name,
pathRoute.Id,
animatedObject,
isVirtualVehicle,
item.FrameRate,
item.DurationSeconds,
item.VirtualVehicleLength,
item.VirtualVehicleWidth,
item.VirtualVehicleHeight,
pathPoints
);
// 🔥 使用 ClashDetective 确认的碰撞数,而不是预计算的碰撞数
item.CollisionCount = ClashDetectiveIntegration.Instance.ClashDetectiveCollisionCount;
// 保存测试名称
item.ClashDetectiveTestName = testName;
// 标记为完成
item.Status = BatchQueueStatus.Completed;
item.EndTime = DateTime.Now;
await _database.UpdateBatchQueueItemAsync(item);
LogManager.Info($"[批处理队列] 队列项执行完成: {item.PathRouteName}, 碰撞数: {item.CollisionCount}");
}
catch (Exception ex)

View File

@ -232,7 +232,7 @@ namespace NavisworksTransport.Core
var systemConfig = ConfigManager.Instance.Current;
return new CollisionDetectionConfig
{
DetectionGapMeters = systemConfig.Animation.DetectionGapMeters,
DetectionToleranceMeters = systemConfig.Animation.DetectionToleranceMeters,
FrameRate = systemConfig.Animation.FrameRate,
DurationSeconds = systemConfig.Animation.DurationSeconds
};

View File

@ -7,6 +7,8 @@ using Autodesk.Navisworks.Api;
using NavisworksTransport.Core.Models;
using NavisworksTransport.Utils;
using NavisworksTransport.Core.Config;
using NavisworksTransport.Core.Animation;
using NavisworksTransport.Core;
namespace NavisworksTransport.Core.Collision
{
@ -148,12 +150,12 @@ namespace NavisworksTransport.Core.Collision
pathRoute,
animatedObject,
isVirtualVehicle,
config.DetectionGapMeters, // 虚拟车辆尺寸从配置获取
config.DetectionGapMeters,
config.DetectionGapMeters,
config.VirtualVehicleLength,
config.VirtualVehicleWidth,
config.VirtualVehicleHeight,
config.FrameRate,
config.DurationSeconds,
config.DetectionGapMeters,
config.DetectionToleranceMeters,
null // 暂不支持手动检测项
);
@ -165,9 +167,11 @@ namespace NavisworksTransport.Core.Collision
}
// 创建并运行ClashDetective测试纯计算无UI操作
// 传入 pathPoints 参数,让 ClashDetective 测试完成后自动恢复到路径起点
var pathPoints = pathRoute.Points.Select(p => p.Position).ToList();
var testName = _processor.CreateAndRunClashDetectiveTest(
allCollisions,
config.DetectionGapMeters,
config.DetectionToleranceMeters,
pathRoute.Name,
pathRoute.Id,
animatedObject,
@ -176,7 +180,8 @@ namespace NavisworksTransport.Core.Collision
config.DurationSeconds,
config.VirtualVehicleLength,
config.VirtualVehicleWidth,
config.VirtualVehicleHeight
config.VirtualVehicleHeight,
pathPoints
);
// 保存测试名称到任务项
@ -262,7 +267,7 @@ namespace NavisworksTransport.Core.Collision
var systemConfig = ConfigManager.Instance.Current;
return new CollisionDetectionConfig
{
DetectionGapMeters = systemConfig.Animation.DetectionGapMeters,
DetectionToleranceMeters = systemConfig.Animation.DetectionToleranceMeters,
FrameRate = systemConfig.Animation.FrameRate,
DurationSeconds = systemConfig.Animation.DurationSeconds,
VirtualVehicleLength = systemConfig.PathEditing.VehicleLengthMeters,

View File

@ -80,7 +80,8 @@ namespace NavisworksTransport.Core.Collision
double duration,
double virtualVehicleLength,
double virtualVehicleWidth,
double virtualVehicleHeight)
double virtualVehicleHeight,
List<Point3D> pathPoints = null)
{
try
{
@ -98,7 +99,8 @@ namespace NavisworksTransport.Core.Collision
duration,
virtualVehicleLength,
virtualVehicleWidth,
virtualVehicleHeight
virtualVehicleHeight,
pathPoints
);
LogManager.Info($"[批处理] ClashDetective测试创建完成 - 测试名称: {testName}");

View File

@ -4,6 +4,7 @@ using System.Linq;
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Clash;
using NavisworksTransport.Core;
using NavisworksTransport.Core.Animation;
using NavisworksTransport.Utils;
namespace NavisworksTransport
@ -755,6 +756,7 @@ namespace NavisworksTransport
/// <param name="virtualVehicleLength">虚拟车辆长度(米)</param>
/// <param name="virtualVehicleWidth">虚拟车辆宽度(米)</param>
/// <param name="virtualVehicleHeight">虚拟车辆高度(米)</param>
/// <param name="pathPoints">路径点列表(用于测试完成后恢复物体位置)</param>
public void CreateAllAnimationCollisionTests(
List<CollisionResult> precomputedCollisions,
double detectionGap,
@ -766,7 +768,8 @@ namespace NavisworksTransport
double duration,
double virtualVehicleLength,
double virtualVehicleWidth,
double virtualVehicleHeight)
double virtualVehicleHeight,
List<Point3D> pathPoints = null)
{
try
{
@ -795,24 +798,10 @@ namespace NavisworksTransport
_animationCollisionCount = collisionResults.Count;
LogManager.Info($"[预计算处理] 原始记录: {precomputedCollisions.Count},有效碰撞: {_animationCollisionCount}");
// 获取动画对象和当前动画终点位置(用于后续恢复)
Point3D animationEndPosition = new Point3D(0, 0, 0);
// 获取动画对象
if (collisionResults.Count > 0)
{
animatedObject = collisionResults[0].Item1;
// 记录当前位置(应该是动画终点)
if (animatedObject != null && IsModelItemValid(animatedObject))
{
var bounds = animatedObject.BoundingBox();
animationEndPosition = new Point3D(
(bounds.Min.X + bounds.Max.X) / 2,
(bounds.Min.Y + bounds.Max.Y) / 2,
(bounds.Min.Z + bounds.Max.Z) / 2
);
LogManager.Info($"记录动画终点位置: ({animationEndPosition.X:F2},{animationEndPosition.Y:F2},{animationEndPosition.Z:F2})");
}
}
var doc = Application.ActiveDocument;
@ -858,35 +847,17 @@ namespace NavisworksTransport
LogManager.Warning("[分组测试] 分组为空(未检测到真实几何碰撞),未添加到主测试");
}
// 碰撞测试完成后,将物体恢复到动画终点位置
if (animatedObject != null && IsModelItemValid(animatedObject))
// 碰撞测试完成后,将物体恢复到路径起点位置(如果提供了路径点)
if (animatedObject != null && IsModelItemValid(animatedObject) && pathPoints != null && pathPoints.Count > 0)
{
try
{
var modelItems = new ModelItemCollection { animatedObject };
// 计算当前位置到动画终点的偏移
var currentBounds = animatedObject.BoundingBox();
var currentPos = new Point3D(
(currentBounds.Min.X + currentBounds.Max.X) / 2,
(currentBounds.Min.Y + currentBounds.Max.Y) / 2,
(currentBounds.Min.Z + currentBounds.Max.Z) / 2
);
var restoreOffset = new Vector3D(
animationEndPosition.X - currentPos.X,
animationEndPosition.Y - currentPos.Y,
animationEndPosition.Z - currentPos.Z
);
var restoreTransform = Transform3D.CreateTranslation(restoreOffset);
doc.Models.OverridePermanentTransform(modelItems, restoreTransform, false);
LogManager.Info($"已将 {animatedObject.DisplayName} 恢复到动画终点位置: ({animationEndPosition.X:F2},{animationEndPosition.Y:F2},{animationEndPosition.Z:F2})");
PathAnimationManager.GetInstance().MoveVehicleToPathStart(animatedObject, pathPoints);
LogManager.Info($"已将 {animatedObject.DisplayName} 恢复到路径起点位置");
}
catch (Exception restoreEx)
{
LogManager.Error($"恢复物体到动画终点失败: {restoreEx.Message}");
LogManager.Error($"恢复物体到路径起点失败: {restoreEx.Message}");
}
}
@ -1555,7 +1526,8 @@ namespace NavisworksTransport
double duration,
double virtualVehicleLength,
double virtualVehicleWidth,
double virtualVehicleHeight)
double virtualVehicleHeight,
List<Point3D> pathPoints = null)
{
try
{
@ -1615,6 +1587,20 @@ namespace NavisworksTransport
LogManager.Warning("[批处理] 分组为空(未检测到真实几何碰撞),未添加到主测试");
}
// 碰撞测试完成后,将物体恢复到路径起点位置(如果提供了路径点)
if (animatedObject != null && IsModelItemValid(animatedObject) && pathPoints != null && pathPoints.Count > 0)
{
try
{
PathAnimationManager.GetInstance().MoveVehicleToPathStart(animatedObject, pathPoints);
LogManager.Info($"[批处理] 已将 {animatedObject.DisplayName} 恢复到路径起点位置");
}
catch (Exception restoreEx)
{
LogManager.Error($"[批处理] 恢复物体到路径起点失败: {restoreEx.Message}");
}
}
return addedMainTest?.DisplayName;
}
catch (Exception ex)

View File

@ -53,6 +53,7 @@ namespace NavisworksTransport.Core.Collision
/// <param name="virtualVehicleLength">虚拟车辆长度(米)</param>
/// <param name="virtualVehicleWidth">虚拟车辆宽度(米)</param>
/// <param name="virtualVehicleHeight">虚拟车辆高度(米)</param>
/// <param name="pathPoints">路径点列表(用于测试完成后恢复物体位置)</param>
/// <returns>ClashDetective测试名称</returns>
string CreateAndRunClashDetectiveTest(
List<CollisionResult> precomputedCollisions,
@ -65,6 +66,7 @@ namespace NavisworksTransport.Core.Collision
double duration,
double virtualVehicleLength,
double virtualVehicleWidth,
double virtualVehicleHeight);
double virtualVehicleHeight,
List<Point3D> pathPoints = null);
}
}

View File

@ -166,8 +166,8 @@ namespace NavisworksTransport.Core.Config
config.PathEditing.VehicleWidthMeters = GetRequiredDoubleValue(pathEdit, "vehicle_width_meters");
config.PathEditing.VehicleHeightMeters = GetRequiredDoubleValue(pathEdit, "vehicle_height_meters");
config.PathEditing.SafetyMarginMeters = GetRequiredDoubleValue(pathEdit, "safety_margin_meters");
config.PathEditing.DefaultPathTurnRadius = GetRequiredDoubleValue(pathEdit, "default_path_turn_radius");
config.PathEditing.ArcSamplingStep = GetRequiredDoubleValue(pathEdit, "arc_sampling_step");
config.PathEditing.DefaultPathTurnRadiusMeters = GetRequiredDoubleValue(pathEdit, "default_path_turn_radius");
config.PathEditing.ArcSamplingStepMeters = GetRequiredDoubleValue(pathEdit, "arc_sampling_step");
// 加载可视化配置
if (!model.ContainsKey("visualization"))
@ -197,8 +197,8 @@ namespace NavisworksTransport.Core.Config
config.Animation.FrameRate = GetRequiredIntValue(anim, "frame_rate");
config.Animation.DurationSeconds = GetRequiredDoubleValue(anim, "duration_seconds");
config.Animation.DetectionGapMeters = GetRequiredDoubleValue(anim, "detection_gap_meters");
config.Animation.SpatialIndexCellSize = GetRequiredDoubleValue(anim, "spatial_index_cell_size");
config.Animation.DetectionToleranceMeters = GetRequiredDoubleValue(anim, "detection_tolerance_meters");
config.Animation.SpatialIndexCellSizeMeters = GetRequiredDoubleValue(anim, "spatial_index_cell_size");
// 加载物流属性配置
if (!model.ContainsKey("logistics"))
@ -321,8 +321,8 @@ namespace NavisworksTransport.Core.Config
pathEdit["vehicle_width_meters"] = config.PathEditing.VehicleWidthMeters;
pathEdit["vehicle_height_meters"] = config.PathEditing.VehicleHeightMeters;
pathEdit["safety_margin_meters"] = config.PathEditing.SafetyMarginMeters;
pathEdit["default_path_turn_radius"] = config.PathEditing.DefaultPathTurnRadius;
pathEdit["arc_sampling_step"] = config.PathEditing.ArcSamplingStep;
pathEdit["default_path_turn_radius"] = config.PathEditing.DefaultPathTurnRadiusMeters;
pathEdit["arc_sampling_step"] = config.PathEditing.ArcSamplingStepMeters;
}
}
@ -344,8 +344,8 @@ namespace NavisworksTransport.Core.Config
{
anim["frame_rate"] = config.Animation.FrameRate;
anim["duration_seconds"] = config.Animation.DurationSeconds;
anim["detection_gap_meters"] = config.Animation.DetectionGapMeters;
anim["spatial_index_cell_size"] = config.Animation.SpatialIndexCellSize;
anim["detection_tolerance_meters"] = config.Animation.DetectionToleranceMeters;
anim["spatial_index_cell_size"] = config.Animation.SpatialIndexCellSizeMeters;
}
}

View File

@ -89,12 +89,54 @@ namespace NavisworksTransport.Core.Config
/// <summary>
/// 路径默认转弯半径(米)
/// </summary>
public double DefaultPathTurnRadius { get; set; }
public double DefaultPathTurnRadiusMeters { get; set; }
/// <summary>
/// 圆弧采样步长(米)
/// </summary>
public double ArcSamplingStep { get; set; }
public double ArcSamplingStepMeters { get; set; }
// === 模型单位接口(用于内部计算) ===
/// <summary>
/// 网格单元大小(模型单位)
/// </summary>
public double CellSize => CellSizeMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 最大高度差(模型单位)
/// </summary>
public double MaxHeightDiff => MaxHeightDiffMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 车辆长度(模型单位)
/// </summary>
public double VehicleLength => VehicleLengthMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 车辆宽度(模型单位)
/// </summary>
public double VehicleWidth => VehicleWidthMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 车辆高度(模型单位)
/// </summary>
public double VehicleHeight => VehicleHeightMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 安全间隙(模型单位)
/// </summary>
public double SafetyMargin => SafetyMarginMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 路径默认转弯半径(模型单位)
/// </summary>
public double DefaultPathTurnRadius => DefaultPathTurnRadiusMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 圆弧采样步长(模型单位)
/// </summary>
public double ArcSamplingStep => ArcSamplingStepMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
}
/// <summary>
@ -124,14 +166,26 @@ namespace NavisworksTransport.Core.Config
public double DurationSeconds { get; set; }
/// <summary>
/// 检测间隙(米)
/// 检测容差(米)- 用于ClashDetective精确检测
/// </summary>
public double DetectionGapMeters { get; set; }
public double DetectionToleranceMeters { get; set; }
/// <summary>
/// 空间索引格子大小(米)- 用于动画碰撞检测的空间索引
/// </summary>
public double SpatialIndexCellSize { get; set; }
public double SpatialIndexCellSizeMeters { get; set; }
// === 模型单位接口(用于内部计算) ===
/// <summary>
/// 检测容差(模型单位)- 用于ClashDetective精确检测
/// </summary>
public double DetectionTolerance => DetectionToleranceMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 空间索引格子大小(模型单位)- 用于动画碰撞检测的空间索引
/// </summary>
public double SpatialIndexCellSize => SpatialIndexCellSizeMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
}
/// <summary>
@ -163,5 +217,22 @@ namespace NavisworksTransport.Core.Config
/// 宽度限制(米)
/// </summary>
public double WidthLimitMeters { get; set; }
// === 模型单位接口(用于内部计算) ===
/// <summary>
/// 高度限制(模型单位)
/// </summary>
public double HeightLimit => HeightLimitMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 速度限制(模型单位/秒)
/// </summary>
public double SpeedLimit => SpeedLimitMetersPerSecond * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
/// <summary>
/// 宽度限制(模型单位)
/// </summary>
public double WidthLimit => WidthLimitMeters * Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
}
}

View File

@ -22,7 +22,7 @@ namespace NavisworksTransport.Core.Models
public double DurationSeconds { get; set; }
// 碰撞检测配置
public double DetectionGapMeters { get; set; }
public double DetectionToleranceMeters { get; set; }
// 运动物体配置
public bool IsVirtualVehicle { get; set; }

View File

@ -5,23 +5,23 @@ namespace NavisworksTransport.Core.Models
/// </summary>
public class CollisionDetectionConfig
{
public double DetectionGapMeters { get; set; } = 0.05;
public int FrameRate { get; set; } = 30;
public double DurationSeconds { get; set; } = 10.0;
public bool CollisionDetectionEnabled { get; set; } = true;
public bool ReportGenerationEnabled { get; set; } = true;
public double DetectionToleranceMeters { get; set; }
public int FrameRate { get; set; }
public double DurationSeconds { get; set; }
public bool CollisionDetectionEnabled { get; set; }
public bool ReportGenerationEnabled { get; set; }
// 虚拟车辆参数
public double VirtualVehicleLength { get; set; } = 1.0;
public double VirtualVehicleWidth { get; set; } = 1.0;
public double VirtualVehicleHeight { get; set; } = 2.0;
public double VirtualVehicleLength { get; set; }
public double VirtualVehicleWidth { get; set; }
public double VirtualVehicleHeight { get; set; }
/// <summary>
/// 序列化为JSON字符串简化版
/// </summary>
public string ToJson()
{
return $"{{\"DetectionGapMeters\":{DetectionGapMeters},\"FrameRate\":{FrameRate},\"DurationSeconds\":{DurationSeconds},\"CollisionDetectionEnabled\":{CollisionDetectionEnabled.ToString().ToLower()},\"ReportGenerationEnabled\":{ReportGenerationEnabled.ToString().ToLower()}}}";
return $"{{\"DetectionToleranceMeters\":{DetectionToleranceMeters},\"FrameRate\":{FrameRate},\"DurationSeconds\":{DurationSeconds},\"CollisionDetectionEnabled\":{CollisionDetectionEnabled.ToString().ToLower()},\"ReportGenerationEnabled\":{ReportGenerationEnabled.ToString().ToLower()}}}";
}
/// <summary>
@ -48,9 +48,9 @@ namespace NavisworksTransport.Core.Models
switch (key)
{
case "DetectionGapMeters":
if (double.TryParse(value, out var detectionGap))
config.DetectionGapMeters = detectionGap;
case "DetectionToleranceMeters":
if (double.TryParse(value, out var detectionTolerance))
config.DetectionToleranceMeters = detectionTolerance;
break;
case "FrameRate":
if (int.TryParse(value, out var frameRate))
@ -88,11 +88,11 @@ namespace NavisworksTransport.Core.Models
if (overrideConfig == null) return this;
return new CollisionDetectionConfig
{
DetectionGapMeters = overrideConfig.DetectionGapMeters > 0
? overrideConfig.DetectionGapMeters : DetectionGapMeters,
FrameRate = overrideConfig.FrameRate > 0
DetectionToleranceMeters = overrideConfig.DetectionToleranceMeters > 0
? overrideConfig.DetectionToleranceMeters : DetectionToleranceMeters,
FrameRate = overrideConfig.FrameRate > 0
? overrideConfig.FrameRate : FrameRate,
DurationSeconds = overrideConfig.DurationSeconds > 0
DurationSeconds = overrideConfig.DurationSeconds > 0
? overrideConfig.DurationSeconds : DurationSeconds,
CollisionDetectionEnabled = overrideConfig.CollisionDetectionEnabled,
ReportGenerationEnabled = overrideConfig.ReportGenerationEnabled

View File

@ -225,7 +225,7 @@ namespace NavisworksTransport
ErrorMessage TEXT,
FrameRate INTEGER NOT NULL,
DurationSeconds REAL NOT NULL,
DetectionGapMeters REAL NOT NULL,
DetectionToleranceMeters REAL NOT NULL,
IsVirtualVehicle INTEGER NOT NULL,
VirtualVehicleLength REAL,
VirtualVehicleWidth REAL,
@ -1598,14 +1598,14 @@ namespace NavisworksTransport
cmd.CommandText = @"
INSERT INTO BatchQueueItems (
PathRouteId, PathRouteName, Status, CreatedTime, StartTime, EndTime, ErrorMessage,
FrameRate, DurationSeconds, DetectionGapMeters,
FrameRate, DurationSeconds, DetectionToleranceMeters,
IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight,
VehicleObjectId, VehicleObjectName, DetectionItems, DetectAllObjects,
ClashDetectiveTestName, CollisionCount
)
VALUES (
@PathRouteId, @PathRouteName, @Status, @CreatedTime, @StartTime, @EndTime, @ErrorMessage,
@FrameRate, @DurationSeconds, @DetectionGapMeters,
@FrameRate, @DurationSeconds, @DetectionToleranceMeters,
@IsVirtualVehicle, @VirtualVehicleLength, @VirtualVehicleWidth, @VirtualVehicleHeight,
@VehicleObjectId, @VehicleObjectName, @DetectionItems, @DetectAllObjects,
@ClashDetectiveTestName, @CollisionCount
@ -1621,7 +1621,7 @@ namespace NavisworksTransport
cmd.Parameters.AddWithValue("@ErrorMessage", item.ErrorMessage ?? "");
cmd.Parameters.AddWithValue("@FrameRate", item.FrameRate);
cmd.Parameters.AddWithValue("@DurationSeconds", item.DurationSeconds);
cmd.Parameters.AddWithValue("@DetectionGapMeters", item.DetectionGapMeters);
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);
@ -1649,7 +1649,7 @@ namespace NavisworksTransport
{
cmd.CommandText = @"
SELECT Id, PathRouteId, PathRouteName, Status, CreatedTime, StartTime, EndTime, ErrorMessage,
FrameRate, DurationSeconds, DetectionGapMeters,
FrameRate, DurationSeconds, DetectionToleranceMeters,
IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight,
VehicleObjectId, VehicleObjectName, DetectionItems, DetectAllObjects,
ClashDetectiveTestName, CollisionCount
@ -1674,7 +1674,7 @@ namespace NavisworksTransport
ErrorMessage = reader["ErrorMessage"].ToString(),
FrameRate = Convert.ToInt32(reader["FrameRate"]),
DurationSeconds = Convert.ToDouble(reader["DurationSeconds"]),
DetectionGapMeters = Convert.ToDouble(reader["DetectionGapMeters"]),
DetectionToleranceMeters = Convert.ToDouble(reader["DetectionToleranceMeters"]),
IsVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]),
VirtualVehicleLength = Convert.ToDouble(reader["VirtualVehicleLength"]),
VirtualVehicleWidth = Convert.ToDouble(reader["VirtualVehicleWidth"]),
@ -1705,7 +1705,7 @@ namespace NavisworksTransport
{
var sql = @"
SELECT Id, PathRouteId, PathRouteName, Status, CreatedTime, StartTime, EndTime, ErrorMessage,
FrameRate, DurationSeconds, DetectionGapMeters,
FrameRate, DurationSeconds, DetectionToleranceMeters,
IsVirtualVehicle, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight,
VehicleObjectId, VehicleObjectName, DetectionItems, DetectAllObjects,
ClashDetectiveTestName, CollisionCount
@ -1755,7 +1755,7 @@ namespace NavisworksTransport
ErrorMessage = reader["ErrorMessage"].ToString(),
FrameRate = Convert.ToInt32(reader["FrameRate"]),
DurationSeconds = Convert.ToDouble(reader["DurationSeconds"]),
DetectionGapMeters = Convert.ToDouble(reader["DetectionGapMeters"]),
DetectionToleranceMeters = Convert.ToDouble(reader["DetectionToleranceMeters"]),
IsVirtualVehicle = Convert.ToBoolean(reader["IsVirtualVehicle"]),
VirtualVehicleLength = Convert.ToDouble(reader["VirtualVehicleLength"]),
VirtualVehicleWidth = Convert.ToDouble(reader["VirtualVehicleWidth"]),

View File

@ -218,9 +218,10 @@ namespace NavisworksTransport.Core
}
/// <summary>
/// 重置虚拟车辆变换为单位矩阵
/// <summary>
/// 重置虚拟车辆变换为单位矩阵(公开方法,供批处理使用)
/// </summary>
private void ResetVirtualVehicleTransform()
public void ResetVirtualVehicleTransform()
{
if (_virtualVehicleModel == null) return;

View File

@ -30,7 +30,7 @@ namespace NavisworksTransport.UI.WPF.Converters
return "未知";
}
}
return "待处理";
return "全部";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

View File

@ -215,7 +215,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private CollisionReportResult _lastGeneratedReport; // 缓存最后生成的报告
// 碰撞检测参数字段(从配置初始化)
private double _detectionGap; // 检测间隙(米)
private double _detectionTolerance; // 检测容差(米)
private int _animationFrameRate; // 动画帧率(FPS)
@ -236,12 +236,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private double _safetyMargin; // 检测间隙(米),从路径编辑同步
// 角度修正相关字段
private double _objectRotationCorrection = 0.0; // 物体角度修正值(度,顺时针)
private double _objectRotationCorrection; // 物体角度修正值(度,顺时针)
// 移动物体原始尺寸(米,在选择物体时保存)
private double _objectOriginalLength = 0.0; // 物体原始长度X方向
private double _objectOriginalWidth = 0.0; // 物体原始宽度Y方向
private double _objectOriginalHeight = 0.0; // 物体原始高度Z方向
private double _objectOriginalLength; // 物体原始长度X方向
private double _objectOriginalWidth; // 物体原始宽度Y方向
private double _objectOriginalHeight; // 物体原始高度Z方向
// 手工碰撞对象相关字段
private bool _isManualCollisionTargetEnabled = false;
@ -411,20 +411,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
/// <summary>
/// 检测间隙(米)
/// </summary>
public double DetectionGap
{
get => _detectionGap;
set
{
// 限制精度到2位小数
var roundedValue = Math.Round(value, 2);
SetProperty(ref _detectionGap, roundedValue);
}
}
/// <summary>
/// 动画帧率(FPS)
/// </summary>
@ -546,18 +532,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
LogManager.Info("已切换到虚拟车辆模式,将之前的手动选择物体归位并清理动画数据");
}
// 显示虚拟车辆,并同步到起点
LogManager.Info("正在显示虚拟车辆到起点...");
// 显示虚拟车辆
LogManager.Info("正在显示虚拟车辆...");
VirtualVehicleManager.Instance.ShowVirtualVehicle(
VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight);
var vModel = VirtualVehicleManager.Instance.CurrentVirtualVehicle;
if (vModel != null && CurrentPathRoute != null && CurrentPathRoute.Points != null)
{
var points = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList();
_pathAnimationManager?.MoveVehicleToPathStart(vModel, points);
}
// 重置角度修正值(虚拟车辆重新选择时重置)
ObjectRotationCorrection = 0.0;
LogManager.Debug($"[切换虚拟车辆] 已重置角度修正值为0度");
@ -620,15 +599,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private set => SetProperty(ref _virtualVehicleHeight, value);
}
/// <summary>
/// 检测间隙(米)- 只读,从路径编辑同步
/// </summary>
public double SafetyMargin
{
get => _safetyMargin;
private set => SetProperty(ref _safetyMargin, value);
}
/// <summary>
/// 物体角度修正值(度,顺时针)
/// </summary>
@ -647,16 +617,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// <summary>
/// 设置虚拟车辆参数由主ViewModel调用
/// 参数单位:模型单位
/// 参数单位:
/// </summary>
public void SetVirtualVehicleParameters(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;
SafetyMargin = safetyMargin;
_safetyMargin = safetyMargin;
LogManager.Info($"[AnimationControlViewModel] 虚拟车辆参数已更新: {length:F1}模型单位 × {width:F1}模型单位 × {height:F1}模型单位, 检测间隙: {safetyMargin:F2}模型单位");
LogManager.Info($"[AnimationControlViewModel] 虚拟车辆参数已更新: {length:F1}× {width:F1}米 × {height:F1}米, 检测间隙: {safetyMargin:F2}米, _safetyMargin={_safetyMargin:F4}");
// 如果当前使用虚拟车辆模式,更新生成动画的可用状态
if (UseVirtualVehicle)
@ -935,22 +906,22 @@ namespace NavisworksTransport.UI.WPF.ViewModels
HasClashDetectiveResults = false;
UpdateMainStatus("碰撞检测就绪");
// 获取单位转换系数
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
// 从配置读取碰撞检测参数(转换为模型单位)
DetectionGap = config.Animation.DetectionGapMeters * metersToModelUnits;
AnimationFrameRate = config.Animation.FrameRate;
// 🔥 从配置加载虚拟车辆尺寸(与路径编辑保持一致,转换为模型单位
VirtualVehicleLength = config.PathEditing.VehicleLengthMeters * metersToModelUnits;
VirtualVehicleWidth = config.PathEditing.VehicleWidthMeters * metersToModelUnits;
VirtualVehicleHeight = config.PathEditing.VehicleHeightMeters * metersToModelUnits;
// 设置动画按钮的初始状态
UpdateAnimationButtonStates();
LogManager.Info($"动画设置初始化完成 - 帧率:{SelectedFrameRate}fps, 持续时间:{AnimationDuration}秒, 检测间隙:{DetectionGap}模型单位"); }
// 从配置读取安全间隙(用于预计算)- 使用米单位接口
_safetyMargin = config.PathEditing.SafetyMarginMeters;
AnimationFrameRate = config.Animation.FrameRate;
// 从配置读取检测容差用于ClashDetective- 使用米单位接口用于显示
_detectionTolerance = config.Animation.DetectionToleranceMeters;
// 🔥 从配置加载虚拟车辆尺寸(与路径编辑保持一致,使用米单位接口
VirtualVehicleLength = config.PathEditing.VehicleLengthMeters;
VirtualVehicleWidth = config.PathEditing.VehicleWidthMeters;
VirtualVehicleHeight = config.PathEditing.VehicleHeightMeters;
// 设置动画按钮的初始状态
UpdateAnimationButtonStates();
LogManager.Info($"动画设置初始化完成 - 帧率:{SelectedFrameRate}fps, 持续时间:{AnimationDuration}秒, 安全间隙:{_safetyMargin}米"); }
/// <summary>
/// 初始化命令
@ -1378,13 +1349,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
LogManager.Debug($"[选择物体] 保持当前角度修正值(同一物体)");
}
// 3. 立即移动到起点(如果路径存在)
if (CurrentPathRoute != null && CurrentPathRoute.Points != null && _pathAnimationManager != null)
{
var points = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList();
_pathAnimationManager.MoveVehicleToPathStart(newObject, points);
}
}
catch (Exception ex)
{
@ -1747,7 +1711,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
reportResult.UniqueCollidedObjectsCount,
reportResult.FrameRate,
reportResult.Duration,
reportResult.DetectionGap,
reportResult.DetectionTolerance,
reportResult.AnimationCollisions,
reportResult.TotalCollisions
);
@ -2453,6 +2417,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
if (!UseVirtualVehicle)
{
UpdateMainStatus("正在分析动画对象...", -1, true);
// 🔥 设置检测容差安全间隙通过CreateAnimation传入
_pathAnimationManager.SetDetectionTolerance(_detectionTolerance);
var success = _pathAnimationManager.PrecomputeCollisionExclusions(SelectedAnimatedObject);
if (!success)
@ -2483,7 +2451,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
_pathAnimationManager.SetAnimationFrameRate(_animationFrameRate);
_pathAnimationManager.SetCollisionDetectionAccuracy(CollisionDetectionAccuracy);
_pathAnimationManager.SetMovementSpeed(MovementSpeed);
_pathAnimationManager.SetDetectionGap(_detectionGap);
_pathAnimationManager.SetDetectionTolerance(_detectionTolerance);
// 将PathRouteViewModel的点转换为Point3D列表
var pathPoints = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList();
@ -2558,15 +2526,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 先设置路径到动画管理器
_pathAnimationManager.SetRoute(pathRoute);
// 准备车辆尺寸参数
double vLength = UseVirtualVehicle ? VirtualVehicleLength : 0;
double vWidth = UseVirtualVehicle ? VirtualVehicleWidth : 0;
double vHeight = UseVirtualVehicle ? VirtualVehicleHeight : 0;
// 准备车辆尺寸参数(从米转换为模型单位)
var metersToModelUnits = Utils.UnitsConverter.GetMetersToUnitsConversionFactor();
double vLength = UseVirtualVehicle ? VirtualVehicleLength * metersToModelUnits : 0;
double vWidth = UseVirtualVehicle ? VirtualVehicleWidth * metersToModelUnits : 0;
double vHeight = UseVirtualVehicle ? VirtualVehicleHeight * metersToModelUnits : 0;
double safetyMargin = _safetyMargin * metersToModelUnits;
LogManager.Info($"[ExecuteGenerateAnimation] 准备调用CreateAnimation: UseVirtualVehicle={UseVirtualVehicle}, 车辆尺寸: {vLength:F2}×{vWidth:F2}×{vHeight:F2}m");
LogManager.Info($"[ExecuteGenerateAnimation] 准备调用CreateAnimation: UseVirtualVehicle={UseVirtualVehicle}, 车辆尺寸: {vLength:F2}×{vWidth:F2}×{vHeight:F2}模型单位, 安全间隙: {safetyMargin:F4}模型单位 (_safetyMargin={_safetyMargin:F4}米)");
_pathAnimationManager.CreateAnimation(animatedObject, pathPoints, AnimationDuration, CurrentPathRoute.Name, CurrentPathRoute.Id, UseVirtualVehicle,
vLength, vWidth, vHeight);
vLength, vWidth, vHeight, safetyMargin);
var totalElapsed = (DateTime.Now - cacheStartTime).TotalMilliseconds;
LogManager.Info($"[动画生成] 动画生成完成,总耗时: {totalElapsed:F1}ms");
@ -2692,7 +2662,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
double passageNormalToPathVertical, passageNormalToPathHorizontal;
// 使用从路径编辑同步过来的检测间隙
double safetyMargin = SafetyMargin;
double safetyMargin = _safetyMargin;
if (UseVirtualVehicle)
{
@ -3505,10 +3475,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 动画配置
FrameRate = _animationFrameRate,
DurationSeconds = AnimationDuration,
// 碰撞检测配置
DetectionGapMeters = _detectionGap,
DetectionToleranceMeters = _detectionTolerance,
// 运动物体配置
IsVirtualVehicle = UseVirtualVehicle,
VirtualVehicleLength = VirtualVehicleLength,

View File

@ -169,12 +169,19 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 订阅队列管理器事件
if (_queueManager != null)
{
_queueManager.ItemAdded += OnItemAdded;
_queueManager.ItemStarted += OnItemStarted;
_queueManager.ItemCompleted += OnItemCompleted;
_queueManager.ItemProgress += OnItemProgress;
}
// 加载队列列表
// 订阅路径规划管理器事件(用于在数据库初始化后重新加载队列列表)
if (_pathPlanningManager != null)
{
_pathPlanningManager.RoutesLoaded += OnRoutesLoaded;
}
// 尝试加载队列列表(如果数据库已初始化)
_ = LoadQueueItemsAsync();
LogManager.Info("[BatchQueueManagement] PathPlanningManager已设置");
@ -203,7 +210,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
var database = GetDatabase();
if (database == null)
{
LogManager.Warning("[BatchQueueManagement] Database未初始化");
return;
}
@ -218,6 +224,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 按创建时间倒序
items = items.OrderByDescending(item => item.CreatedTime).ToList();
LogManager.Info($"[BatchQueueManagement] 加载队列列表完成,共 {items.Count} 项");
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
QueueItems.Clear();
@ -343,6 +351,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#region
private async void OnRoutesLoaded(object sender, RoutesLoadedEventArgs e)
{
// 数据库初始化完成,重新加载队列列表
await _uiStateManager.ExecuteUIUpdateAsync(async () =>
{
await LoadQueueItemsAsync();
});
}
private async void OnItemAdded(object sender, BatchQueueItemEventArgs e)
{
// 自动刷新列表
await _uiStateManager.ExecuteUIUpdateAsync(async () =>
{
await LoadQueueItemsAsync();
});
}
private async void OnItemStarted(object sender, BatchQueueItemEventArgs e)
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>

View File

@ -81,7 +81,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private string _pathName;
private int _frameRate;
private double _duration;
private double _detectionGap;
private double _detectionTolerance;
private CollisionReportResult _currentReport;
#endregion
@ -234,12 +234,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
/// <summary>
/// 检测间隙
/// 检测容差
/// </summary>
public double DetectionGap
public double DetectionTolerance
{
get => _detectionGap;
set => SetProperty(ref _detectionGap, value);
get => _detectionTolerance;
set => SetProperty(ref _detectionTolerance, value);
}
/// <summary>
@ -378,7 +378,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
PathName = reportResult.PathName;
FrameRate = reportResult.FrameRate;
Duration = reportResult.Duration;
DetectionGap = reportResult.DetectionGap;
DetectionTolerance = reportResult.DetectionTolerance;
// 更新统计信息
UpdateStatistics(reportResult);
@ -680,7 +680,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
report.AppendLine("=== 动画参数 ===");
report.AppendLine($"帧率: {FrameRate} FPS");
report.AppendLine($"时长: {Duration:F1} 秒");
report.AppendLine($"检测间隙: {DetectionGap:F2} 米");
report.AppendLine($"检测容差: {DetectionTolerance:F2} 米");
report.AppendLine();
// 运动构件信息
@ -826,8 +826,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
html.AppendLine($"<div class='stat-value'>{Duration:F1} 秒</div>");
html.AppendLine("</div>");
html.AppendLine("<div class='stat-item'>");
html.AppendLine("<div class='stat-label'>检测间隙</div>");
html.AppendLine($"<div class='stat-value'>{DetectionGap:F2} 米</div>");
html.AppendLine("<div class='stat-label'>检测容差</div>");
html.AppendLine($"<div class='stat-value'>{DetectionTolerance:F2} 米</div>");
html.AppendLine("</div>");
html.AppendLine("</div>");

View File

@ -788,17 +788,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
var config = ConfigManager.Instance.Current;
// 获取单位转换系数
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
// 从 PathEditing 配置加载所有参数(使用米单位接口)
_gridSize = config.PathEditing.CellSizeMeters;
_vehicleLength = config.PathEditing.VehicleLengthMeters;
_vehicleWidth = config.PathEditing.VehicleWidthMeters;
_vehicleHeight = config.PathEditing.VehicleHeightMeters;
_safetyMargin = config.PathEditing.SafetyMarginMeters;
// 从 PathEditing 配置加载所有参数(转换为模型单位)
_gridSize = config.PathEditing.CellSizeMeters * metersToModelUnits;
_vehicleLength = config.PathEditing.VehicleLengthMeters * metersToModelUnits;
_vehicleWidth = config.PathEditing.VehicleWidthMeters * metersToModelUnits;
_vehicleHeight = config.PathEditing.VehicleHeightMeters * metersToModelUnits;
_safetyMargin = config.PathEditing.SafetyMarginMeters * metersToModelUnits;
LogManager.Info($"从配置加载参数 - 车辆: {_vehicleLength:F1}x{_vehicleWidth:F1}x{_vehicleHeight:F1}模型单位, 安全间隙: {_safetyMargin:F2}模型单位, 网格: {_gridSize:F1}模型单位");
LogManager.Info($"从配置加载参数 - 车辆: {_vehicleLength:F1}x{_vehicleWidth:F1}x{_vehicleHeight:F1}米, 安全间隙: {_safetyMargin:F2}米, 网格: {_gridSize:F1}米");
}
catch (Exception ex)
{

View File

@ -91,9 +91,9 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 检测间隙 -->
<!-- 检测容差 -->
<StackPanel Grid.Row="0">
<Label Content="检测间隙(米)"
<Label Content="检测容差(米)"
Style="{StaticResource ParameterLabelStyle}"
HorizontalAlignment="Center"/>
<Grid>

View File

@ -64,7 +64,7 @@ namespace NavisworksTransport.UI.WPF.Views
{
FrameRate = int.Parse(txtFrameRate.Text),
DurationSeconds = double.Parse(txtDuration.Text),
DetectionGapMeters = double.Parse(txtDetectionGap.Text)
DetectionToleranceMeters = double.Parse(txtDetectionGap.Text)
};
}
@ -83,7 +83,7 @@ namespace NavisworksTransport.UI.WPF.Views
txtVehicleHeight.Text = config.VirtualVehicleHeight.ToString("F2");
txtFrameRate.Text = config.FrameRate.ToString();
txtDuration.Text = config.DurationSeconds.ToString("F2");
txtDetectionGap.Text = config.DetectionGapMeters.ToString("F2");
txtDetectionGap.Text = config.DetectionToleranceMeters.ToString("F2");
}
/// <summary>

View File

@ -15,9 +15,9 @@ namespace NavisworksTransport
private double _mapWidth;
private double _mapHeight;
private double _defaultElevation;
private double _zoomFactor = 1.0;
private double _offsetX = 0.0;
private double _offsetY = 0.0;
private double _zoomFactor;
private double _offsetX;
private double _offsetY;
/// <summary>
/// 获取地图边距比例(从配置读取)