优化ClashDetective集成,减少临时测试创建和删除的性能开销,简化碰撞结果的DisplayName设置

This commit is contained in:
tian 2026-01-30 12:41:15 +08:00
parent 9fac32741e
commit cdd6ee9319
2 changed files with 96 additions and 63 deletions

View File

@ -483,7 +483,7 @@ namespace NavisworksTransport.Core.Animation
_currentYaw = ModelItemTransformHelper.GetYawFromTransform(_originalTransform);
LogManager.Debug($"[MoveVehicleToPathStart初始化] 当前实际yaw={_currentYaw * 180 / Math.PI:F2}度, _isVirtualVehicle={_isVirtualVehicle}");
}
if (pathPoints != null)
{
_pathPoints = pathPoints;
@ -499,7 +499,7 @@ namespace NavisworksTransport.Core.Animation
// 计算朝向(使用前两个路径点的方向)
double pathDirectionYaw = Math.Atan2(_pathPoints[1].Y - _pathPoints[0].Y, _pathPoints[1].X - _pathPoints[0].X);
double yaw;
LogManager.Info($"[移动到起点] 路径方向yaw: {pathDirectionYaw * 180 / Math.PI:F2}度, 角度修正: {_objectRotationCorrection:F1}度");
// 根据路径类型调整朝向
@ -564,7 +564,7 @@ namespace NavisworksTransport.Core.Animation
}
LogManager.Info($"物体已初始化到路径起点并对齐朝向: pos=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2}), yaw={yaw:F3}rad, 路径类型={pathTypeName}");
// 打印实际物体的位置和方向
if (_animatedObject != null)
{
@ -719,10 +719,10 @@ namespace NavisworksTransport.Core.Animation
if (!manualOverrideActive)
{
LogManager.Info("=== 构建全局空间索引 ===");
// 🔥 设置移动物体到 ClashDetectiveIntegration以便从空间索引中排除
ClashDetectiveIntegration.SetAnimatedObject(_animatedObject);
spatialIndexManager = SpatialIndexManager.Instance;
// 使用动画专用的空间索引格子大小配置 - 使用模型单位接口
@ -731,9 +731,9 @@ namespace NavisworksTransport.Core.Animation
LogManager.Info($"[空间索引] 格子大小: {cellSizeInModelUnits:F2}模型单位 (动画配置)");
// 检查空间索引是否需要重新构建(格子大小变化或未初始化)
bool needRebuild = !spatialIndexManager.IsInitialized ||
bool needRebuild = !spatialIndexManager.IsInitialized ||
Math.Abs(spatialIndexManager.CellSize - cellSizeInModelUnits) > 0.0001;
if (needRebuild)
{
LogManager.Info("[空间索引] 空间索引未初始化或格子大小已改变,开始重新构建...");
@ -767,15 +767,15 @@ namespace NavisworksTransport.Core.Animation
double yawRadians;
if (isAerialPath)
{
// === 空中路径:在路径点之间进行线性插值 ===
int segmentIndex = FindSegmentForDistance(targetDistance, segmentLengths);
if (segmentIndex < 0 || segmentIndex >= segmentLengths.Count)
{
string subTypeName = _route.PathType == PathType.Rail ? "空轨" : "吊装";
LogManager.Warning($"[{subTypeName}路径] 无法找到线段,目标距离:{targetDistance / metersToModelUnits:F2}米");
continue;
}
{
// === 空中路径:在路径点之间进行线性插值 ===
int segmentIndex = FindSegmentForDistance(targetDistance, segmentLengths);
if (segmentIndex < 0 || segmentIndex >= segmentLengths.Count)
{
string subTypeName = _route.PathType == PathType.Rail ? "空轨" : "吊装";
LogManager.Warning($"[{subTypeName}路径] 无法找到线段,目标距离:{targetDistance / metersToModelUnits:F2}米");
continue;
}
double accumulatedLength = segmentLengths.Take(segmentIndex).Sum();
double segmentProgress = (targetDistance - accumulatedLength) / segmentLengths[segmentIndex];
@ -846,14 +846,14 @@ namespace NavisworksTransport.Core.Animation
}
}
else
{
// === 地面路径:在边内插值 ===
int edgeIndex = FindEdgeForDistance(targetDistance, segmentLengths);
if (edgeIndex < 0 || edgeIndex >= _route.Edges.Count)
{
LogManager.Warning($"无法找到边,目标距离:{targetDistance / metersToModelUnits:F2}米");
continue;
}
{
// === 地面路径:在边内插值 ===
int edgeIndex = FindEdgeForDistance(targetDistance, segmentLengths);
if (edgeIndex < 0 || edgeIndex >= _route.Edges.Count)
{
LogManager.Warning($"无法找到边,目标距离:{targetDistance / metersToModelUnits:F2}米");
continue;
}
var edge = _route.Edges[edgeIndex];
double accumulatedLength = segmentLengths.Take(edgeIndex).Sum();
double edgeProgress = (targetDistance - accumulatedLength) / edge.PhysicalLength;
@ -941,9 +941,9 @@ namespace NavisworksTransport.Core.Animation
if (intersects)
{
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}");
// 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}");
var collisionResult = new CollisionResult
{
@ -990,7 +990,7 @@ namespace NavisworksTransport.Core.Animation
LogManager.Info($"包含碰撞的帧: {framesWithCollision}");
LogManager.Info($"总碰撞次数: {totalCollisions}");
LogManager.Info($"记录的碰撞结果总数: {_allCollisionResults.Count} 个");
// 🔥 清除移动物体集合
ClashDetectiveIntegration.ClearAnimatedObject();
}
@ -1525,11 +1525,11 @@ namespace NavisworksTransport.Core.Animation
if (!_completedCollisionTests.Contains(_currentAnimationHash))
{
LogManager.Info($"此动画配置首次完成,开始创建碰撞测试汇总(基于 {_allCollisionResults.Count} 个预计算碰撞记录)...");
// 🔥 设置等待光标,避免进度条关闭后的无响应
var oldCursor = System.Windows.Input.Mouse.OverrideCursor;
System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
try
{
// 🔥 使用用户设置的检测容差(米)
@ -1552,7 +1552,7 @@ namespace NavisworksTransport.Core.Animation
// 恢复光标
System.Windows.Input.Mouse.OverrideCursor = oldCursor;
}
_completedCollisionTests.Add(_currentAnimationHash); // 记录此配置已完成碰撞检测
LogManager.Info($"碰撞测试汇总已创建并记录,此配置后续播放将跳过碰撞检测");
}
@ -1954,7 +1954,7 @@ namespace NavisworksTransport.Core.Animation
// 我们需要手动计算旋转导致的位置偏移,并补偿
double deltaYaw = newYaw - _currentYaw;
LogManager.Debug($"[UpdateObjectPosition] 当前yaw={_currentYaw * 180 / Math.PI:F2}度, 目标yaw={newYaw * 180 / Math.PI:F2}度, 旋转增量deltaYaw={deltaYaw * 180 / Math.PI:F2}度");
//LogManager.Debug($"[UpdateObjectPosition] 当前yaw={_currentYaw * 180 / Math.PI:F2}度, 目标yaw={newYaw * 180 / Math.PI:F2}度, 旋转增量deltaYaw={deltaYaw * 180 / Math.PI:F2}度");
// 计算绕当前位置旋转的等效变换:
// 1. 如果绕原点旋转deltaYaw当前位置_currentPosition会移动到哪里
@ -1982,17 +1982,18 @@ namespace NavisworksTransport.Core.Animation
_currentYaw = newYaw;
}
else
{
// 纯平移
incrementalTransform = Transform3D.CreateTranslation(deltaPos);
LogManager.Debug($"[UpdateObjectPosition] 纯平移: ({deltaPos.X:F2},{deltaPos.Y:F2},{deltaPos.Z:F2})");
}
// 应用增量变换false = 增量模式)
doc.Models.OverridePermanentTransform(modelItems, incrementalTransform, false);
// 更新当前位置
_currentPosition = newPosition; }
{
// 纯平移
incrementalTransform = Transform3D.CreateTranslation(deltaPos);
LogManager.Debug($"[UpdateObjectPosition] 纯平移: ({deltaPos.X:F2},{deltaPos.Y:F2},{deltaPos.Z:F2})");
}
// 应用增量变换false = 增量模式)
doc.Models.OverridePermanentTransform(modelItems, incrementalTransform, false);
// 更新当前位置
_currentPosition = newPosition;
}
catch (Exception ex)
{
LogManager.Error($"更新部件位置失败: {ex.Message}");
@ -2601,10 +2602,10 @@ namespace NavisworksTransport.Core.Animation
}
// 设置动画参数并预计算动画帧
// 注意物体应该在调用CreateAnimation之前已经通过MoveVehicleToPathStart旋转到起点
LogManager.Debug($"[CreateAnimation开始] _currentYaw之前={_currentYaw * 180 / Math.PI:F2}度, _isVirtualVehicle={_isVirtualVehicle}");
SetupAnimation(animatedObject, durationSeconds, _route);
LogManager.Debug($"[CreateAnimation结束] _currentYaw之后={_currentYaw * 180 / Math.PI:F2}度");
// 注意物体应该在调用CreateAnimation之前已经通过MoveVehicleToPathStart旋转到起点
LogManager.Debug($"[CreateAnimation开始] _currentYaw之前={_currentYaw * 180 / Math.PI:F2}度, _isVirtualVehicle={_isVirtualVehicle}");
SetupAnimation(animatedObject, durationSeconds, _route);
LogManager.Debug($"[CreateAnimation结束] _currentYaw之后={_currentYaw * 180 / Math.PI:F2}度");
// 设置动画状态为Ready动画已生成可以播放
SetState(AnimationState.Ready);
LogManager.Info($"[CreateAnimation] 动画已创建状态设置为Ready");
@ -2771,7 +2772,7 @@ namespace NavisworksTransport.Core.Animation
if (_currentFrameIndex < _animationFrames.Count)
{
var frameData = _animationFrames[_currentFrameIndex];
// 计算实际朝向 = 路径方向 + 角度修正
double actualYaw = frameData.YawRadians;
if (_objectRotationCorrection != 0.0)
@ -2779,7 +2780,7 @@ namespace NavisworksTransport.Core.Animation
double correctionRad = _objectRotationCorrection * Math.PI / 180.0;
actualYaw += correctionRad;
}
UpdateObjectPosition(frameData.Position, actualYaw);
// 更新碰撞高亮(基于预计算结果)

View File

@ -608,6 +608,9 @@ namespace NavisworksTransport
int skippedCount = 0;
var doc = Application.ActiveDocument;
// 收集所有临时测试,用于批量删除
var tempTestsToRemove = new List<ClashTest>();
// 2. 遍历每一组
for (int groupIndex = 0; groupIndex < groupedCollisions.Count; groupIndex++)
{
@ -655,6 +658,8 @@ namespace NavisworksTransport
doc.Models.OverridePermanentTransform(modelItems, transform, false);
var tempTestName = $"临时验证_{confirmedCount + 1}_{i}_{DateTime.Now:HHmmss_fff}";
// 🔥 优化3预配置 ClashTest避免后续 CreateCopy 和 TestsEditTestFromCopy 调用
var tempTest = new ClashTest
{
DisplayName = tempTestName,
@ -668,17 +673,19 @@ namespace NavisworksTransport
var selectionB = new ModelItemCollection { candidate.Item2 };
tempTest.SelectionA.Selection.CopyFrom(selectionA);
tempTest.SelectionB.Selection.CopyFrom(selectionB);
// 直接设置 PrimitiveTypes避免后续的 CreateCopy 和 TestsEditTestFromCopy
tempTest.SelectionA.PrimitiveTypes = PrimitiveTypes.Triangles;
tempTest.SelectionB.PrimitiveTypes = PrimitiveTypes.Triangles | PrimitiveTypes.Lines | PrimitiveTypes.Points;
_documentClash.TestsData.TestsAddCopy(tempTest);
var addedTempTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == tempTestName) as ClashTest;
if (addedTempTest != null)
{
var copyTest = addedTempTest.CreateCopy() as ClashTest;
copyTest.SelectionA.PrimitiveTypes = PrimitiveTypes.Triangles | PrimitiveTypes.Lines | PrimitiveTypes.Points;
copyTest.SelectionB.PrimitiveTypes = PrimitiveTypes.Triangles | PrimitiveTypes.Lines | PrimitiveTypes.Points;
_documentClash.TestsData.TestsEditTestFromCopy(addedTempTest, copyTest);
// 🔥 优化3跳过了 addedTempTest.CreateCopy() 和 TestsEditTestFromCopy 调用
// 因为 PrimitiveTypes 已在创建 tempTest 时设置好
_documentClash.TestsData.TestsRunTest(addedTempTest);
var refreshedTempTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName == tempTestName) as ClashTest;
@ -697,15 +704,10 @@ namespace NavisworksTransport
var copiedResult = result.CreateCopy() as ClashResult;
copiedResult.Guid = Guid.NewGuid(); // 生成新的GUID
// 设置唯一且有意义的碰撞名称
// 先找到有意义的容器对象,再获取其名称
var container1 = ModelItemAnalysisHelper.FindNamedParentContainer(result.Item1);
var container2 = ModelItemAnalysisHelper.FindNamedParentContainer(result.Item2);
var object1Name = ModelItemAnalysisHelper.GetSafeDisplayName(container1);
var object2Name = ModelItemAnalysisHelper.GetSafeDisplayName(container2);
// 🔥 优化:简化 DisplayName避免复杂的父容器查找
// 详细的名称将在去重后统一设置
var timeStamp = DateTime.Now.ToString("HHmmss");
copiedResult.DisplayName = $"物流碰撞#{confirmedCount:00}-{subResultIndex:00}_{timeStamp}: {object1Name} ↔ {object2Name}";
copiedResult.DisplayName = $"碰撞_{confirmedCount:00}_{subResultIndex:00}_{timeStamp}";
collisionGroup.Children.Add(copiedResult);
subResultIndex++;
@ -713,7 +715,8 @@ namespace NavisworksTransport
}
}
_documentClash.TestsData.TestsRemove(refreshedTempTest ?? addedTempTest);
// 🔥 优化4收集测试用于批量删除而不是立即删除
tempTestsToRemove.Add(refreshedTempTest ?? addedTempTest);
if (pairConfirmed)
{
@ -728,6 +731,23 @@ namespace NavisworksTransport
}
}
// 🔥 优化4批量删除所有临时测试
if (tempTestsToRemove.Count > 0)
{
LogManager.Debug($"[分组测试] 批量删除 {tempTestsToRemove.Count} 个临时测试");
foreach (var test in tempTestsToRemove)
{
try
{
_documentClash.TestsData.TestsRemove(test);
}
catch (Exception ex)
{
LogManager.Debug($"[分组测试] 删除临时测试失败: {ex.Message}");
}
}
}
LogManager.Info($"[分组测试] ClashDetective检测完成: 确认碰撞 {confirmedCount} 组, 跳过 {skippedCount} 个冗余检测点");
// 第三步:处理碰撞结果
@ -766,6 +786,18 @@ namespace NavisworksTransport
LogManager.Info($"[最终去重] ClashDetective结果去重: {clashResults.Count} 个碰撞 -> {finalClashResults.Count} 个唯一碰撞对");
// 🔥 优化:在去重后为结果设置详细的 DisplayName
// 这样只对保留的结果进行名称计算,避免在子碰撞结果上浪费性能
foreach (var result in finalClashResults)
{
if (result.Item1 != null && result.Item2 != null)
{
var object1Name = ModelItemAnalysisHelper.GetSafeDisplayName(result.Item1);
var object2Name = ModelItemAnalysisHelper.GetSafeDisplayName(result.Item2);
result.DisplayName = $"物流碰撞: {object1Name} ↔ {object2Name}";
}
}
// 缓存最终结果
lock (_clashResultsCacheLock)
{