实现历史碰撞报告生成,调整时间格式显示,重构相关UI组件

This commit is contained in:
tian 2026-01-09 11:28:49 +08:00
parent a40e52f538
commit df2c09a167
6 changed files with 292 additions and 314 deletions

View File

@ -108,6 +108,7 @@ namespace NavisworksTransport.Commands
#endregion
private readonly CollisionReportParameters _parameters;
private string _specificTestName = null; // 指定的测试名称(用于历史报告)
public GenerateCollisionReportCommand(CollisionReportParameters parameters = null)
: base("GenerateCollisionReport", "生成碰撞报告", "生成并显示详细的碰撞检测报告")
@ -115,6 +116,14 @@ namespace NavisworksTransport.Commands
_parameters = parameters ?? new CollisionReportParameters();
}
/// <summary>
/// 设置要生成报告的测试名称
/// </summary>
public void SetTestName(string testName)
{
_specificTestName = testName;
}
protected override PathPlanningResult ValidateParameters()
{
return _parameters.ValidateParameters();
@ -126,39 +135,40 @@ namespace NavisworksTransport.Commands
UpdateProgress(10, "开始生成碰撞报告...");
// 检查缓存
// 获取ClashDetectiveIntegration实例
var clashIntegration = ClashDetectiveIntegration.Instance;
var currentTestName = clashIntegration?.CurrentTestName;
if (!string.IsNullOrEmpty(currentTestName))
// 使用指定的测试名称(如果有),否则使用当前测试名称
var targetTestName = _specificTestName ?? clashIntegration?.CurrentTestName;
if (string.IsNullOrEmpty(targetTestName))
{
lock (_cacheLock)
{
if (_reportCache.ContainsKey(currentTestName))
{
var cachedResult = _reportCache[currentTestName];
LogManager.Info($"使用缓存的碰撞报告: {currentTestName}");
UpdateProgress(100, "使用缓存报告");
// 显示缓存的报告
ShowReport(cachedResult);
var cachedMessage = cachedResult.TotalCollisions > 0 ?
$"碰撞报告显示完成(缓存):发现 {cachedResult.TotalCollisions} 个碰撞" :
"碰撞报告显示完成(缓存):未发现碰撞";
return PathPlanningResult<CollisionReportResult>.Success(cachedResult, cachedMessage);
}
else
{
LogManager.Debug($"缓存中未找到测试: {currentTestName}");
}
}
return PathPlanningResult.Failure("无法确定测试名称,请先运行碰撞检测或选择历史记录");
}
else
// 检查缓存
lock (_cacheLock)
{
LogManager.Warning("无法获取测试名称,跳过缓存检查");
if (_reportCache.ContainsKey(targetTestName))
{
var cachedResult = _reportCache[targetTestName];
LogManager.Info($"使用缓存的碰撞报告: {targetTestName}");
UpdateProgress(100, "使用缓存报告");
// 显示缓存的报告
ShowReport(cachedResult);
var cachedMessage = cachedResult.TotalCollisions > 0 ?
$"碰撞报告显示完成(缓存):发现 {cachedResult.TotalCollisions} 个碰撞" :
"碰撞报告显示完成(缓存):未发现碰撞";
return PathPlanningResult<CollisionReportResult>.Success(cachedResult, cachedMessage);
}
else
{
LogManager.Debug($"缓存中未找到测试: {targetTestName}");
}
}
var result = new CollisionReportResult();
@ -225,13 +235,10 @@ namespace NavisworksTransport.Commands
ShowReport(result);
// 将报告结果缓存起来
if (!string.IsNullOrEmpty(currentTestName))
lock (_cacheLock)
{
lock (_cacheLock)
{
_reportCache[currentTestName] = result;
LogManager.Info($"碰撞报告已缓存: {currentTestName}, 缓存总数: {_reportCache.Count}");
}
_reportCache[targetTestName] = result;
LogManager.Info($"碰撞报告已缓存: {targetTestName}, 缓存总数: {_reportCache.Count}");
}
}
catch (OperationCanceledException)
@ -255,6 +262,40 @@ namespace NavisworksTransport.Commands
#region
/// <summary>
/// 从缓存获取报告
/// </summary>
public static CollisionReportResult GetReportFromCache(string testName)
{
if (string.IsNullOrEmpty(testName))
return null;
lock (_cacheLock)
{
if (_reportCache.ContainsKey(testName))
{
LogManager.Info($"从缓存获取报告: {testName}");
return _reportCache[testName];
}
}
return null;
}
/// <summary>
/// 缓存报告
/// </summary>
public static void CacheReport(string testName, CollisionReportResult reportResult)
{
if (string.IsNullOrEmpty(testName) || reportResult == null)
return;
lock (_cacheLock)
{
_reportCache[testName] = reportResult;
LogManager.Info($"报告已缓存: {testName}, 缓存总数: {_reportCache.Count}");
}
}
/// <summary>
/// 清理过期缓存(可选功能)
/// </summary>
@ -291,29 +332,31 @@ namespace NavisworksTransport.Commands
// 从动画管理器获取当前路径名称
var animationManager = Core.Animation.PathAnimationManager.GetInstance();
var currentPathName = animationManager?.PathName;
var currentTestName = clashIntegration?.CurrentTestName;
// 使用指定的测试名称(如果有),否则使用当前测试名称
var targetTestName = _specificTestName ?? clashIntegration?.CurrentTestName;
if (string.IsNullOrEmpty(currentTestName))
if (string.IsNullOrEmpty(targetTestName))
{
throw new InvalidOperationException("无法获取当前测试名称,请先运行碰撞检测");
throw new InvalidOperationException("无法确定测试名称,请先运行碰撞检测或选择历史记录");
}
// 直接从缓存获取ClashDetective结果
var testCollisionsRaw = clashIntegration.GetCurrentPathClashResults(currentTestName);
// 获取碰撞结果(先检查缓存,没有则从数据库加载)
var testCollisionsRaw = clashIntegration.GetCurrentPathClashResults(targetTestName);
if (testCollisionsRaw == null || testCollisionsRaw.Count == 0)
{
throw new InvalidOperationException($"未找到测试 '{currentTestName}' 的ClashDetective碰撞结果");
throw new InvalidOperationException($"未找到测试 '{targetTestName}' 的ClashDetective碰撞结果");
}
LogManager.Info($"从缓存获取ClashDetective结果: {testCollisionsRaw.Count}个碰撞,测试名称:{currentTestName}");
LogManager.Info($"从缓存获取ClashDetective结果: {testCollisionsRaw.Count}个碰撞,测试名称:{targetTestName}");
// 直接使用缓存中的CollisionResult对象已经过复合对象处理和去重
allCollisions.AddRange(testCollisionsRaw);
// 统计碰撞总数
result.ClashDetectiveCollisionCount = testCollisionsRaw.Count;
LogManager.Debug($"测试 '{currentTestName}' 包含 {testCollisionsRaw.Count} 个碰撞");
LogManager.Debug($"测试 '{targetTestName}' 包含 {testCollisionsRaw.Count} 个碰撞");
// 统计被撞物体(缓存中已经是复合对象,不需要再去重)
var nameCountDict = new Dictionary<string, int>();

