完善了碰撞报告

This commit is contained in:
tian 2025-08-31 15:45:21 +08:00
parent 3df7124cf8
commit 6893b7efeb
9 changed files with 441 additions and 178 deletions

View File

@ -12,6 +12,7 @@ using NavisworksTransport.Core;
using NavisworksTransport.PathPlanning;
using NavisworksTransport.Utils;
using NavisworksTransport.UI.WPF.Views;
using NavisworksTransport.Core.Animation;
namespace NavisworksTransport.Commands
{
@ -54,6 +55,17 @@ namespace NavisworksTransport.Commands
}
}
/// <summary>
/// 碰撞数据收集结果
/// </summary>
public class CollisionDataResult
{
public List<CollisionResult> AllCollisions { get; set; } = new List<CollisionResult>();
public int BoundingBoxTestCount { get; set; } // 包围盒测试数量
public int ClashDetectiveCollisionCount { get; set; } // Clash Detective结果数量
public string MovingObjectInfo { get; set; } = string.Empty;
}
/// <summary>
/// 碰撞报告结果类
/// </summary>
@ -65,6 +77,7 @@ namespace NavisworksTransport.Commands
public int IndependentCollisions { get; set; }
public List<CollisionResult> AllCollisions { get; set; } = new List<CollisionResult>();
public long GenerationTimeMs { get; set; }
public string MovingObjectInfo { get; set; } = string.Empty;
}
/// <summary>
@ -99,33 +112,36 @@ namespace NavisworksTransport.Commands
{
UpdateProgress(30, "收集碰撞数据...");
// 收集所有碰撞数据
var allCollisions = CollectAllCollisionData();
result.AllCollisions = allCollisions;
// 收集所有碰撞数据及统计信息
var collisionData = CollectAllCollisionData();
result.AllCollisions = collisionData.AllCollisions;
// 分类统计
result.AnimationCollisions = allCollisions.Count(c => c.DisplayName.Contains("动画") || c.DisplayName.Contains("精确碰撞"));
result.IndependentCollisions = allCollisions.Count(c => c.DisplayName.Contains("独立检测"));
result.TotalCollisions = allCollisions.Count;
// 直接使用收集到的统计数字,无需参数传递!
result.AnimationCollisions = collisionData.BoundingBoxTestCount; // 包围盒测试数量
result.IndependentCollisions = collisionData.ClashDetectiveCollisionCount; // Clash Detective结果数量
result.TotalCollisions = collisionData.ClashDetectiveCollisionCount; // 总数以权威结果为准
result.MovingObjectInfo = collisionData.MovingObjectInfo; // 运动物体信息
LogManager.Info($"碰撞报告计数 - 动画检测: {result.AnimationCollisions}, Clash Detective: {result.IndependentCollisions}, 总计: {result.TotalCollisions}");
UpdateProgress(60, "生成报告内容...");
// 生成报告内容
result.ReportContent = GenerateReportContent(allCollisions, _parameters.Type, _parameters.IncludeDetails);
result.ReportContent = GenerateReportContent(collisionData, _parameters.Type, _parameters.IncludeDetails);
UpdateProgress(90, "处理报告显示...");
// 自动高亮(如果启用)
if (_parameters.AutoHighlight && allCollisions.Count > 0)
if (_parameters.AutoHighlight && collisionData.AllCollisions.Count > 0)
{
try
{
var clashIntegration = ClashDetectiveIntegration.Instance;
if (clashIntegration != null)
var highlightIntegration = ClashDetectiveIntegration.Instance;
if (highlightIntegration != null)
{
var highlightColor = Color.Green; // 绿色 (Navisworks API中没有Orange)
clashIntegration.ManageHighlightsByCategory("report", allCollisions, highlightColor, true);
LogManager.Info($"自动高亮显示报告中的 {allCollisions.Count} 个碰撞对象");
highlightIntegration.ManageHighlightsByCategory("report", collisionData.AllCollisions, highlightColor, true);
LogManager.Info($"自动高亮显示报告中的 {collisionData.AllCollisions.Count} 个碰撞对象");
}
}
catch (Exception ex)
@ -161,15 +177,19 @@ namespace NavisworksTransport.Commands
}
/// <summary>
/// 收集所有碰撞数据
/// 收集所有碰撞数据及统计信息
/// </summary>
private List<CollisionResult> CollectAllCollisionData()
private CollisionDataResult CollectAllCollisionData()
{
var result = new CollisionDataResult();
var allCollisions = new List<CollisionResult>();
try
{
LogManager.Info("开始收集所有碰撞数据...");
LogManager.Info("开始收集所有碰撞数据及统计信息...");
// 收集运动物体信息
result.MovingObjectInfo = GetMovingObjectInfo();
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
var documentClash = doc.GetClash();
@ -177,16 +197,28 @@ namespace NavisworksTransport.Commands
if (documentClash == null)
{
LogManager.Warning("无法获取 Clash Detective 文档,无法收集碰撞数据");
return allCollisions;
return result;
}
// 遍历所有测试
int animationTestCount = 0; // 包围盒测试数量
int totalCollisionCount = 0; // Clash Detective总碰撞数
// 遍历所有测试,区分动画测试和统计信息
foreach (var test in documentClash.TestsData.Tests)
{
if (test is ClashTest clashTest)
{
var testCollisions = ExtractCollisionsFromTest(clashTest);
allCollisions.AddRange(testCollisions);
// 统计信息:如果是动画相关测试,记录包围盒测试数量
if (clashTest.DisplayName.Contains("动画路径碰撞"))
{
animationTestCount = documentClash.TestsData.Tests.Cast<ClashTest>()
.Where(t => t.DisplayName.Contains("动画路径碰撞"))
.Count();
totalCollisionCount += clashTest.Children.Count;
}
}
}
@ -196,14 +228,19 @@ namespace NavisworksTransport.Commands
.Select(g => g.First())
.ToList();
LogManager.Info($"收集到 {allCollisions.Count} 个碰撞记录,去重后 {uniqueCollisions.Count} 个");
result.AllCollisions = uniqueCollisions;
result.BoundingBoxTestCount = animationTestCount;
result.ClashDetectiveCollisionCount = totalCollisionCount > 0 ? totalCollisionCount : uniqueCollisions.Count;
return uniqueCollisions;
LogManager.Info($"收集完成 - 包围盒测试: {result.BoundingBoxTestCount}个, Clash Detective: {result.ClashDetectiveCollisionCount}个, 去重后碰撞: {uniqueCollisions.Count}个");
return result;
}
catch (Exception ex)
{
LogManager.Error($"收集碰撞数据失败: {ex.Message}");
return allCollisions;
result.AllCollisions = allCollisions;
return result;
}
}
@ -270,11 +307,12 @@ namespace NavisworksTransport.Commands
/// <summary>
/// 生成报告内容
/// </summary>
private string GenerateReportContent(List<CollisionResult> collisions,
private string GenerateReportContent(CollisionDataResult collisionData,
CollisionReportParameters.ReportType reportType, bool includeDetails)
{
var report = new StringBuilder();
var now = DateTime.Now;
var collisions = collisionData.AllCollisions;
// 报告头部
report.AppendLine("========================================");
@ -282,19 +320,21 @@ namespace NavisworksTransport.Commands
report.AppendLine("========================================");
report.AppendLine($"生成时间: {now:yyyy年MM月dd日 HH:mm:ss}");
report.AppendLine($"报告类型: {GetReportTypeName(reportType)}");
// 使用收集到的运动物体信息
if (!string.IsNullOrEmpty(collisionData.MovingObjectInfo))
{
report.AppendLine($"{collisionData.MovingObjectInfo}");
}
report.AppendLine();
// 总体统计
report.AppendLine("=== 总体统计 ===");
report.AppendLine($"总碰撞数量: {collisions.Count}");
var animationCollisions = collisions.Where(c => c.DisplayName.Contains("动画") || c.DisplayName.Contains("精确碰撞")).ToList();
var independentCollisions = collisions.Where(c => c.DisplayName.Contains("独立检测")).ToList();
var otherCollisions = collisions.Except(animationCollisions).Except(independentCollisions).ToList();
report.AppendLine($"动画过程碰撞: {animationCollisions.Count}");
report.AppendLine($"独立检测碰撞: {independentCollisions.Count}");
report.AppendLine($"其他碰撞: {otherCollisions.Count}");
// 使用收集到的统计数字
report.AppendLine($"包围盒测试发现: {collisionData.BoundingBoxTestCount}个碰撞 (快速粗略检测结果)");
report.AppendLine($"Clash Detective确认: {collisionData.ClashDetectiveCollisionCount}个碰撞 (精确权威检测结果)");
report.AppendLine($"总碰撞数量: {collisionData.ClashDetectiveCollisionCount}个 (以权威结果为准)");
report.AppendLine();
// 按状态分类
@ -317,56 +357,16 @@ namespace NavisworksTransport.Commands
{
report.AppendLine("=== 详细碰撞信息 ===");
// 按类型分组显示
if (reportType == CollisionReportParameters.ReportType.Comprehensive ||
reportType == CollisionReportParameters.ReportType.Animation)
report.AppendLine("--- 碰撞详情 ---");
foreach (var collision in collisions.Take(10)) // 限制显示数量
{
if (animationCollisions.Count > 0)
{
report.AppendLine("--- 动画过程碰撞 ---");
foreach (var collision in animationCollisions.Take(10)) // 限制显示数量
{
AppendCollisionDetail(report, collision);
}
if (animationCollisions.Count > 10)
{
report.AppendLine($"... 还有 {animationCollisions.Count - 10} 个动画碰撞未显示");
}
report.AppendLine();
}
AppendCollisionDetail(report, collision);
}
if (reportType == CollisionReportParameters.ReportType.Comprehensive ||
reportType == CollisionReportParameters.ReportType.Independent)
if (collisions.Count > 10)
{
if (independentCollisions.Count > 0)
{
report.AppendLine("--- 独立检测碰撞 ---");
foreach (var collision in independentCollisions.Take(10)) // 限制显示数量
{
AppendCollisionDetail(report, collision);
}
if (independentCollisions.Count > 10)
{
report.AppendLine($"... 还有 {independentCollisions.Count - 10} 个独立检测碰撞未显示");
}
report.AppendLine();
}
}
if (otherCollisions.Count > 0)
{
report.AppendLine("--- 其他碰撞 ---");
foreach (var collision in otherCollisions.Take(5))
{
AppendCollisionDetail(report, collision);
}
if (otherCollisions.Count > 5)
{
report.AppendLine($"... 还有 {otherCollisions.Count - 5} 个其他碰撞未显示");
}
report.AppendLine();
report.AppendLine($"... 还有 {collisions.Count - 10} 个碰撞未显示");
}
report.AppendLine();
}
// 建议和结论
@ -383,14 +383,7 @@ namespace NavisworksTransport.Commands
report.AppendLine(" 3. 考虑增加临时障碍物标记");
report.AppendLine(" 4. 重新评估物流流程设计");
if (animationCollisions.Count > independentCollisions.Count)
{
report.AppendLine(" 5. 动画过程碰撞较多,建议检查实时检测设置");
}
else if (independentCollisions.Count > animationCollisions.Count)
{
report.AppendLine(" 5. 独立检测发现更多碰撞,建议增强实时监控");
}
report.AppendLine(" 5. 建议进行更详细的碰撞检测分析");
}
report.AppendLine();
@ -409,9 +402,15 @@ namespace NavisworksTransport.Commands
var item1Name = collision.Item1?.DisplayName ?? "未知对象";
var item2Name = collision.Item2?.DisplayName ?? "未知对象";
// 转换距离单位为米
var distanceInMeters = ConvertDistanceToMeters(collision.Distance);
report.AppendLine($"• {item1Name} ↔ {item2Name}");
report.AppendLine($" 状态: {GetStatusName(collision.Status)}, 距离: {collision.Distance:F3}m");
report.AppendLine($" 位置: ({collision.Center.X:F2}, {collision.Center.Y:F2}, {collision.Center.Z:F2})");
report.AppendLine($" 状态: {GetStatusName(collision.Status)}, 距离: {distanceInMeters:F3}m");
// 转换位置坐标单位为米
var centerInMeters = ConvertPointToMeters(collision.Center);
report.AppendLine($" 位置: ({centerInMeters.X:F2}, {centerInMeters.Y:F2}, {centerInMeters.Z:F2})m");
report.AppendLine($" GUID: {collision.ClashGuid}");
report.AppendLine();
}
@ -593,5 +592,92 @@ namespace NavisworksTransport.Commands
AutoHighlight = autoHighlight
});
}
/// <summary>
/// 获取运动物体信息
/// </summary>
private string GetMovingObjectInfo()
{
try
{
LogManager.Debug("[GetMovingObjectInfo] 开始获取运动物体信息");
// 尝试获取当前选中的模型项作为运动对象
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
LogManager.Debug($"[GetMovingObjectInfo] 文档: {doc != null}, 选择: {doc?.CurrentSelection != null}");
if (doc?.CurrentSelection?.SelectedItems?.Count > 0)
{
var selectedItems = doc.CurrentSelection.SelectedItems;
LogManager.Debug($"[GetMovingObjectInfo] 选中项数量: {selectedItems.Count}");
if (selectedItems.Count == 1)
{
var item = selectedItems.First();
var displayName = item?.DisplayName ?? "未知对象";
LogManager.Debug($"[GetMovingObjectInfo] 单个对象名称: '{displayName}'");
return $"运动对象: {displayName}";
}
else
{
var displayNames = selectedItems.Take(3).Select(item => item?.DisplayName ?? "未知对象");
var summary = string.Join(", ", displayNames);
if (selectedItems.Count > 3)
{
summary += $" 等{selectedItems.Count}个对象";
}
LogManager.Debug($"[GetMovingObjectInfo] 多个对象摘要: '{summary}'");
return $"运动对象: {summary}";
}
}
LogManager.Debug("[GetMovingObjectInfo] 未选择对象,返回默认信息");
return "运动对象: 物流运输对象 (建议先选择要运动的模型元素)";
}
catch (Exception ex)
{
LogManager.Error($"获取运动物体信息失败: {ex.Message}");
return "运动对象: 获取信息失败";
}
}
/// <summary>
/// 将距离转换为米
/// </summary>
private double ConvertDistanceToMeters(double distance)
{
try
{
var conversionFactor = UnitsConverter.GetUnitsToMetersConversionFactor();
return distance * conversionFactor;
}
catch (Exception ex)
{
LogManager.Warning($"距离单位转换失败: {ex.Message},使用原始值");
return distance;
}
}
/// <summary>
/// 将3D点坐标转换为米
/// </summary>
private Point3D ConvertPointToMeters(Point3D point)
{
try
{
var conversionFactor = UnitsConverter.GetUnitsToMetersConversionFactor();
return new Point3D(
point.X * conversionFactor,
point.Y * conversionFactor,
point.Z * conversionFactor
);
}
catch (Exception ex)
{
LogManager.Warning($"坐标单位转换失败: {ex.Message},使用原始值");
return point;
}
}
}
}

