From 2d1c835398ef37842fc2dcc17b590c56506e0f4f Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Wed, 27 Aug 2025 20:53:09 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A2=B0=E6=92=9E=E6=8A=A5?=
=?UTF-8?q?=E5=91=8A=E6=97=A0=E7=BB=93=E6=9E=9C=E7=9A=84=E9=97=AE=E9=A2=98?=
=?UTF-8?q?=EF=BC=88=E7=A2=B0=E6=92=9E=E9=9C=80=E8=A6=81=E6=89=BE=E5=88=B0?=
=?UTF-8?q?=E5=AE=B9=E5=99=A8=E8=8A=82=E7=82=B9=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Collision/ClashDetectiveIntegration.cs | 274 ++++++++++++++++--
1 file changed, 252 insertions(+), 22 deletions(-)
diff --git a/src/Core/Collision/ClashDetectiveIntegration.cs b/src/Core/Collision/ClashDetectiveIntegration.cs
index 00412a4..47458bf 100644
--- a/src/Core/Collision/ClashDetectiveIntegration.cs
+++ b/src/Core/Collision/ClashDetectiveIntegration.cs
@@ -359,7 +359,18 @@ namespace NavisworksTransport
return;
}
- // 使用精确的碰撞检测算法
+ // 🔧 智能容器映射:将几何体子对象映射到有名称的容器对象
+ var mappedAnimatedObject = GetCollisionObjectWithValidIdentity(animatedObject);
+ var mappedCollisionObject = GetCollisionObjectWithValidIdentity(collisionObject);
+
+ // 检查是否进行了容器映射
+ bool hasMapping1 = !mappedAnimatedObject.Equals(animatedObject);
+ bool hasMapping2 = !mappedCollisionObject.Equals(collisionObject);
+
+ LogManager.Info($"[容器映射] 动画对象: '{animatedObject.DisplayName}' -> '{mappedAnimatedObject.DisplayName}' (映射: {hasMapping1})");
+ LogManager.Info($"[容器映射] 碰撞对象: '{collisionObject.DisplayName}' -> '{mappedCollisionObject.DisplayName}' (映射: {hasMapping2})");
+
+ // 使用精确的碰撞检测算法(基于原始几何体)
var animatedBoundingBox = animatedObject.BoundingBox();
var collisionBoundingBox = collisionObject.BoundingBox();
@@ -386,7 +397,7 @@ namespace NavisworksTransport
LogManager.Warning($"[诊断-位置警告] 两个对象位置几乎相同 (距离: {positionDistance:F6}),这可能是自碰撞的标志!");
}
- // 创建精确的碰撞结果
+ // 创建精确的碰撞结果(使用原始几何体计算,但记录容器对象)
var collisionDistance = CalculateDistance(animatedBoundingBox, collisionBoundingBox);
var collisionCenter = CalculateCenter(animatedBoundingBox, collisionBoundingBox);
@@ -396,10 +407,13 @@ namespace NavisworksTransport
var collision = new CollisionResult
{
ClashGuid = Guid.NewGuid(),
- DisplayName = $"精确碰撞: {animatedObject.DisplayName} <-> {collisionObject.DisplayName}",
+ DisplayName = $"精确碰撞: {mappedAnimatedObject.DisplayName} <-> {mappedCollisionObject.DisplayName}",
Status = ClashResultStatus.New,
- Item1 = animatedObject,
- Item2 = collisionObject,
+ Item1 = mappedAnimatedObject, // 记录容器对象
+ Item2 = mappedCollisionObject, // 记录容器对象
+ OriginalItem1 = animatedObject, // 保存原始几何体对象
+ OriginalItem2 = collisionObject, // 保存原始几何体对象
+ HasContainerMapping = hasMapping1 || hasMapping2, // 标记是否进行了映射
CreatedTime = DateTime.Now,
Distance = collisionDistance,
Center = collisionCenter,
@@ -413,26 +427,30 @@ namespace NavisworksTransport
LogManager.Debug($" DisplayName: {collision.DisplayName}");
LogManager.Debug($" Item1: {collision.Item1?.DisplayName ?? "NULL"}");
LogManager.Debug($" Item2: {collision.Item2?.DisplayName ?? "NULL"}");
+ LogManager.Debug($" OriginalItem1: {collision.OriginalItem1?.DisplayName ?? "NULL"}");
+ LogManager.Debug($" OriginalItem2: {collision.OriginalItem2?.DisplayName ?? "NULL"}");
+ LogManager.Debug($" HasContainerMapping: {collision.HasContainerMapping}");
LogManager.Debug($" Distance: {collision.Distance:F4}");
LogManager.Debug($" HasPositionInfo: {collision.HasPositionInfo}");
- // 去重处理:避免重复缓存相同的碰撞对
+ // 去重处理:避免重复缓存相同的碰撞对(基于容器对象)
var existing = _cachedResults.FirstOrDefault(r =>
- r.Item1.Equals(animatedObject) && r.Item2.Equals(collisionObject));
+ r.Item1.Equals(mappedAnimatedObject) && r.Item2.Equals(mappedCollisionObject));
if (existing == null)
{
_cachedResults.Add(collision);
- LogManager.Info($"[碰撞缓存-成功] 缓存精确碰撞: {animatedObject.DisplayName} <-> {collisionObject.DisplayName}");
+ LogManager.Info($"[碰撞缓存-成功] 缓存精确碰撞: {mappedAnimatedObject.DisplayName} <-> {mappedCollisionObject.DisplayName}");
LogManager.Info($" 时间: {collision.CreatedTime:HH:mm:ss}");
LogManager.Info($" 动画位置: ({collision.Item1Position.X:F3},{collision.Item1Position.Y:F3},{collision.Item1Position.Z:F3})");
LogManager.Info($" 碰撞位置: ({collision.Item2Position.X:F3},{collision.Item2Position.Y:F3},{collision.Item2Position.Z:F3})");
LogManager.Info($" 包围盒距离: {collision.Distance:F4}");
+ LogManager.Info($" 容器映射: {collision.HasContainerMapping}");
LogManager.Info($" 当前缓存总数: {_cachedResults.Count}");
}
else
{
- LogManager.Debug($"[碰撞缓存-跳过] 重复碰撞: {animatedObject.DisplayName} <-> {collisionObject.DisplayName}");
+ LogManager.Debug($"[碰撞缓存-跳过] 重复碰撞: {mappedAnimatedObject.DisplayName} <-> {mappedCollisionObject.DisplayName}");
LogManager.Debug($" 原有记录时间: {existing.CreatedTime:HH:mm:ss}");
LogManager.Debug($" 本次尝试时间: {DateTime.Now:HH:mm:ss}");
}
@@ -2165,20 +2183,34 @@ namespace NavisworksTransport
// 只有真正相交(距离为0)或在检测间隙内的才算碰撞
if (distance <= tolerance)
{
+ // 🔧 智能容器映射:使用有名称的容器对象而非几何体子对象
+ var mappedAnimatedObject = GetCollisionObjectWithValidIdentity(animatedObject);
+ var mappedCollisionObject = GetCollisionObjectWithValidIdentity(item);
+
+ // 检查是否进行了容器映射
+ bool hasMapping1 = !mappedAnimatedObject.Equals(animatedObject);
+ bool hasMapping2 = !mappedCollisionObject.Equals(item);
+
+ LogManager.Info($"[容器映射] 原始对象: {animatedObject.DisplayName} -> 容器对象: {mappedAnimatedObject.DisplayName} (映射: {hasMapping1})");
+ LogManager.Info($"[容器映射] 原始对象: {item.DisplayName} -> 容器对象: {mappedCollisionObject.DisplayName} (映射: {hasMapping2})");
+
var result = new CollisionResult
{
ClashGuid = Guid.NewGuid(),
- DisplayName = $"纯碰撞检测: {animatedObject.DisplayName} <-> {item.DisplayName}",
+ DisplayName = $"纯碰撞检测: {mappedAnimatedObject.DisplayName} <-> {mappedCollisionObject.DisplayName}",
Status = ClashResultStatus.New,
- Item1 = animatedObject,
- Item2 = item,
+ Item1 = mappedAnimatedObject, // 使用映射后的容器对象
+ Item2 = mappedCollisionObject, // 使用映射后的容器对象
+ OriginalItem1 = animatedObject, // 保存原始几何体对象
+ OriginalItem2 = item, // 保存原始几何体对象
+ HasContainerMapping = hasMapping1 || hasMapping2, // 标记是否进行了映射
CreatedTime = DateTime.Now,
Distance = distance,
Center = CalculateCenter(animatedBoundingBox, itemBoundingBox)
};
results.Add(result);
- LogManager.Info($"检测到碰撞: {animatedObject.DisplayName} <-> {item.DisplayName},距离: {result.Distance:F2}");
+ LogManager.Info($"检测到碰撞: {mappedAnimatedObject.DisplayName} <-> {mappedCollisionObject.DisplayName},距离: {result.Distance:F2}");
}
}
@@ -2297,20 +2329,39 @@ namespace NavisworksTransport
try
{
- // 一次性获取所有对象
- var allItems = Application.ActiveDocument.Models.RootItemDescendantsAndSelf
- .Where(item => item.HasGeometry);
+ // 🔥 修复:搜索所有对象,不过滤HasGeometry,以支持容器型通道节点
+ LogManager.Debug("[通道缓存] 开始搜索所有模型对象(包括容器节点)");
+ var allItems = Application.ActiveDocument.Models.RootItemDescendantsAndSelf;
+ var allItemsList = allItems.ToList();
+ LogManager.Debug($"[通道缓存] 总对象数量: {allItemsList.Count}");
- // 第一轮:找出所有标记为通道的对象
- foreach (var item in allItems)
+ int checkedCount = 0;
+ int channelFound = 0;
+
+ // 第一轮:找出所有标记为通道的对象(包括容器节点)
+ foreach (var item in allItemsList)
{
try
{
+ checkedCount++;
+
+ // 添加调试信息
+ if (item.DisplayName == "Plaza Surround" || item.DisplayName.Contains("Plaza"))
+ {
+ LogManager.Debug($"[通道缓存-调试] 检查对象: {item.DisplayName}, HasGeometry: {item.HasGeometry}");
+ }
+
var elementType = CategoryAttributeManager.GetLogisticsElementType(item);
if (elementType == CategoryAttributeManager.LogisticsElementType.通道)
{
+ channelFound++;
tempChannelObjects.Add(item);
_channelObjectsCache.Add(item);
+ LogManager.Info($"[通道缓存] 发现通道对象: {item.DisplayName}, HasGeometry: {item.HasGeometry}");
+ }
+ else if (item.DisplayName == "Plaza Surround" || item.DisplayName.Contains("Plaza"))
+ {
+ LogManager.Debug($"[通道缓存-调试] {item.DisplayName} 的物流类型: {elementType}");
}
}
catch (Exception ex)
@@ -2319,16 +2370,22 @@ namespace NavisworksTransport
}
}
- // 第二轮:添加通道对象的所有子对象
+ LogManager.Info($"[通道缓存] 第一轮搜索完成: 检查了 {checkedCount} 个对象,找到 {channelFound} 个通道根对象");
+
+ // 第二轮:添加通道对象的所有子对象(只添加有几何体的子对象到缓存)
+ int childrenAdded = 0;
foreach (var channelObject in tempChannelObjects)
{
try
{
+ LogManager.Debug($"[通道缓存] 处理通道对象的子对象: {channelObject.DisplayName}");
+
foreach (var descendant in channelObject.DescendantsAndSelf)
{
- if (descendant.HasGeometry)
+ if (descendant.HasGeometry && _channelObjectsCache.Add(descendant))
{
- _channelObjectsCache.Add(descendant);
+ childrenAdded++;
+ LogManager.Debug($"[通道缓存] 添加通道子对象: {descendant.DisplayName}");
}
}
}
@@ -2341,7 +2398,22 @@ namespace NavisworksTransport
cacheStopwatch.Stop();
LogManager.Info($"通道对象缓存构建完成,耗时: {cacheStopwatch.ElapsedMilliseconds}ms");
LogManager.Info($" - 通道根对象: {tempChannelObjects.Count} 个");
+ LogManager.Info($" - 新增子对象: {childrenAdded} 个");
LogManager.Info($" - 缓存总对象: {_channelObjectsCache.Count} 个");
+
+ // 列出找到的通道根对象
+ if (tempChannelObjects.Count > 0)
+ {
+ LogManager.Info("[通道缓存] 找到的通道根对象列表:");
+ for (int i = 0; i < tempChannelObjects.Count; i++)
+ {
+ LogManager.Info($" {i + 1}. {tempChannelObjects[i].DisplayName} (HasGeometry: {tempChannelObjects[i].HasGeometry})");
+ }
+ }
+ else
+ {
+ LogManager.Warning("[通道缓存] ⚠️ 未找到任何通道根对象,请检查模型中的物流属性设置");
+ }
}
catch (Exception ex)
{
@@ -2411,6 +2483,68 @@ namespace NavisworksTransport
}
}
+
+ ///
+ /// 查找具有有效名称的父级容器对象,用于解决几何体子对象无名称问题
+ ///
+ /// 几何体对象(可能无名称)
+ /// 有名称的容器对象,如果找不到则返回原对象
+ private static ModelItem FindNamedParentContainer(ModelItem geometryItem)
+ {
+ if (geometryItem == null) return null;
+
+ try
+ {
+ var current = geometryItem;
+ int levels = 0; // 防止无限递归
+
+ while (current != null && levels < 10) // 最多向上查找10层
+ {
+ // 检查当前对象是否有有效名称
+ if (!string.IsNullOrEmpty(current.DisplayName) && current.DisplayName.Trim().Length > 0)
+ {
+ LogManager.Debug($"[容器映射] 几何体 -> 容器: '{geometryItem.DisplayName}' -> '{current.DisplayName}' (向上{levels}层)");
+ return current;
+ }
+
+ current = current.Parent;
+ levels++;
+ }
+
+ // 如果没有找到有名称的父级,返回原对象
+ LogManager.Warning($"[容器映射] 未找到有名称的父级容器,使用原对象: {geometryItem.DisplayName}");
+ return geometryItem;
+ }
+ catch (Exception ex)
+ {
+ LogManager.Warning($"[容器映射] 查找父级容器时出错: {ex.Message}");
+ return geometryItem; // 出错时返回原对象
+ }
+ }
+
+ ///
+ /// 增强的碰撞对象信息,包含容器映射
+ ///
+ /// 原始碰撞对象(可能是几何体子对象)
+ /// 包含完整标识信息的对象
+ private static ModelItem GetCollisionObjectWithValidIdentity(ModelItem originalItem)
+ {
+ if (originalItem == null) return null;
+
+ // 如果原对象已经有有效名称,直接返回
+ if (!string.IsNullOrEmpty(originalItem.DisplayName) && originalItem.DisplayName.Trim().Length > 0)
+ {
+ return originalItem;
+ }
+
+ // 否则查找有名称的父级容器
+ var containerObject = FindNamedParentContainer(originalItem);
+
+ LogManager.Info($"[碰撞对象映射] 原对象: '{originalItem.DisplayName}' -> 容器对象: '{containerObject?.DisplayName}'");
+
+ return containerObject ?? originalItem;
+ }
+
///
/// 计算两个包围盒之间的最短距离(真实碰撞距离)
///
@@ -2551,6 +2685,89 @@ namespace NavisworksTransport
}
}
+ ///
+ /// 测试容器映射功能是否正常工作
+ ///
+ public void TestContainerMapping()
+ {
+ try
+ {
+ LogManager.Info("=== [容器映射测试] 开始测试容器映射功能 ===");
+
+ var testResults = new List();
+
+ // 获取一些测试对象
+ var allItems = Application.ActiveDocument.Models.RootItemDescendantsAndSelf
+ .Where(item => item.HasGeometry).Take(10).ToList();
+
+ LogManager.Info($"[容器映射测试] 找到 {allItems.Count} 个几何体对象进行测试");
+
+ foreach (var item in allItems)
+ {
+ try
+ {
+ var originalName = item.DisplayName ?? "无名称";
+ var mappedObject = GetCollisionObjectWithValidIdentity(item);
+ var mappedName = mappedObject?.DisplayName ?? "无名称";
+
+ bool hasMapping = !mappedObject.Equals(item);
+
+ testResults.Add($"原始: '{originalName}' -> 映射: '{mappedName}' (映射: {hasMapping})");
+
+ LogManager.Info($"[容器映射测试] {testResults.Last()}");
+
+ // 验证映射对象的有效性
+ if (hasMapping)
+ {
+ var isValidOriginal = IsModelItemValid(item);
+ var isValidMapped = IsModelItemValid(mappedObject);
+ LogManager.Info($" - 原始对象有效性: {isValidOriginal}");
+ LogManager.Info($" - 映射对象有效性: {isValidMapped}");
+ LogManager.Info($" - 原始对象GUID: {item.InstanceGuid}");
+ LogManager.Info($" - 映射对象GUID: {mappedObject.InstanceGuid}");
+ }
+ }
+ catch (Exception itemEx)
+ {
+ LogManager.Warning($"[容器映射测试] 测试单个对象失败: {itemEx.Message}");
+ }
+ }
+
+ LogManager.Info("=== [容器映射测试] 测试结果汇总 ===");
+ int mappingCount = testResults.Count(r => r.Contains("映射: True"));
+ LogManager.Info($"测试对象总数: {testResults.Count}");
+ LogManager.Info($"发生映射的对象: {mappingCount}");
+ LogManager.Info($"映射成功率: {(mappingCount * 100.0 / Math.Max(testResults.Count, 1)):F1}%");
+
+ // 测试碰撞结果数据结构
+ var testCollision = new CollisionResult
+ {
+ ClashGuid = Guid.NewGuid(),
+ DisplayName = "测试碰撞",
+ Item1 = allItems.FirstOrDefault(),
+ Item2 = allItems.Skip(1).FirstOrDefault(),
+ OriginalItem1 = allItems.FirstOrDefault(),
+ OriginalItem2 = allItems.Skip(1).FirstOrDefault(),
+ HasContainerMapping = true,
+ HasPositionInfo = true
+ };
+
+ LogManager.Info($"[容器映射测试] CollisionResult数据结构测试:");
+ LogManager.Info($" - GetValidItem1: {testCollision.GetValidItem1()?.DisplayName ?? "NULL"}");
+ LogManager.Info($" - GetValidItem2: {testCollision.GetValidItem2()?.DisplayName ?? "NULL"}");
+ LogManager.Info($" - GetOriginalItem1: {testCollision.GetOriginalItem1()?.DisplayName ?? "NULL"}");
+ LogManager.Info($" - GetOriginalItem2: {testCollision.GetOriginalItem2()?.DisplayName ?? "NULL"}");
+ LogManager.Info($" - HasContainerMapping: {testCollision.HasContainerMapping}");
+
+ LogManager.Info("=== [容器映射测试] 测试完成 ===");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"[容器映射测试] 测试失败: {ex.Message}");
+ LogManager.Error($"[容器映射测试] 堆栈跟踪: {ex.StackTrace}");
+ }
+ }
+
// 已删除:ForceShowTestResults 和 CreateDemoTest - 不再需要这些已废弃的方法
///
@@ -2639,10 +2856,23 @@ namespace NavisworksTransport
public double Distance { get; set; }
public DateTime CreatedTime { get; set; }
- // 新增:位置信息用于恢复测试
+ // 位置信息用于恢复测试
public Point3D Item1Position { get; set; }
public Point3D Item2Position { get; set; }
public bool HasPositionInfo { get; set; }
+
+ // 📦 容器映射信息:记录原始几何体对象引用
+ public ModelItem OriginalItem1 { get; set; } // 原始几何体对象
+ public ModelItem OriginalItem2 { get; set; } // 原始几何体对象
+ public bool HasContainerMapping { get; set; } // 标识是否进行了容器映射
+
+ // 📍 获取最终用于ClashDetective的有效对象
+ public ModelItem GetValidItem1() => Item1; // 容器对象,用于ClashDetective选择集
+ public ModelItem GetValidItem2() => Item2; // 容器对象,用于ClashDetective选择集
+
+ // 📍 获取原始几何体对象(用于精确位置信息)
+ public ModelItem GetOriginalItem1() => OriginalItem1 ?? Item1;
+ public ModelItem GetOriginalItem2() => OriginalItem2 ?? Item2;
}
///