View File

@ -98,7 +98,6 @@ namespace NavisworksTransport
private ClashDetectiveIntegration()
{
_currentCollisions = new List<ClashResult>();
_cachedResults = new List<CollisionResult>();
// 自动初始化 Clash Detective 集成
try
@ -124,26 +123,7 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 创建碰撞快照(动画结束后一次性更新结果)
/// </summary>
public void CreateCollisionSnapshot(List<CollisionResult> results)
{
try
{
if (_documentClash == null)
return;
// 缓存结果,等动画结束后统一处理
CacheCollisionResults(results);
}
catch (Exception ex)
{
LogManager.Error($"创建实时碰撞快照失败: {ex.Message}");
}
}
private List<CollisionResult> _cachedResults = new List<CollisionResult>();
private List<CollisionResult> _deduplicatedCollisionResults = new List<CollisionResult>(); // 去重后的预计算碰撞结果
private readonly object _resultsLock = new object();
// ClashDetective测试结果缓存pathName -> List<CollisionResult>
@ -152,13 +132,14 @@ namespace NavisworksTransport
private readonly object _clashResultsCacheLock = new object();
/// <summary>
/// 缓存碰撞结果
/// 获取去重后的预计算碰撞结果(第一次去重,按碰撞对象对去重)
/// </summary>
private void CacheCollisionResults(List<CollisionResult> results)
public List<CollisionResult> GetDeduplicatedCollisionResults()
{
if (results != null && results.Count > 0)
lock (_resultsLock)
{
_cachedResults.AddRange(results);
LogManager.Debug($"[GetDeduplicatedCollisionResults] 当前去重缓存数量: {_deduplicatedCollisionResults.Count}");
return new List<CollisionResult>(_deduplicatedCollisionResults);
}
}
@ -263,7 +244,7 @@ namespace NavisworksTransport
/// </summary>
/// <param name="testName">测试名称</param>
/// <returns>碰撞结果列表如果加载失败返回null</returns>
private List<CollisionResult> LoadClashDetectiveResultsFromDatabase(string testName)
public List<CollisionResult> GetClashDetectiveResultsFromDatabase(string testName)
{
try
{
@ -516,75 +497,7 @@ namespace NavisworksTransport
return clashResults;
}
/// <summary>
/// 缓存碰撞结果(动画过程中使用)- 现在包含位置信息用于恢复测试
/// 使用精确的碰撞检测算法替代简化检测
/// </summary>
public void CacheCollisionDuringAnimation(ModelItem animatedObject, Point3D animatedObjectPosition, ModelItem collisionObject, Point3D collisionObjectPosition = null)
{
try
{
if (!IsModelItemValid(animatedObject) || !IsModelItemValid(collisionObject))
{
LogManager.Warning($"[诊断-无效对象] 对象验证失败,退出缓存过程");
return;
}
// 🔧 智能容器映射:将几何体子对象映射到有名称的容器对象
var mappedAnimatedObject = GetCollisionObjectWithValidIdentity(animatedObject);
var mappedCollisionObject = GetCollisionObjectWithValidIdentity(collisionObject);
// 检查是否进行了容器映射
bool hasMapping1 = !mappedAnimatedObject.Equals(animatedObject);
bool hasMapping2 = !mappedCollisionObject.Equals(collisionObject);
// 使用包围盒碰撞检测算法
var animatedBoundingBox = animatedObject.BoundingBox();
var collisionBoundingBox = collisionObject.BoundingBox();
if (BoundingBoxGeometryUtils.BoundingBoxesIntersect(animatedBoundingBox, collisionBoundingBox))
{
// 🔍 计算并验证位置信息
var finalCollisionPosition = collisionObjectPosition ?? GetObjectPosition(collisionObject);
// 创建碰撞结果
var collisionDistance = BoundingBoxGeometryUtils.CalculateDistance(animatedBoundingBox, collisionBoundingBox);
var collisionCenter = BoundingBoxGeometryUtils.CalculateCenter(animatedBoundingBox, collisionBoundingBox);
var collision = new CollisionResult
{
ClashGuid = Guid.NewGuid(),
DisplayName = $"精确碰撞: {mappedAnimatedObject.DisplayName} <-> {mappedCollisionObject.DisplayName}",
Status = ClashResultStatus.New,
Item1 = mappedAnimatedObject, // 记录容器对象
Item2 = mappedCollisionObject, // 记录容器对象
OriginalItem1 = animatedObject, // 保存原始几何体对象
OriginalItem2 = collisionObject, // 保存原始几何体对象
HasContainerMapping = hasMapping1 || hasMapping2, // 标记是否进行了映射
CreatedTime = DateTime.Now,
Distance = collisionDistance,
Center = collisionCenter,
Item1Position = animatedObjectPosition,
Item2Position = finalCollisionPosition,
HasPositionInfo = true
};
// 去重处理:避免重复缓存相同的碰撞对(基于容器对象)
var existing = _cachedResults.FirstOrDefault(r =>
r.Item1.Equals(mappedAnimatedObject) && r.Item2.Equals(mappedCollisionObject));
if (existing == null)
{
_cachedResults.Add(collision);
}
}
}
catch (Exception ex)
{
LogManager.Error($"缓存碰撞失败: {ex.Message}");
LogManager.Error($"[诊断-异常堆栈] {ex.StackTrace}");
}
}
/// <summary>
/// 获取对象当前位置
@ -701,7 +614,7 @@ namespace NavisworksTransport
LogManager.Info($"[分组测试] 有效碰撞数量: {validCollisions.Count}");
// 创建主测试名称
var mainTestName = $"物流碰撞检测_{pathName}_{DateTime.Now:yyyyMMdd_HHmmss}";
var mainTestName = $"碰撞检测_{pathName}_{DateTime.Now:yyyyMMdd_HHmmss}";
_currentTestName = mainTestName;
LogManager.Info($"[分组测试] 创建主测试: {mainTestName}");
@ -748,9 +661,20 @@ namespace NavisworksTransport
LogManager.Info($"[分组测试] 智能去重: {validCollisions.Count} 个检测点 -> {groupedCollisions.Count} 个唯一碰撞对");
// 缓存去重后的碰撞结果(每组取第一个)
lock (_resultsLock)
{
_deduplicatedCollisionResults.Clear();
foreach (var group in groupedCollisions)
{
_deduplicatedCollisionResults.Add(group.First());
}
LogManager.Debug($"[去重缓存] 已缓存 {_deduplicatedCollisionResults.Count} 个去重后的碰撞结果");
}
var collisionGroup = new ClashResultGroup
{
DisplayName = $"物流碰撞检测组 ({groupedCollisions.Count} 个唯一碰撞对)"
DisplayName = $"碰撞检测组 ({groupedCollisions.Count} 个唯一碰撞对)"
};
LogManager.Info($"[分组测试] 创建碰撞分组: {collisionGroup.DisplayName}");
@ -983,7 +907,7 @@ namespace NavisworksTransport
}
// 检查是否成功创建了主测试
var finalMainTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName.Contains("物流碰撞检测")) as ClashTest;
var finalMainTest = _documentClash.TestsData.Tests.FirstOrDefault(t => t.DisplayName.Contains("碰撞检测")) as ClashTest;
if (finalMainTest != null)
{
// 刷新Clash Detective窗口
@ -1226,10 +1150,10 @@ namespace NavisworksTransport
}
/// <summary>
/// 获取所有物流碰撞检测测试
/// 获取所有碰撞检测测试
/// </summary>
/// <returns>物流碰撞检测测试列表</returns>
public List<ClashTest> GetLogisticsClashTests()
/// <returns>碰撞检测测试列表</returns>
public List<ClashTest> GetClashTests()
{
if (_documentClash == null)
{
@ -1237,8 +1161,7 @@ namespace NavisworksTransport
}
return _documentClash.TestsData.Tests.Cast<ClashTest>()
.Where(t => t.DisplayName.Contains("物流碰撞检测") ||
t.DisplayName.Contains("物流碰撞"))
.Where(t => t.DisplayName.Contains("碰撞检测"))
.ToList();
}
@ -1259,17 +1182,17 @@ namespace NavisworksTransport
throw new ArgumentException("路径名称不能为空", nameof(pathName));
}
// 获取所有物流碰撞检测测试
var logisticsTests = GetLogisticsClashTests();
// 获取所有碰撞检测测试
var logisticsTests = GetClashTests();
if (logisticsTests.Count == 0)
{
throw new InvalidOperationException("未找到任何物流碰撞检测测试");
throw new InvalidOperationException("未找到任何碰撞检测测试");
}
// 精确匹配当前路径的测试
var matchedTest = logisticsTests
.Where(t => t.DisplayName.StartsWith("物流碰撞检测_") &&
.Where(t => t.DisplayName.StartsWith("碰撞检测_") &&
t.DisplayName.Contains(pathName))
.OrderByDescending(t => t.DisplayName)
.FirstOrDefault();
@ -1304,7 +1227,7 @@ namespace NavisworksTransport
// 缓存中没有,尝试从数据库加载
LogManager.Info($"[ClashDetective结果] 缓存中没有 '{testName}',尝试从数据库加载");
var loadedResults = LoadClashDetectiveResultsFromDatabase(testName);
var loadedResults = GetClashDetectiveResultsFromDatabase(testName);
if (loadedResults != null && loadedResults.Count > 0)
{
@ -1380,12 +1303,12 @@ namespace NavisworksTransport
}
/// <summary>
/// 获取所有物流碰撞检测的碰撞结果
/// 获取所有碰撞检测的碰撞结果
/// </summary>
/// <returns>碰撞结果列表</returns>
public List<ClashResult> GetAllLogisticsClashResults()
public List<ClashResult> GetAllClashResults()
{
var tests = GetLogisticsClashTests();
var tests = GetClashTests();
var allResults = new List<ClashResult>();
foreach (var test in tests)
@ -1705,7 +1628,7 @@ namespace NavisworksTransport
// 清空缓存的结果
lock (_resultsLock)
{
_cachedResults?.Clear();
_deduplicatedCollisionResults?.Clear();
}
// 清除对象缓存
@ -1912,7 +1835,7 @@ namespace NavisworksTransport
_currentCollisions?.Clear();
lock (_resultsLock)
{
_cachedResults?.Clear();
_deduplicatedCollisionResults?.Clear();
}
// 清理.NET API引用

View File

@ -94,7 +94,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
public ClashDetectiveResultRecord Record { get; }
public string TestTimeDisplay => Record.TestTime.ToString("HH:mm:ss");
public string TestTimeDisplay => Record.TestTime.ToString("MM-dd HH:mm:ss");
public string CollisionCountDisplay => $"{Record.CollisionCount}个";
public ICommand ViewCommand { get; }
public ICommand ReportCommand { get; }
@ -110,8 +110,22 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private void ExecuteReport()
{
// 打开该次检测的详细报告
var command = GenerateCollisionReportCommand.CreateComprehensive(autoHighlight: false);
command.ExecuteAsync();
try
{
var testName = Record.TestName;
LogManager.Info($"[历史报告] 开始生成历史碰撞报告: {testName}");
// 直接使用现有的报告生成命令,但指定测试名称
var command = GenerateCollisionReportCommand.CreateComprehensive(autoHighlight: false);
command.SetTestName(testName);
command.ExecuteAsync();
}
catch (Exception ex)
{
LogManager.Error($"[历史报告] 生成历史报告失败: {ex.Message}", ex);
System.Windows.MessageBox.Show($"生成历史报告失败: {ex.Message}", "错误",
System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
}
}
private void ExecuteDelete()
@ -135,7 +149,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
#region
private readonly NavisworksTransport.Core.Animation.PathAnimationManager _pathAnimationManager;
private readonly Core.Animation.PathAnimationManager _pathAnimationManager;
private readonly ClashDetectiveIntegration _clashIntegration;
private readonly UIStateManager _uiStateManager;
@ -148,7 +162,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private bool _canStopAnimation = false;
// 碰撞检测相关字段
private bool _hasCollisionResults = false;
private CollisionReportResult _lastGeneratedReport; // 缓存最后生成的报告
// 碰撞检测参数字段(从配置初始化)
@ -177,7 +190,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private ObservableCollection<ManualCollisionTargetViewModel> _manualCollisionTargets;
private string _manualCollisionTargetSummary = "未指定碰撞检测对象";
private DateTime? _manualTargetsLastSyncTime;
private List<CollisionResult> _latestCollisionResults = new List<CollisionResult>();
private const int ManualCollisionTargetLimit = 60;
private const string ManualTargetsHighlightCategory = ModelHighlightHelper.ManualTargetsCategory;
private const string CollisionResultsHighlightCategory = ModelHighlightHelper.CollisionResultsCategory;
@ -266,18 +278,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// <summary>
/// 是否有碰撞检测结果
/// </summary>
public bool HasCollisionResults
{
get => _hasCollisionResults;
set
{
if (SetProperty(ref _hasCollisionResults, value))
{
System.Windows.Input.CommandManager.InvalidateRequerySuggested();
}
}
}
private bool _hasClashDetectiveResults;
public bool HasClashDetectiveResults
{
@ -711,8 +711,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public ICommand RemoveManualTargetCommand { get; private set; }
public ICommand HighlightManualTargetsCommand { get; private set; }
public ICommand ClearManualHighlightsCommand { get; private set; }
public ICommand HighlightCollisionResultsCommand { get; private set; }
public ICommand ClearCollisionHighlightsCommand { get; private set; }
public ICommand HighlightPrecomputedCollisionResultsCommand { get; private set; }
public ICommand ClearPrecomputedCollisionHighlightsCommand { get; private set; }
public ICommand HighlightClashDetectiveResultsCommand { get; private set; }
public ICommand ClearClashDetectiveHighlightsCommand { get; private set; }
@ -816,7 +816,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
CanStopAnimation = false;
// 初始化碰撞检测状态
HasCollisionResults = false;
HasClashDetectiveResults = false;
UpdateMainStatus("碰撞检测就绪");
// 从配置读取碰撞检测参数
@ -837,7 +837,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
StartAnimationCommand = new RelayCommand(async () => await ExecuteStartAnimationAsync(), () => CanStartAnimation);
PauseAnimationCommand = new RelayCommand(async () => await ExecutePauseAnimationAsync(), () => CanPauseAnimation);
StopAnimationCommand = new RelayCommand(async () => await ExecuteStopAnimationAsync(), () => CanStopAnimation);
ViewCollisionReportCommand = new RelayCommand(async () => await ExecuteViewCollisionReport(), () => HasCollisionResults);
ViewCollisionReportCommand = new RelayCommand(async () => await ExecuteViewCollisionReport(), () => HasClashDetectiveResults);
SelectAnimatedObjectCommand = new RelayCommand(ExecuteSelectAnimatedObject);
ClearAnimatedObjectCommand = new RelayCommand(ExecuteClearAnimatedObject, () => HasSelectedAnimatedObject);
GenerateAnimationCommand = new RelayCommand(ExecuteGenerateAnimation, () => CanGenerateAnimation);
@ -846,8 +846,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
RemoveManualTargetCommand = new RelayCommand<ManualCollisionTargetViewModel>(ExecuteRemoveManualTarget, target => target != null);
HighlightManualTargetsCommand = new RelayCommand(ExecuteHighlightManualTargets, () => HasManualCollisionTargets);
ClearManualHighlightsCommand = new RelayCommand(ExecuteClearManualHighlights, () => HasManualCollisionTargets);
HighlightCollisionResultsCommand = new RelayCommand(ExecuteHighlightCollisionResults, () => HasCollisionResults);
ClearCollisionHighlightsCommand = new RelayCommand(ExecuteClearCollisionHighlights, () => HasCollisionResults);
HighlightPrecomputedCollisionResultsCommand = new RelayCommand(ExecuteHighlightPrecomputedCollisionResults, () => HasClashDetectiveResults);
ClearPrecomputedCollisionHighlightsCommand = new RelayCommand(ExecuteClearPrecomputedCollisionHighlights, () => HasClashDetectiveResults);
HighlightClashDetectiveResultsCommand = new RelayCommand(ExecuteHighlightClashDetectiveResults, () => HasClashDetectiveResults);
ClearClashDetectiveHighlightsCommand = new RelayCommand(ExecuteClearClashDetectiveHighlights, () => HasClashDetectiveResults);
RefreshClashDetectiveResultsCommand = new RelayCommand(ExecuteRefreshClashDetectiveResults);
@ -993,7 +993,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// </summary>
private async Task ExecuteViewCollisionReport()
{
if (!HasCollisionResults)
if (!HasClashDetectiveResults)
{
UpdateMainStatus("尚无碰撞检测结果可查看");
return;
@ -1421,19 +1421,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// </summary>
private async void OnCollisionDetected(object sender, CollisionDetectedEventArgs e)
{
_latestCollisionResults = e?.Results?.Where(r => r != null).ToList() ?? new List<CollisionResult>();
HasCollisionResults = _latestCollisionResults.Count > 0;
if (!HasCollisionResults)
try
{
ModelHighlightHelper.ClearCollisionHighlights();
}
// 获取ClashDetective结果
var clashResults = _clashIntegration?.GetCurrentTestResults();
var collisionCount = clashResults?.Count ?? 0;
var collisionCount = _latestCollisionResults.Count;
if (collisionCount > 0)
{
try
if (collisionCount > 0)
{
UpdateMainStatus($"发现 {collisionCount} 个碰撞点,正在生成报告...", -1, true);
LogManager.Info($"碰撞检测完成,发现 {collisionCount} 个碰撞,开始自动生成报告");
@ -1464,16 +1458,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels
LogManager.Error($"自动生成碰撞报告失败: {result.ErrorMessage}");
}
}
catch (Exception ex)
else
{
LogManager.Error($"处理碰撞检测事件失败: {ex.Message}", ex);
UpdateMainStatus($"发现 {collisionCount} 个碰撞点(报告生成异常)");
UpdateMainStatus("未发现碰撞");
_lastGeneratedReport = null;
}
}
else
catch (Exception ex)
{
UpdateMainStatus("未发现碰撞");
_lastGeneratedReport = null;
LogManager.Error($"处理碰撞检测事件失败: {ex.Message}", ex);
UpdateMainStatus("处理碰撞检测事件失败");
}
}
@ -1703,23 +1697,42 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#region
private void ExecuteHighlightCollisionResults()
private void ExecuteHighlightPrecomputedCollisionResults()
{
if (_latestCollisionResults == null || _latestCollisionResults.Count == 0)
try
{
UpdateMainStatus("没有可高亮的碰撞结果对象");
return;
}
var deduplicatedResults = _clashIntegration?.GetDeduplicatedCollisionResults();
LogManager.Debug($"[预计算碰撞结果高亮] 获取到去重后的预计算结果数量: {deduplicatedResults?.Count ?? 0}");
_clashIntegration?.HighlightCollisions(_latestCollisionResults, CollisionResultHighlightColor, false);
UpdateMainStatus($"已高亮 {_latestCollisionResults.Count} 个碰撞结果");
LogManager.Info($"[碰撞结果高亮] 已高亮 {_latestCollisionResults.Count} 个结果");
if (deduplicatedResults == null || deduplicatedResults.Count == 0)
{
UpdateMainStatus("没有可高亮的去重预计算碰撞结果对象");
LogManager.Warning("[预计算碰撞结果高亮] 去重预计算缓存为空");
return;
}
// 输出前3个碰撞结果的信息
for (int i = 0; i < Math.Min(3, deduplicatedResults.Count); i++)
{
var collision = deduplicatedResults[i];
LogManager.Debug($"[预计算碰撞结果高亮] 碰撞{i+1}: {collision.DisplayName}, Item1={collision.Item1?.DisplayName}, Item2={collision.Item2?.DisplayName}");
}
_clashIntegration?.HighlightCollisions(deduplicatedResults, CollisionResultHighlightColor, false);
UpdateMainStatus($"已高亮 {deduplicatedResults.Count} 个去重预计算碰撞结果");
LogManager.Info($"[预计算碰撞结果高亮] 已高亮 {deduplicatedResults.Count} 个结果");
}
catch (Exception ex)
{
LogManager.Error($"高亮预计算碰撞结果失败: {ex.Message}", ex);
UpdateMainStatus("高亮预计算碰撞结果失败");
}
}
private void ExecuteClearCollisionHighlights()
private void ExecuteClearPrecomputedCollisionHighlights()
{
ModelHighlightHelper.ClearCategory(CollisionResultsHighlightCategory);
UpdateMainStatus("已清除碰撞结果高亮");
UpdateMainStatus("已清除预计算碰撞结果高亮");
}
private void ExecuteHighlightClashDetectiveResults()
@ -2456,11 +2469,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 获取所有动画相关的碰撞测试(包括新的分组测试)
var animationTests = documentClash.TestsData.Tests.Cast<ClashTest>()
.Where(t => t.DisplayName.Contains("物流碰撞检测") ||
t.DisplayName.Contains("物流碰撞"))
.Where(t => t.DisplayName.Contains("碰撞检测") )
.ToList();
LogManager.Info($"找到 {animationTests.Count} 个物流碰撞测");
LogManager.Info($"找到 {animationTests.Count} 个碰撞测");
foreach (var test in animationTests)
{
@ -2668,9 +2680,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
HasSelectedAnimatedObject = false;
// 清空碰撞结果
HasCollisionResults = false;
HasClashDetectiveResults = false;
_latestCollisionResults.Clear();
ModelHighlightHelper.ClearCollisionHighlights();
UpdateMainStatus("已重置");

View File

@ -376,19 +376,9 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
<StackPanel Orientation="Horizontal" Margin="0,10,0,15">
<Button Content="查看碰撞报告"
Command="{Binding ViewCollisionReportCommand}"
IsEnabled="{Binding HasCollisionResults}"
IsEnabled="{Binding HasClashDetectiveResults}"
Style="{StaticResource ActionButtonStyle}"
Margin="0,0,8,0"/>
<Button Content="预计算高亮"
Command="{Binding HighlightCollisionResultsCommand}"
IsEnabled="{Binding HasCollisionResults}"
Style="{StaticResource SecondaryButtonStyle}"
Margin="0,0,8,0"/>
<Button Content="清除预计算高亮"
Command="{Binding ClearCollisionHighlightsCommand}"
IsEnabled="{Binding HasCollisionResults}"
Style="{StaticResource SecondaryButtonStyle}"
Margin="0,0,8,0"/>
<Button Content="结果高亮"
Command="{Binding HighlightClashDetectiveResultsCommand}"
IsEnabled="{Binding HasClashDetectiveResults}"
@ -398,99 +388,111 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
Command="{Binding ClearClashDetectiveHighlightsCommand}"
IsEnabled="{Binding HasClashDetectiveResults}"
Style="{StaticResource SecondaryButtonStyle}"/>
<Button Content="预计算高亮(调试)"
Command="{Binding HighlightPrecomputedCollisionResultsCommand}"
IsEnabled="{Binding HasClashDetectiveResults}"
Style="{StaticResource SecondaryButtonStyle}"
Margin="0,0,8,0"/>
<Button Content="清除预计算高亮(调试)"
Command="{Binding ClearPrecomputedCollisionHighlightsCommand}"
IsEnabled="{Binding HasClashDetectiveResults}"
Style="{StaticResource SecondaryButtonStyle}"
Margin="0,0,8,0"/>
</StackPanel>
</StackPanel>
</Border>
<!-- 区域6: 碰撞检测历史 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="碰撞检测历史" Style="{StaticResource SectionHeaderStyle}"/>
<Button Grid.Column="1"
Content="刷新"
Command="{Binding RefreshClashDetectiveResultsCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Height="22"
Padding="8,2"
Margin="0,0,0,0"/>
</Grid>
<!-- ClashDetective结果列表 -->
<StackPanel Margin="0,15,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="碰撞检测历史" Style="{StaticResource SectionHeaderStyle}"/>
<Button Grid.Column="1"
Content="刷新"
Command="{Binding RefreshClashDetectiveResultsCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Height="22"
Padding="8,2"
Margin="0,0,0,0"/>
</Grid>
<TextBlock Text="当前路径暂无碰撞检测结果"
Style="{StaticResource StatusTextStyle}"
Foreground="#FF777777"
Visibility="{Binding HasClashDetectiveResults, Converter={StaticResource BoolToVisConverter}, ConverterParameter=Inverse}"
Margin="0,5,0,0"/>
<TextBlock Text="当前路径暂无碰撞检测结果"
Style="{StaticResource StatusTextStyle}"
Foreground="#FF777777"
Visibility="{Binding HasClashDetectiveResults, Converter={StaticResource BoolToVisConverter}, ConverterParameter=Inverse}"
Margin="0,5,0,0"/>
<ListView ItemsSource="{Binding ClashDetectiveResults}"
Margin="0,5,0,0"
Visibility="{Binding HasClashDetectiveResults, Converter={StaticResource BoolToVisConverter}}"
MinHeight="120"
MaxHeight="200"
BorderBrush="#FFE2E8F0"
BorderThickness="1">
<ListView.View>
<GridView>
<GridViewColumn Header="测试名称" Width="140">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Record.TestName}"
FontWeight="SemiBold"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding Record.TestName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="时间" Width="60">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding TestTimeDisplay}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="碰撞数" Width="60">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding CollisionCountDisplay}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="操作" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="查看"
Command="{Binding ViewCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Height="20"
Padding="6,0"
Margin="0,0,4,0"/>
<Button Content="报告"
Command="{Binding ReportCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Height="20"
Padding="6,0"
Margin="0,0,4,0"/>
<Button Content="删除"
Command="{Binding DeleteCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Height="20"
Padding="6,0"
Background="#FFFFE6E6"
Foreground="#FF8B0000"
Margin="0"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
<ListView ItemsSource="{Binding ClashDetectiveResults}"
Margin="0,5,0,0"
Visibility="{Binding HasClashDetectiveResults, Converter={StaticResource BoolToVisConverter}}"
MinHeight="120"
MaxHeight="200"
BorderBrush="#FFE2E8F0"
BorderThickness="1">
<ListView.View>
<GridView>
<GridViewColumn Header="测试名称" Width="140">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Record.TestName}"
FontWeight="SemiBold"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding Record.TestName}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="时间" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding TestTimeDisplay}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="碰撞数" Width="60">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding CollisionCountDisplay}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="操作" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Content="高亮"
Command="{Binding ViewCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Height="20"
Padding="6,0"
Margin="0,0,4,0"/>
<Button Content="报告"
Command="{Binding ReportCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Height="20"
Padding="6,0"
Margin="0,0,4,0"/>
<Button Content="删除"
Command="{Binding DeleteCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Height="20"
Padding="6,0"
Background="#FFFFE6E6"
Foreground="#FF8B0000"
Margin="0"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Border>

View File

@ -239,7 +239,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
<GridViewColumn Header="路径名称" DisplayMemberBinding="{Binding Name}" Width="160"/>
<GridViewColumn Header="点数" DisplayMemberBinding="{Binding PointCount}" Width="50"/>
<GridViewColumn Header="状态" DisplayMemberBinding="{Binding StatusString}" Width="60"/>
<GridViewColumn Header="创建时间" DisplayMemberBinding="{Binding CreatedTime, StringFormat='MM-dd HH:mm'}" Width="90"/>
<GridViewColumn Header="创建时间" DisplayMemberBinding="{Binding CreatedTime, StringFormat='MM-dd HH:mm:ss'}" Width="100"/>
<GridViewColumn Header="操作" Width="60">
<GridViewColumn.CellTemplate>
<DataTemplate>

View File

@ -21,7 +21,7 @@ namespace NavisworksTransport.UI.WPF.Views
LogManager.Info("TimeTagDialog初始化完成");
// 设置窗口标题包含当前时间
Title = $"时间标签设置 [{DateTime.Now:MM-dd HH:mm}]";
Title = $"时间标签设置 [{DateTime.Now:MM-dd HH:mm:ss}]";
// 设置ViewModel
this.DataContext = new TimeTagViewModel();