View File

@ -29,6 +29,26 @@ namespace NavisworksTransport
// 几何对象列表缓存,用于避免重复获取对象列表
private static List<ModelItem> _allGeometryItemsCache = null;
// 碰撞检测计数器
private int _animationCollisionCount = 0; // 动画过程中简单包围盒检测的碰撞数量
private int _clashDetectiveCollisionCount = 0; // Clash Detective最终检测的碰撞数量
/// <summary>
/// 动画过程中检测到的碰撞数量(仅供参考统计)
/// </summary>
public int AnimationCollisionCount
{
get { return _animationCollisionCount; }
}
/// <summary>
/// Clash Detective检测到的权威碰撞数量
/// </summary>
public int ClashDetectiveCollisionCount
{
get { return _clashDetectiveCollisionCount; }
}
/// <summary>
/// 单例实例
@ -839,6 +859,22 @@ namespace NavisworksTransport
LogManager.Error($"动画结束后自动高亮失败: {highlightEx.Message}");
}
// 更新Clash Detective碰撞计数器 - 统计实际创建的测试数量
var finalClashDetectiveCount = 0;
if (_documentClash != null)
{
// 计算所有动画相关测试的碰撞总数
var animationTests = _documentClash.TestsData.Tests.Cast<ClashTest>()
.Where(t => t.DisplayName.Contains("动画路径碰撞") || t.DisplayName.Contains("动画碰撞"))
.ToList();
finalClashDetectiveCount = animationTests.Sum(t => t.Children.Count);
LogManager.Info($"统计Clash Detective最终碰撞数量: {animationTests.Count}个测试,总共{finalClashDetectiveCount}个碰撞");
}
_clashDetectiveCollisionCount = finalClashDetectiveCount;
LogManager.Info($"Clash Detective碰撞计数器已更新: {_clashDetectiveCollisionCount}");
// 清空缓存
_cachedResults.Clear();
LogManager.Info("=== 动画碰撞测试(位置恢复方案)完成 ===");
@ -2247,6 +2283,10 @@ namespace NavisworksTransport
{
LogManager.Info($"未发现碰撞");
}
// 更新动画碰撞计数器
_animationCollisionCount = results.Count;
LogManager.Info($"动画碰撞计数器已更新: {_animationCollisionCount}");
}
catch (Exception ex)
{

View File

@ -95,11 +95,6 @@ namespace NavisworksTransport.PathPlanning
// 统计变量
var totalItems = modelItems?.Count() ?? 0;
var itemsWithGeometry = 0;
var channelItemsExcluded = 0;
var itemsWithoutBounds = 0;
var itemsOutOfBounds = 0;
var itemsAddedToHash = 0;
LogManager.Info($"【垂直扫描处理器】 输入统计 - 总模型项: {totalItems}, 将排除通道元素: {channelItemsSet.Count}");
LogManager.Info($"【垂直扫描处理器】 扫描边界: [{bounds.Min.X:F1},{bounds.Min.Y:F1},{bounds.Min.Z:F1}] - [{bounds.Max.X:F1},{bounds.Max.Y:F1},{bounds.Max.Z:F1}]");

View File

@ -8,6 +8,13 @@ namespace NavisworksTransport.UI.WPF.Converters
/// <summary>
/// 布尔值到可见性的转换器
/// </summary>
/// <summary>
/// 通用值到可见性转换器
/// - 布尔值true/false → Visible/Collapsed
/// - 字符串:非空非白字符 → Visible空/null → Collapsed
/// - 数字:非零 → Visible零 → Collapsed
/// - 对象非null → Visiblenull → Collapsed
/// </summary>
public class BoolToVisibilityConverter : IValueConverter
{
/// <summary>
@ -17,21 +24,52 @@ namespace NavisworksTransport.UI.WPF.Converters
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isVisible = false;
// 处理布尔值
if (value is bool boolValue)
{
// 检查是否需要反向转换
bool isInverse = parameter?.ToString()?.Equals("Inverse", StringComparison.OrdinalIgnoreCase) == true;
if (isInverse)
{
return boolValue ? Visibility.Collapsed : Visibility.Visible;
}
else
{
return boolValue ? Visibility.Visible : Visibility.Collapsed;
}
isVisible = boolValue;
}
// 处理字符串 - 非空非白字符字符串为true
else if (value is string stringValue)
{
isVisible = !string.IsNullOrWhiteSpace(stringValue);
}
// 处理数字类型
else if (value is int intValue)
{
isVisible = intValue != 0;
}
else if (value is long longValue)
{
isVisible = longValue != 0;
}
else if (value is double doubleValue)
{
isVisible = Math.Abs(doubleValue) > double.Epsilon;
}
else if (value is float floatValue)
{
isVisible = Math.Abs(floatValue) > float.Epsilon;
}
// 处理其他对象 - 非null为true
else
{
isVisible = value != null;
}
// 检查是否需要反向转换
bool isInverse = parameter?.ToString()?.Equals("Inverse", StringComparison.OrdinalIgnoreCase) == true;
if (isInverse)
{
return isVisible ? Visibility.Collapsed : Visibility.Visible;
}
else
{
return isVisible ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

View File

@ -82,4 +82,44 @@ namespace NavisworksTransport.UI.WPF.Converters
return true;
}
}
/// <summary>
/// 布尔值到可见性转换器(标准命名)
/// </summary>
/// <summary>
/// 严格布尔值到可见性转换器(只接受布尔值)
/// </summary>
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// 只接受严格的布尔值
if (value is bool boolValue)
{
// 检查是否需要反向转换
bool isInverse = parameter?.ToString()?.Equals("Inverse", StringComparison.OrdinalIgnoreCase) == true;
if (isInverse)
{
return boolValue ? Visibility.Collapsed : Visibility.Visible;
}
else
{
return boolValue ? Visibility.Visible : Visibility.Collapsed;
}
}
// 非布尔值直接返回Collapsed
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Visibility visibility)
{
return visibility == Visibility.Visible;
}
return false;
}
}
}

