修复路径预计算范围不对、碰撞检测报告名字匹配错误的BUG
This commit is contained in:
parent
882f8283b5
commit
bd7eeb3d46
@ -294,6 +294,7 @@
|
||||
<Compile Include="src\Utils\NavisworksToDMesh3Converter.cs" />
|
||||
<Compile Include="src\Utils\UnitsConverter.cs" />
|
||||
<Compile Include="src\Utils\VisibilityHelper.cs" />
|
||||
<Compile Include="src\Utils\ModelItemTransformHelper.cs" />
|
||||
|
||||
<!-- Assembly Info -->
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
||||
@ -275,27 +275,36 @@ namespace NavisworksTransport.Commands
|
||||
return null;
|
||||
}
|
||||
|
||||
// 查找最新的物流碰撞检测测试
|
||||
var latestTest = documentClash.TestsData.Tests.Cast<ClashTest>()
|
||||
.Where(t => t.DisplayName.StartsWith("物流碰撞检测_"))
|
||||
.OrderByDescending(t => t.DisplayName)
|
||||
// 从动画管理器获取当前路径名称
|
||||
var animationManager = Core.Animation.PathAnimationManager.GetInstance();
|
||||
var currentPathName = animationManager?.PathName;
|
||||
|
||||
if (string.IsNullOrEmpty(currentPathName))
|
||||
{
|
||||
throw new InvalidOperationException("无法获取当前路径名称");
|
||||
}
|
||||
|
||||
// 精确匹配当前路径的测试
|
||||
var matchedTest = documentClash.TestsData.Tests.Cast<ClashTest>()
|
||||
.Where(t => t.DisplayName.StartsWith("物流碰撞检测_") &&
|
||||
t.DisplayName.Contains(currentPathName))
|
||||
.OrderByDescending(t => t.DisplayName) // 同一路径可能有多个测试,取最新的
|
||||
.FirstOrDefault();
|
||||
|
||||
if (latestTest != null)
|
||||
if (matchedTest != null)
|
||||
{
|
||||
LogManager.Debug($"缓存键用测试名称: {latestTest.DisplayName}");
|
||||
return latestTest.DisplayName;
|
||||
LogManager.Info($"找到当前路径的测试: {matchedTest.DisplayName}");
|
||||
return matchedTest.DisplayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info("未找到物流碰撞检测测试,无法生成缓存键");
|
||||
return null;
|
||||
throw new InvalidOperationException($"未找到路径 '{currentPathName}' 的碰撞测试");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"获取测试名称作为缓存键失败: {ex.Message}");
|
||||
return null;
|
||||
throw; // 让错误暴露出来
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,27 +346,37 @@ namespace NavisworksTransport.Commands
|
||||
|
||||
int totalCollisionCount = 0; // Clash Detective总碰撞数
|
||||
|
||||
// 🔧 修复:只统计最新的物流碰撞检测测试,避免重复累积
|
||||
var latestTest = documentClash.TestsData.Tests.Cast<ClashTest>()
|
||||
.Where(t => t.DisplayName.StartsWith("物流碰撞检测_"))
|
||||
// 从动画管理器获取当前路径名称
|
||||
var animationManager = Core.Animation.PathAnimationManager.GetInstance();
|
||||
var currentPathName = animationManager?.PathName;
|
||||
|
||||
if (string.IsNullOrEmpty(currentPathName))
|
||||
{
|
||||
throw new InvalidOperationException("无法获取当前路径名称");
|
||||
}
|
||||
|
||||
// 精确匹配当前路径的测试
|
||||
var matchedTest = documentClash.TestsData.Tests.Cast<ClashTest>()
|
||||
.Where(t => t.DisplayName.StartsWith("物流碰撞检测_") &&
|
||||
t.DisplayName.Contains(currentPathName))
|
||||
.OrderByDescending(t => t.DisplayName)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (latestTest != null)
|
||||
|
||||
if (matchedTest != null)
|
||||
{
|
||||
LogManager.Info($"找到最新的物流路径测试: {latestTest.DisplayName}");
|
||||
|
||||
// 提取最新测试的碰撞数据
|
||||
var testCollisions = ExtractCollisionsFromTest(latestTest);
|
||||
LogManager.Info($"找到当前路径的测试: {matchedTest.DisplayName}");
|
||||
|
||||
// 提取匹配测试的碰撞数据
|
||||
var testCollisions = ExtractCollisionsFromTest(matchedTest);
|
||||
allCollisions.AddRange(testCollisions);
|
||||
|
||||
// 统计最新测试的碰撞总数
|
||||
totalCollisionCount = GetTotalClashResultCountFromTest(latestTest);
|
||||
LogManager.Debug($"最新测试 '{latestTest.DisplayName}' 包含 {totalCollisionCount} 个碰撞");
|
||||
|
||||
// 统计匹配测试的碰撞总数
|
||||
totalCollisionCount = GetTotalClashResultCountFromTest(matchedTest);
|
||||
LogManager.Debug($"匹配测试 '{matchedTest.DisplayName}' 包含 {totalCollisionCount} 个碰撞");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info("未找到物流碰撞检测测试");
|
||||
throw new InvalidOperationException($"未找到路径 '{currentPathName}' 的碰撞测试");
|
||||
}
|
||||
|
||||
// 去重处理
|
||||
|
||||
@ -466,45 +466,81 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 构建通道缓存
|
||||
ClashDetectiveIntegration.Instance.BuildChannelObjectsCache();
|
||||
ClashDetectiveIntegration.BuildAllGeometryItemsCache();
|
||||
|
||||
|
||||
// 获取所有有几何体的对象
|
||||
var allItems = NavisApplication.ActiveDocument.Models.RootItemDescendantsAndSelf
|
||||
.Where(item => item.HasGeometry)
|
||||
.ToList();
|
||||
|
||||
|
||||
// 构建排除列表:动画对象本身及其子对象
|
||||
var excludeList = new ModelItemCollection();
|
||||
excludeList.AddRange(_animatedObject.DescendantsAndSelf);
|
||||
|
||||
// 使用ClashDetectiveIntegration的碰撞检测方法,它会自动排除通道对象
|
||||
// 创建一个较大的检测间隙来获取路径范围内所有潜在碰撞对象
|
||||
var detectionGap = 100.0; // 100米范围内的对象都视为潜在碰撞对象
|
||||
|
||||
// 调用ClashDetectiveIntegration的DetectCollisions方法
|
||||
// 该方法内部会自动排除通道对象(通过IsChannelObject方法)
|
||||
var collisionResults = ClashDetectiveIntegration.Instance.DetectCollisions(
|
||||
_animatedObject,
|
||||
excludeList,
|
||||
detectionGap
|
||||
|
||||
// 计算路径包围盒
|
||||
var pathBounds = CalculatePathBounds();
|
||||
|
||||
// 计算路径包围盒中心点(模型单位)
|
||||
var pathCenter = new Point3D(
|
||||
(pathBounds.Min.X + pathBounds.Max.X) / 2,
|
||||
(pathBounds.Min.Y + pathBounds.Max.Y) / 2,
|
||||
(pathBounds.Min.Z + pathBounds.Max.Z) / 2
|
||||
);
|
||||
|
||||
// 从碰撞结果中提取唯一的碰撞对象
|
||||
var potentialColliders = new HashSet<ModelItem>();
|
||||
foreach (var result in collisionResults)
|
||||
|
||||
// 计算包围盒对角线长度
|
||||
var diagonal = Math.Sqrt(
|
||||
Math.Pow(pathBounds.Max.X - pathBounds.Min.X, 2) +
|
||||
Math.Pow(pathBounds.Max.Y - pathBounds.Min.Y, 2) +
|
||||
Math.Pow(pathBounds.Max.Z - pathBounds.Min.Z, 2)
|
||||
);
|
||||
|
||||
// 检测半径 = 包围盒对角线的一半(精确覆盖整条路径)
|
||||
var detectionGap = diagonal / 2;
|
||||
|
||||
LogManager.Info($"路径包围盒: Min=({pathBounds.Min.X:F2}, {pathBounds.Min.Y:F2}, {pathBounds.Min.Z:F2}), " +
|
||||
$"Max=({pathBounds.Max.X:F2}, {pathBounds.Max.Y:F2}, {pathBounds.Max.Z:F2})");
|
||||
LogManager.Info($"路径中心: ({pathCenter.X:F2}, {pathCenter.Y:F2}, {pathCenter.Z:F2})");
|
||||
LogManager.Info($"包围盒对角线: {diagonal:F2} 模型单位");
|
||||
|
||||
// 临时移动物体到路径中心,以便在路径范围内检测潜在碰撞对象
|
||||
var offset = ModelItemTransformHelper.MoveItemToPosition(_animatedObject, pathCenter);
|
||||
|
||||
try
|
||||
{
|
||||
if (result.Item2 != null && !potentialColliders.Contains(result.Item2))
|
||||
LogManager.Info($"检测半径: {detectionGap:F2} 模型单位(对角线的一半)");
|
||||
|
||||
// 调用ClashDetectiveIntegration的DetectCollisions方法
|
||||
// 现在物体在路径中心,检测路径长度半径内的对象
|
||||
// 该方法内部会自动排除通道对象(通过IsChannelObject方法)
|
||||
var collisionResults = ClashDetectiveIntegration.Instance.DetectCollisions(
|
||||
_animatedObject,
|
||||
excludeList,
|
||||
detectionGap
|
||||
);
|
||||
|
||||
// 从碰撞结果中提取唯一的碰撞对象
|
||||
var potentialColliders = new HashSet<ModelItem>();
|
||||
foreach (var result in collisionResults)
|
||||
{
|
||||
potentialColliders.Add(result.Item2);
|
||||
if (result.Item2 != null && !potentialColliders.Contains(result.Item2))
|
||||
{
|
||||
potentialColliders.Add(result.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
var finalList = potentialColliders.ToList();
|
||||
|
||||
LogManager.Info($"获取潜在碰撞对象完成: 总对象={allItems.Count}, " +
|
||||
$"排除自身及子对象={excludeList.Count}, " +
|
||||
$"路径沿途潜在碰撞对象={finalList.Count}(已自动排除通道)");
|
||||
|
||||
return finalList;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 恢复物体到原位置
|
||||
ModelItemTransformHelper.RestoreItemPosition(_animatedObject, offset);
|
||||
LogManager.Info("物体已恢复到原始位置");
|
||||
}
|
||||
|
||||
var finalList = potentialColliders.ToList();
|
||||
|
||||
LogManager.Info($"获取潜在碰撞对象完成: 总对象={allItems.Count}, " +
|
||||
$"排除自身及子对象={excludeList.Count}, " +
|
||||
$"检测范围内潜在碰撞对象={finalList.Count}(已自动排除通道)");
|
||||
|
||||
return finalList;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
60
src/Utils/ModelItemTransformHelper.cs
Normal file
60
src/Utils/ModelItemTransformHelper.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using Autodesk.Navisworks.Api;
|
||||
|
||||
namespace NavisworksTransport.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// ModelItem变换辅助工具
|
||||
/// 提供临时移动和恢复物体位置的通用方法
|
||||
/// </summary>
|
||||
public static class ModelItemTransformHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 临时移动物体到指定位置
|
||||
/// </summary>
|
||||
/// <param name="item">要移动的物体</param>
|
||||
/// <param name="targetPosition">目标位置(物体中心)</param>
|
||||
/// <returns>用于恢复的偏移向量</returns>
|
||||
public static Vector3D MoveItemToPosition(ModelItem item, Point3D targetPosition)
|
||||
{
|
||||
var doc = Application.ActiveDocument;
|
||||
var modelItems = new ModelItemCollection { item };
|
||||
|
||||
// 计算当前中心位置
|
||||
var currentBounds = item.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 offset = new Vector3D(
|
||||
targetPosition.X - currentPos.X,
|
||||
targetPosition.Y - currentPos.Y,
|
||||
targetPosition.Z - currentPos.Z
|
||||
);
|
||||
|
||||
// 应用变换
|
||||
var transform = Transform3D.CreateTranslation(offset);
|
||||
doc.Models.OverridePermanentTransform(modelItems, transform, false);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复物体到原位置
|
||||
/// </summary>
|
||||
/// <param name="item">要恢复的物体</param>
|
||||
/// <param name="originalOffset">原始移动偏移向量</param>
|
||||
public static void RestoreItemPosition(ModelItem item, Vector3D originalOffset)
|
||||
{
|
||||
var doc = Application.ActiveDocument;
|
||||
var modelItems = new ModelItemCollection { item };
|
||||
|
||||
// 反向偏移
|
||||
var restoreOffset = new Vector3D(-originalOffset.X, -originalOffset.Y, -originalOffset.Z);
|
||||
var restoreTransform = Transform3D.CreateTranslation(restoreOffset);
|
||||
doc.Models.OverridePermanentTransform(modelItems, restoreTransform, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user