优化代码格式,调整空行和注释位置;更新生成碰撞报告的方法为异步执行

This commit is contained in:
tian 2026-02-06 20:42:40 +08:00
parent a94d1c35b7
commit 6be1de113e
3 changed files with 79 additions and 75 deletions

View File

@ -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()` 输出调试信息

View File

@ -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<Point3D> { 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);
}
}
/// <summary>
/// 通过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<CollisionResult>();
@ -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;
}
}

View File

@ -1652,7 +1652,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// </summary>
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<Task>(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
/// <summary>
/// 生成并保存碰撞报告(无论有无碰撞都生成)
/// </summary>
private async void GenerateAndSaveCollisionReport()
private async Task GenerateAndSaveCollisionReport()
{
try
{