View File

@ -963,7 +963,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
if (success)
{
var cacheStats = _logisticsAnimationManager.GetCacheStats();
GenerationStatus = $"动画对象分析完成 - {cacheStats}";
GenerationStatus = $"动画对象分析完成";
LogManager.Info($"[缓存预计算] 预计算成功 - {cacheStats}");
}
else
@ -1348,7 +1348,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
if (reportData.IsValid)
{
CollisionSummary = $"共找到 {reportData.TotalTests} 个测试,{reportData.TotalCollisions} 个碰撞点";
// 直接使用报告数据统计
CollisionSummary = $"动画检测: {reportData.TotalTests}个 | Clash Detective权威结果: {reportData.TotalCollisions}个";
}
else
{
@ -1362,7 +1363,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 调用ViewCollisionReportCommand显示详细报告窗口
try
{
// 创建综合碰撞报告命令并执行
// 创建综合碰撞报告命令(现在不需要传递参数了!)
var reportCommand = NavisworksTransport.Commands.ViewCollisionReportCommand.CreateComprehensive(autoHighlight: false);
// 执行命令UI显示会在正确的线程中处理

View File

@ -12,6 +12,7 @@ using System.IO;
using System.Text;
using Microsoft.Win32;
using System.Threading.Tasks;
using Autodesk.Navisworks.Api;
namespace NavisworksTransport.UI.WPF.ViewModels
{
@ -51,7 +52,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public int TotalCollisions { get; set; }
public int AnimationCollisions { get; set; }
public int IndependentCollisions { get; set; }
public int OtherCollisions { get; set; }
public int NewCollisions { get; set; }
public int ActiveCollisions { get; set; }
public int ReviewedCollisions { get; set; }
@ -73,13 +73,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private CollisionReportStatistics _statistics;
private ObservableCollection<CollisionReportItem> _animationCollisions;
private ObservableCollection<CollisionReportItem> _independentCollisions;
private ObservableCollection<CollisionReportItem> _otherCollisions;
private string _progressMessage;
private int _progressPercentage;
private bool _isGenerating;
private bool _hasCollisions;
private string _summaryMessage;
private string _recommendationMessage;
private string _movingObjectInfo;
#endregion
@ -130,14 +130,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
set => SetProperty(ref _independentCollisions, value);
}
/// <summary>
/// 其他碰撞列表
/// </summary>
public ObservableCollection<CollisionReportItem> OtherCollisions
{
get => _otherCollisions;
set => SetProperty(ref _otherCollisions, value);
}
/// <summary>
/// 进度消息
@ -193,6 +185,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels
set => SetProperty(ref _recommendationMessage, value);
}
/// <summary>
/// 运动物体信息
/// </summary>
public string MovingObjectInfo
{
get => _movingObjectInfo;
set => SetProperty(ref _movingObjectInfo, value);
}
#endregion
#region
@ -226,7 +227,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 初始化集合
AnimationCollisions = new ObservableCollection<CollisionReportItem>();
IndependentCollisions = new ObservableCollection<CollisionReportItem>();
OtherCollisions = new ObservableCollection<CollisionReportItem>();
Statistics = new CollisionReportStatistics();
@ -269,7 +269,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 清空现有数据
AnimationCollisions.Clear();
IndependentCollisions.Clear();
OtherCollisions.Clear();
// 设置运动物体信息
MovingObjectInfo = reportResult.MovingObjectInfo;
// 更新统计信息
UpdateStatistics(reportResult);
@ -328,7 +330,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
TotalCollisions = reportResult.TotalCollisions,
AnimationCollisions = reportResult.AnimationCollisions,
IndependentCollisions = reportResult.IndependentCollisions,
OtherCollisions = reportResult.TotalCollisions - reportResult.AnimationCollisions - reportResult.IndependentCollisions,
GenerationTime = $"{reportResult.GenerationTimeMs}ms",
ReportType = "综合碰撞报告"
};
@ -352,39 +353,20 @@ namespace NavisworksTransport.UI.WPF.ViewModels
if (collisions == null || collisions.Count == 0)
return;
var animationList = new List<CollisionReportItem>();
var independentList = new List<CollisionReportItem>();
var otherList = new List<CollisionReportItem>();
foreach (var collision in collisions)
{
var item = CreateCollisionReportItem(collision);
if (collision.DisplayName.Contains("动画") || collision.DisplayName.Contains("精确碰撞"))
{
animationList.Add(item);
}
else if (collision.DisplayName.Contains("独立检测"))
{
independentList.Add(item);
}
else
{
otherList.Add(item);
}
independentList.Add(item);
}
// 更新UI集合
SafeExecute(() =>
{
foreach (var item in animationList.OrderBy(i => i.Title))
AnimationCollisions.Add(item);
foreach (var item in independentList.OrderBy(i => i.Title))
IndependentCollisions.Add(item);
foreach (var item in otherList.OrderBy(i => i.Title))
OtherCollisions.Add(item);
}, "更新碰撞报告项目列表", true);
}
@ -393,20 +375,27 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// </summary>
private CollisionReportItem CreateCollisionReportItem(CollisionResult collision)
{
var item1Name = collision.Item1?.DisplayName ?? "未知对象";
var item2Name = collision.Item2?.DisplayName ?? "未知对象";
return new CollisionReportItem
// 获取元素名称 - 向上
var item1Name = NavisworksApiHelper.GetModelItemNameWithAncestorFallback(collision.Item1);
var item2Name = NavisworksApiHelper.GetModelItemNameWithAncestorFallback(collision.Item2);
var title = $"{item1Name} ↔ {item2Name}";
var item = new CollisionReportItem
{
Title = $"{item1Name} ↔ {item2Name}",
Description = collision.DisplayName,
Title = string.IsNullOrEmpty(title.Trim().Replace("↔", "").Trim()) ? "【空标题测试】" : title,
Description = collision.DisplayName ?? "【空描述测试】",
StatusText = GetStatusDisplayText(collision.Status),
StatusColor = GetStatusColor(collision.Status),
Details = $"距离: {collision.Distance:F3}m\n位置: ({collision.Center.X:F2}, {collision.Center.Y:F2}, {collision.Center.Z:F2})\nGUID: {collision.ClashGuid}",
CollisionData = collision
};
return item;
}
/// <summary>
/// 获取状态显示文本
/// </summary>
@ -486,6 +475,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
/// <summary>
/// 设置空报告状态
/// </summary>
@ -579,14 +569,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
report.AppendLine("========================================");
report.AppendLine($"生成时间: {now:yyyy年MM月dd日 HH:mm:ss}");
report.AppendLine($"报告类型: {Statistics.ReportType}");
report.AppendLine();
// 总体统计
report.AppendLine("=== 总体统计 ===");
report.AppendLine($"总碰撞数量: {Statistics.TotalCollisions}");
report.AppendLine($"动画过程碰撞: {Statistics.AnimationCollisions}");
report.AppendLine($"独立检测碰撞: {Statistics.IndependentCollisions}");
report.AppendLine($"其他碰撞: {Statistics.OtherCollisions}");
report.AppendLine($"碰撞数量: {Statistics.TotalCollisions}");
report.AppendLine($"动画检测碰撞(参考): {Statistics.AnimationCollisions}");
report.AppendLine($"ClashDetective检测碰撞: {Statistics.IndependentCollisions}");
report.AppendLine();
// 按状态分类
@ -598,12 +586,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
report.AppendLine($"已解决: {Statistics.ResolvedCollisions}");
report.AppendLine();
// 运动物体信息
if (!string.IsNullOrEmpty(MovingObjectInfo))
{
report.AppendLine($"{MovingObjectInfo}");
}
report.AppendLine();
// 详细碰撞信息
if (HasCollisions)
{
AddCollisionDetailsToTextReport(report, "动画过程碰撞", AnimationCollisions);
AddCollisionDetailsToTextReport(report, "独立检测碰撞", IndependentCollisions);
AddCollisionDetailsToTextReport(report, "其他碰撞", OtherCollisions);
}
// 总结和建议

