From 6be1de113e3f4060a9d74e0deb8c4a5db259ac2a Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Fri, 6 Feb 2026 20:42:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=EF=BC=8C=E8=B0=83=E6=95=B4=E7=A9=BA=E8=A1=8C=E5=92=8C?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=BD=8D=E7=BD=AE=EF=BC=9B=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=94=9F=E6=88=90=E7=A2=B0=E6=92=9E=E6=8A=A5=E5=91=8A=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E4=B8=BA=E5=BC=82=E6=AD=A5=E6=89=A7=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 6 +- .../Collision/ClashDetectiveIntegration.cs | 138 +++++++++--------- .../ViewModels/AnimationControlViewModel.cs | 10 +- 3 files changed, 79 insertions(+), 75 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 3ba84e8..87daf49 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -77,6 +77,7 @@ set MSBUILD_PATH="C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuil ``` 该脚本将: + 1. 构建主项目 2. 构建测试项目 3. 使用 VSTest.Console 运行单元测试 @@ -162,6 +163,7 @@ UnitTests/ # 单元测试 ### 关键依赖 **Navisworks API(必须安装Navisworks 2026):** + - `Autodesk.Navisworks.Api.dll` - `Autodesk.Navisworks.ComApi.dll` - `Autodesk.Navisworks.Interop.ComApi.dll` @@ -170,6 +172,7 @@ UnitTests/ # 单元测试 - `Autodesk.Navisworks.Controls.dll` **NuGet包:** + - `RoyT.AStar 3.0.2` - A*寻路算法 - `geometry4Sharp 1.0.0` - 3D几何计算(体素路径规划) - `System.Data.SQLite.Core 1.0.118.0` - SQLite数据库 @@ -233,6 +236,7 @@ if (heightDiff > MAX_HEIGHT_DIFF) // 单位不匹配,严重Bug! ``` `UnitsConverter` 提供以下方法: + - `GetUnitsToMetersConversionFactor()` - 文档单位转米 - `GetMetersToUnitsConversionFactor()` - 米转文档单位 - `ConvertToMeters(distance)` - 转换距离为米 @@ -408,7 +412,7 @@ namespace NavisworksTransport.UnitTests 1. **查看日志**: 日志文件位于 `C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\NavisworksTransportPlugin\logs\` 2. **使用 LogManager**: 所有重要操作都应记录日志 -3. **Navisworks插件调试**: +3. **Navisworks插件调试**: - 附加到 `Roamer.exe` 进程 - 使用 `LogManager.Debug()` 输出调试信息 diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs index 2d3c91e..c342611 100644 --- a/src/Core/Collision/ClashDetectiveIntegration.cs +++ b/src/Core/Collision/ClashDetectiveIntegration.cs @@ -213,7 +213,7 @@ namespace NavisworksTransport { // 使用 CreatePathId API 获取 ModelIndex 和 PathId var pathId = Application.ActiveDocument.Models.CreatePathId(collision.Item2); - + collisionObjects.Add(new ClashDetectiveCollisionObjectRecord { ResultId = resultId, @@ -328,14 +328,14 @@ namespace NavisworksTransport if (testInfo.IsVirtualVehicle) { // 显示虚拟车辆 + var modelToMeters = UnitsConverter.GetUnitsToMetersConversionFactor(); VirtualVehicleManager.Instance.ShowVirtualVehicle( - testInfo.VirtualVehicleLength, - testInfo.VirtualVehicleWidth, - testInfo.VirtualVehicleHeight + testInfo.VirtualVehicleLength * modelToMeters, + testInfo.VirtualVehicleWidth * modelToMeters, + testInfo.VirtualVehicleHeight * modelToMeters ); - vehicleObject = VirtualVehicleManager.Instance.CurrentVirtualVehicle + vehicleObject = VirtualVehicleManager.Instance.CurrentVirtualVehicle ?? throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 显示虚拟车辆失败"); - LogManager.Info($"[LoadClashDetectiveResultsFromDatabase] 已显示虚拟车辆: {testInfo.VirtualVehicleLength}×{testInfo.VirtualVehicleWidth}×{testInfo.VirtualVehicleHeight}m"); } else if (testInfo.VehicleModelIndex.HasValue && !string.IsNullOrEmpty(testInfo.VehiclePathId)) { @@ -368,15 +368,15 @@ namespace NavisworksTransport { var pathPlanningManager = PathPlanningManager.Instance; var route = pathPlanningManager.GetAllRoutes().FirstOrDefault(r => r.Id == testInfo.RouteId); - + if (route != null && route.Points != null && route.Points.Count > 0) { // 获取第一个点(起点) var startPoint = route.Points.FirstOrDefault(p => p.Type == PathPointType.StartPoint) ?? route.Points[0]; var startPointPosition = startPoint.Position; - + // 使用 PathAnimationManager 将车辆移动到起点 - var pathAnimationManager = Core.Animation.PathAnimationManager.GetInstance(); + var pathAnimationManager = PathAnimationManager.GetInstance(); pathAnimationManager.MoveVehicleToPathStart(vehicleObject, new List { startPointPosition, startPointPosition }); LogManager.Info($"[LoadClashDetectiveResultsFromDatabase] 虚拟车辆已移动到路径起点: ({startPointPosition.X:F2}, {startPointPosition.Y:F2}, {startPointPosition.Z:F2})"); } @@ -419,7 +419,7 @@ namespace NavisworksTransport foreach (var obj in collisionObjects) { ModelItem collidedObject = null; - + // 优先使用 ResolvePathId API(新方式) if (obj.ModelIndex.HasValue && !string.IsNullOrEmpty(obj.PathId)) { @@ -435,12 +435,12 @@ namespace NavisworksTransport throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] ResolvePathId 失败: ModelIndex={obj.ModelIndex}, PathId={obj.PathId}", ex); } } - + if (collidedObject == null) { throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 无法通过路径找到车辆对象: {obj.ModelIndex},{obj.PathId}"); } - + if (!ModelItemAnalysisHelper.IsModelItemValid(collidedObject)) { throw new InvalidOperationException($"[LoadClashDetectiveResultsFromDatabase] 找到的 ModelItem 无效: {obj.ModelIndex},{obj.PathId}"); @@ -500,7 +500,7 @@ namespace NavisworksTransport return new Point3D(0, 0, 0); } } - + /// /// 通过PathId向上查找匹配的原始对象 /// 从ClashDetective返回的几何体组件开始,向上遍历父节点, @@ -545,7 +545,7 @@ namespace NavisworksTransport try { var currentPathId = doc.Models.CreatePathId(current); - + // 检查PathId是否在预计算记录中 if (precomputedPathIds.Contains((currentPathId.ModelIndex, currentPathId.PathId))) { @@ -635,10 +635,10 @@ namespace NavisworksTransport if (validCollisions.Count == 0) { LogManager.Warning("[ClashDetective] 没有有效的碰撞,保存空碰撞记录"); - + // 重置碰撞计数器(重要:避免保留上次测试的值) _clashDetectiveCollisionCount = 0; - + // 保存到数据库 SaveClashDetectiveResultToDatabase( routeId, @@ -653,7 +653,7 @@ namespace NavisworksTransport virtualVehicleHeight, precomputedCollisionCount ); - + return (null, addedMainTest, 0); } @@ -739,7 +739,7 @@ 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 { @@ -754,7 +754,7 @@ 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; @@ -766,9 +766,9 @@ namespace NavisworksTransport { // 🔥 优化3:跳过了 addedTempTest.CreateCopy() 和 TestsEditTestFromCopy 调用 // 因为 PrimitiveTypes 已在创建 tempTest 时设置好 - + _documentClash.TestsData.TestsRunTest(addedTempTest); - + // 增加检测计数并打印进度日志(每100次) testCount++; if (testCount % 100 == 0) @@ -788,7 +788,7 @@ namespace NavisworksTransport int subResultIndex = 1; // 🔥 优化:预获取运动物体名称,避免在循环中重复获取 var animatedObjectName = ModelItemAnalysisHelper.GetSafeDisplayName(animatedObject); - + foreach (var child in refreshedTempTest.Children) { if (child is ClashResult result) @@ -948,48 +948,48 @@ namespace NavisworksTransport try { LogManager.Info($"=== 使用预计算碰撞数据创建ClashDetective测试(容差: {detectionGap}米)==="); - - LogManager.Info($"[预计算数据] 共有 {precomputedCollisions.Count} 个碰撞记录"); - - // 直接使用所有预计算结果,只过滤有效对象(不去重) - var collisionResults = precomputedCollisions - .Where(result => IsModelItemValid(result.Item1) && IsModelItemValid(result.Item2)) - .ToList(); - - // 记录预计算碰撞数量(作为参考值,不作为类状态) - int precomputedCollisionCount = collisionResults.Count; - LogManager.Info($"[预计算处理] 原始记录: {precomputedCollisions.Count},有效碰撞: {precomputedCollisionCount}"); - - // 获取动画对象 - if (collisionResults.Count > 0) - { - animatedObject = collisionResults[0].Item1; - } - - var doc = Application.ActiveDocument; - - // 调用公共方法运行ClashDetective测试并保存到数据库 - Progress progress = Application.BeginProgress("碰撞检测数据分析中,请稍候..."); - ClashTest addedMainTest = null; - ClashResultGroup collisionGroup = null; - int confirmedCount = 0; - try - { - var result = RunClashDetectiveTestsAndSaveToDatabase( - precomputedCollisions, - detectionGap, - routeId, - animatedObject, - isVirtualVehicle, - frameRate, - duration, - virtualVehicleLength, - virtualVehicleWidth, - virtualVehicleHeight, - progress, - precomputedCollisionCount - ); + LogManager.Info($"[预计算数据] 共有 {precomputedCollisions.Count} 个碰撞记录"); + + // 直接使用所有预计算结果,只过滤有效对象(不去重) + var collisionResults = precomputedCollisions + .Where(result => IsModelItemValid(result.Item1) && IsModelItemValid(result.Item2)) + .ToList(); + + // 记录预计算碰撞数量(作为参考值,不作为类状态) + int precomputedCollisionCount = collisionResults.Count; + LogManager.Info($"[预计算处理] 原始记录: {precomputedCollisions.Count},有效碰撞: {precomputedCollisionCount}"); + + // 获取动画对象 + if (collisionResults.Count > 0) + { + animatedObject = collisionResults[0].Item1; + } + + var doc = Application.ActiveDocument; + + // 调用公共方法运行ClashDetective测试并保存到数据库 + Progress progress = Application.BeginProgress("碰撞检测数据分析中,请稍候..."); + ClashTest addedMainTest = null; + ClashResultGroup collisionGroup = null; + int confirmedCount = 0; + + try + { + var result = RunClashDetectiveTestsAndSaveToDatabase( + precomputedCollisions, + detectionGap, + routeId, + animatedObject, + isVirtualVehicle, + frameRate, + duration, + virtualVehicleLength, + virtualVehicleWidth, + virtualVehicleHeight, + progress, + precomputedCollisionCount + ); collisionGroup = result.collisionGroup; addedMainTest = result.addedMainTest; confirmedCount = result.confirmedCount; @@ -1156,11 +1156,11 @@ namespace NavisworksTransport LogManager.Debug($"[ClashDetective结果] 从缓存获取 '{testName}' 的结果:{cachedResults.Count}个碰撞"); return cachedResults; } - + // 缓存中没有,尝试从数据库加载 LogManager.Info($"[ClashDetective结果] 缓存中没有 '{testName}',尝试从数据库加载"); var loadedResults = GetClashDetectiveResultsFromDatabase(testName); - + if (loadedResults != null && loadedResults.Count > 0) { // 缓存加载的结果 @@ -1168,7 +1168,7 @@ namespace NavisworksTransport LogManager.Info($"[ClashDetective结果] 已从数据库加载 '{testName}' 的结果并缓存:{loadedResults.Count}个碰撞"); return loadedResults; } - + // 没有找到结果,返回空列表 LogManager.Info($"[ClashDetective结果] 未找到测试 '{testName}' 的碰撞结果,返回空列表"); return new List(); @@ -1384,7 +1384,7 @@ namespace NavisworksTransport { _animatedObject = animatedObject; LogManager.Info($"移动物体已设置: {animatedObject?.DisplayName ?? "null"}"); - + // 🔥 关键:清除几何对象缓存,强制重新构建以排除移动物体 // 原因:BuildNonHidddenGeometryItemsCache 使用双重检查锁定,只构建一次 // 如果在第一次构建时移动物体为 null,摩托车会被添加到缓存 @@ -1392,7 +1392,7 @@ namespace NavisworksTransport _allGeometryItemsCache = null; _nonChannelGeometryItemsCache = null; LogManager.Info("几何对象缓存已清除,将重新构建以排除移动物体"); - + // 🔥 立即重新构建几何对象缓存(排除移动物体) BuildNonHidddenGeometryItemsCache(); LogManager.Info("几何对象缓存已重新构建完成"); @@ -1589,7 +1589,7 @@ namespace NavisworksTransport { lock (_cacheLock) { - return _allGeometryItemsCache; + return _allGeometryItemsCache; } } diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index b891b49..f0aa907 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -1652,7 +1652,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels /// private void OnAnimationStateChanged(object sender, Core.Animation.AnimationState state) { - System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => + System.Windows.Application.Current.Dispatcher.BeginInvoke(new Func(async () => { switch (state) { @@ -1678,9 +1678,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels UpdateMediaControlProperties(); // 更新媒体控制属性 // 先清除所有碰撞高亮(包括预计算和ClashDetective) ModelHighlightHelper.ClearCollisionHighlights(); - // 生成碰撞报告(无论有无碰撞) - GenerateAndSaveCollisionReport(); - // 高亮ClashDetective结果(只在动画自然完成时进行) + // 生成碰撞报告(无论有无碰撞)并等待完成 + await GenerateAndSaveCollisionReport(); + // 高亮ClashDetective结果(只在动画自然完成时进行,确保报告生成完成) HighlightClashDetectiveResults(); break; case NavisworksTransport.Core.Animation.AnimationState.Stopped: @@ -1704,7 +1704,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels /// /// 生成并保存碰撞报告(无论有无碰撞都生成) /// - private async void GenerateAndSaveCollisionReport() + private async Task GenerateAndSaveCollisionReport() { try {