修复碰撞报告无结果的问题(碰撞需要找到容器节点)

This commit is contained in:
tian 2025-08-27 20:53:09 +08:00
parent 0943637f5a
commit 2d1c835398

View File

@ -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
}
}
/// <summary>
/// 查找具有有效名称的父级容器对象,用于解决几何体子对象无名称问题
/// </summary>
/// <param name="geometryItem">几何体对象(可能无名称)</param>
/// <returns>有名称的容器对象,如果找不到则返回原对象</returns>
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; // 出错时返回原对象
}
}
/// <summary>
/// 增强的碰撞对象信息,包含容器映射
/// </summary>
/// <param name="originalItem">原始碰撞对象(可能是几何体子对象)</param>
/// <returns>包含完整标识信息的对象</returns>
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;
}
/// <summary>
/// 计算两个包围盒之间的最短距离(真实碰撞距离)
/// </summary>
@ -2551,6 +2685,89 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 测试容器映射功能是否正常工作
/// </summary>
public void TestContainerMapping()
{
try
{
LogManager.Info("=== [容器映射测试] 开始测试容器映射功能 ===");
var testResults = new List<string>();
// 获取一些测试对象
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 - 不再需要这些已废弃的方法
/// <summary>
@ -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;
}
/// <summary>