View File

@ -135,7 +135,7 @@ NavisworksTransport 碰撞检测报告对话框 - 采用与主界面一致的Nav
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Title}" Style="{StaticResource CollisionTitleStyle}"/>
<TextBlock Grid.Row="0" Text="{Binding Title}" Style="{StaticResource CollisionDescriptionStyle}" FontWeight="SemiBold"/>
<Border Grid.Row="1" Style="{StaticResource StatusTagStyle}" Background="{Binding StatusColor}">
<TextBlock Text="{Binding StatusText}" Style="{StaticResource StatusTextStyle}"/>
@ -191,7 +191,7 @@ NavisworksTransport 碰撞检测报告对话框 - 采用与主界面一致的Nav
<!-- 总体统计信息 -->
<Label Content="总体统计" Style="{StaticResource SectionHeaderStyle}"/>
<UniformGrid Columns="4" Margin="0,0,0,15">
<UniformGrid Columns="3" Margin="0,0,0,15">
<Border Style="{StaticResource StatisticItemStyle}">
<Grid>
<Grid.RowDefinitions>
@ -222,16 +222,6 @@ NavisworksTransport 碰撞检测报告对话框 - 采用与主界面一致的Nav
<TextBlock Grid.Row="1" Text="{Binding Statistics.IndependentCollisions}" Style="{StaticResource StatisticValueStyle}"/>
</Grid>
</Border>
<Border Style="{StaticResource StatisticItemStyle}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="其他碰撞" Style="{StaticResource StatisticLabelStyle}"/>
<TextBlock Grid.Row="1" Text="{Binding Statistics.OtherCollisions}" Style="{StaticResource StatisticValueStyle}"/>
</Grid>
</Border>
</UniformGrid>
<!-- 按状态分类统计 -->
@ -269,6 +259,27 @@ NavisworksTransport 碰撞检测报告对话框 - 采用与主界面一致的Nav
</Border>
</UniformGrid>
<!-- 运动物体信息 -->
<Border Style="{StaticResource StatisticItemStyle}"
Margin="0,0,0,15"
Background="#FFF0F8FF"
BorderBrush="#FFB0D4F1">
<StackPanel HorizontalAlignment="Center">
<TextBlock Text="🚛 运动物体信息"
FontSize="11"
FontWeight="SemiBold"
Foreground="{StaticResource NavisworksPrimaryBrush}"
HorizontalAlignment="Center"
Margin="0,0,0,5"/>
<TextBlock Text="{Binding MovingObjectInfo}"
FontSize="12"
FontWeight="Normal"
Foreground="#FF333333"
HorizontalAlignment="Center"
TextWrapping="Wrap"/>
</StackPanel>
</Border>
<!-- 总结信息 -->
<Label Content="总结与建议" Style="{StaticResource SectionHeaderStyle}"/>
<Border Style="{StaticResource StatisticItemStyle}" Margin="0,0,0,10">
@ -288,14 +299,6 @@ NavisworksTransport 碰撞检测报告对话框 - 采用与主界面一致的Nav
<!-- 详细碰撞信息 -->
<StackPanel Visibility="{Binding HasCollisions, Converter={StaticResource BooleanToVisibilityConverter}}">
<!-- 动画过程碰撞 -->
<StackPanel Visibility="{Binding AnimationCollisions.Count, Converter={StaticResource CountToVisibilityConverter}}">
<Label Content="动画过程碰撞" Style="{StaticResource SectionHeaderStyle}"/>
<ItemsControl ItemsSource="{Binding AnimationCollisions}"
ItemTemplate="{StaticResource CollisionItemTemplate}"
Margin="0,0,0,10"/>
</StackPanel>
<!-- 独立检测碰撞 -->
<StackPanel Visibility="{Binding IndependentCollisions.Count, Converter={StaticResource CountToVisibilityConverter}}">
<Label Content="独立检测碰撞" Style="{StaticResource SectionHeaderStyle}"/>
@ -304,13 +307,6 @@ NavisworksTransport 碰撞检测报告对话框 - 采用与主界面一致的Nav
Margin="0,0,0,10"/>
</StackPanel>
<!-- 其他碰撞 -->
<StackPanel Visibility="{Binding OtherCollisions.Count, Converter={StaticResource CountToVisibilityConverter}}">
<Label Content="其他碰撞" Style="{StaticResource SectionHeaderStyle}"/>
<ItemsControl ItemsSource="{Binding OtherCollisions}"
ItemTemplate="{StaticResource CollisionItemTemplate}"
Margin="0,0,0,10"/>
</StackPanel>
</StackPanel>

