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; } ///