View File

@ -97,5 +97,78 @@ namespace NavisworksTransport.Utils
System.Windows.Application.Current.Dispatcher.Invoke(operation);
}
}
/// <summary>
/// 获取ModelItem的显示名称支持向上溯源父节点
/// 如果当前节点没有名称,会向上查找父节点直到找到有名称的节点
/// </summary>
/// <param name="item">要获取名称的ModelItem</param>
/// <param name="maxDepth">最大向上查找深度,防止无限递归</param>
/// <returns>元素的显示名称</returns>
public static string GetModelItemNameWithAncestorFallback(ModelItem item, int maxDepth = 10)
{
if (item == null) return "未知对象";
try
{
var current = item;
int depth = 0;
while (current != null && depth < maxDepth)
{
// 只查找DisplayName
if (!string.IsNullOrEmpty(current.DisplayName))
{
return current.DisplayName;
}
// 向上一级父节点继续查找
current = current.Parent;
depth++;
}
// 如果所有父节点都没有DisplayName返回默认名称
LogManager.Debug($"[元素名称获取] 向上查找{depth}层后仍未找到DisplayName返回默认名称");
return depth > 0 ? "未命名对象(已溯源)" : "未命名对象";
}
catch (Exception ex)
{
LogManager.Error($"获取ModelItem DisplayName失败: {ex.Message}");
return "获取失败";
}
}
/// <summary>
/// 获取ModelItem的直接显示名称不溯源父节点
/// 仅从当前节点获取名称,适用于不需要父节点信息的场景
/// </summary>
/// <param name="item">要获取名称的ModelItem</param>
/// <returns>元素的显示名称</returns>
public static string GetModelItemName(ModelItem item)
{
if (item == null) return "未知对象";
try
{
// 1. 尝试DisplayName
if (!string.IsNullOrEmpty(item.DisplayName))
{
return item.DisplayName;
}
// 2. 尝试ClassDisplayName
if (!string.IsNullOrEmpty(item.ClassDisplayName))
{
return item.ClassDisplayName;
}
return "未命名对象";
}
catch (Exception ex)
{
LogManager.Error($"获取ModelItem名称失败: {ex.Message}");
return "获取失败";
}
}
}
}