重构了高亮显示的逻辑,统一处理流程。

This commit is contained in:
tian 2025-12-11 13:23:55 +08:00
parent adde6cbdf4
commit 2bd117ff8a
10 changed files with 397 additions and 247 deletions

View File

@ -156,6 +156,8 @@
<Compile Include="src\Core\Properties\CategoryAttributeManager.cs" />
<Compile Include="src\Core\Properties\NavisworksComPropertyManager.cs" />
<Compile Include="src\Core\FloorAttributeManager.cs" />
<!-- Utilities -->
<Compile Include="src\Utils\ModelHighlightHelper.cs" />
<!-- PathPlanning - Auto Path Planning -->
<Compile Include="src\PathPlanning\GridMap.cs" />
<Compile Include="src\PathPlanning\GridMapGenerator.cs" />

View File

@ -207,7 +207,7 @@ namespace NavisworksTransport.Commands
if (highlightIntegration != null)
{
var highlightColor = Color.Green; // 绿色 (Navisworks API中没有Orange)
highlightIntegration.ManageHighlightsByCategory("report", collisionData.AllCollisions, highlightColor, true);
highlightIntegration.ManageHighlightsByCategory(ModelHighlightHelper.CollisionResultsCategory, collisionData.AllCollisions, highlightColor, true);
LogManager.Info($"自动高亮显示报告中的 {collisionData.AllCollisions.Count} 个碰撞对象");
}
}

View File

@ -781,7 +781,7 @@ namespace NavisworksTransport.Core.Animation
}
else
{
ClashDetectiveIntegration.Instance.ClearHighlights();
ModelHighlightHelper.ClearCategory("collisionresults");
LogManager.Info("动画停止,路径上无碰撞对象");
}
@ -879,7 +879,7 @@ namespace NavisworksTransport.Core.Animation
}
else
{
ClashDetectiveIntegration.Instance.ClearHighlights();
ModelHighlightHelper.ClearCategory("collisionresults");
LogManager.Info("动画完成,路径上无碰撞对象");
}
@ -1928,7 +1928,7 @@ namespace NavisworksTransport.Core.Animation
else
{
// 从有碰撞到无碰撞:清除高亮
ClashDetectiveIntegration.Instance.ClearHighlights();
ModelHighlightHelper.ClearCategory("collisionresults");
LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 清除高亮");
}

View File

@ -15,6 +15,8 @@ namespace NavisworksTransport
public class ClashDetectiveIntegration
{
private static ClashDetectiveIntegration _instance;
private const string CollisionHighlightsCategory = ModelHighlightHelper.CollisionResultsCategory;
private DocumentClash _documentClash;
private List<ClashResult> _currentCollisions;
// 通道对象缓存,用于优化碰撞检测性能
@ -125,10 +127,7 @@ namespace NavisworksTransport
}
private List<CollisionResult> _cachedResults = new List<CollisionResult>();
// 高亮管理字段
private Dictionary<string, ModelItemCollection> _activeHighlights = new Dictionary<string, ModelItemCollection>();
private readonly object _highlightLock = new object();
private readonly object _resultsLock = new object();
/// <summary>
/// 缓存碰撞结果
@ -580,7 +579,7 @@ namespace NavisworksTransport
{
// 使用类别管理的高亮方式
var darkRed = Color.Red; // 红色暗红色在Navisworks API中不可用
ManageHighlightsByCategory("animation", validResults, darkRed, true);
ManageHighlightsByCategory(ModelHighlightHelper.CollisionResultsCategory, validResults, darkRed, true);
LogManager.Info($"自动高亮显示 {validResults.Count} 个动画结束后的碰撞结果(暗红色)");
}
}
@ -742,29 +741,40 @@ namespace NavisworksTransport
{
try
{
var doc = Application.ActiveDocument;
var validResults = results?.Where(r => r != null).ToList() ?? new List<CollisionResult>();
if (validResults.Count == 0)
{
if (clearPrevious)
{
ModelHighlightHelper.ClearCategory(CollisionHighlightsCategory);
}
return;
}
// 根据参数决定是否清除之前的高亮
if (clearPrevious)
{
doc.Models.ResetAllTemporaryMaterials();
ModelHighlightHelper.ClearCategory(CollisionHighlightsCategory);
}
if (results != null && results.Count > 0)
var highlightItems = new List<ModelItem>();
foreach (var collision in validResults)
{
var collidingItems = new ModelItemCollection();
var item1 = collision.GetValidItem1();
var item2 = collision.GetValidItem2();
foreach (var result in results)
if (IsModelItemValid(item1) && !highlightItems.Contains(item1))
{
if (result.Item1 != null && !collidingItems.Contains(result.Item1))
collidingItems.Add(result.Item1);
if (result.Item2 != null && !collidingItems.Contains(result.Item2))
collidingItems.Add(result.Item2);
highlightItems.Add(item1);
}
// 高亮碰撞对象(使用指定颜色)
doc.Models.OverrideTemporaryColor(collidingItems, highlightColor);
if (IsModelItemValid(item2) && !highlightItems.Contains(item2))
{
highlightItems.Add(item2);
}
}
ModelHighlightHelper.HighlightItems(CollisionHighlightsCategory, highlightItems, highlightColor);
}
catch (Exception ex)
{
@ -779,13 +789,8 @@ namespace NavisworksTransport
{
try
{
lock (_highlightLock)
{
var doc = Application.ActiveDocument;
doc.Models.ResetAllTemporaryMaterials();
_activeHighlights.Clear();
LogManager.Debug("已清除所有碰撞高亮"); // 改为DEBUG级别减少日志噪音
}
ModelHighlightHelper.ClearAllHighlights();
LogManager.Debug("已清除所有碰撞高亮");
}
catch (Exception ex)
{
@ -793,158 +798,42 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 高亮任意模型对象集合
/// </summary>
public void HighlightModelItems(string category, IEnumerable<ModelItem> items, Color highlightColor, bool clearOtherCategories = false)
{
if (string.IsNullOrWhiteSpace(category))
{
category = "custom";
}
try
{
lock (_highlightLock)
{
var doc = Application.ActiveDocument;
if (clearOtherCategories)
{
doc.Models.ResetAllTemporaryMaterials();
_activeHighlights.Clear();
}
else if (_activeHighlights.ContainsKey(category))
{
doc.Models.ResetAllTemporaryMaterials();
_activeHighlights.Remove(category);
foreach (var kvp in _activeHighlights)
{
var categoryColor = GetCategoryColor(kvp.Key);
doc.Models.OverrideTemporaryColor(kvp.Value, categoryColor);
}
}
var collection = new ModelItemCollection();
if (items != null)
{
foreach (var item in items)
{
if (item != null && IsModelItemValid(item) && !collection.Contains(item))
{
collection.Add(item);
}
}
}
if (collection.Count == 0)
{
_activeHighlights.Remove(category);
return;
}
doc.Models.OverrideTemporaryColor(collection, highlightColor);
_activeHighlights[category] = collection;
}
}
catch (Exception ex)
{
LogManager.Error($"高亮模型对象失败[{category}]: {ex.Message}");
}
}
/// <summary>
/// 清除指定类别的高亮
/// </summary>
public void ClearHighlightCategory(string category)
{
if (string.IsNullOrWhiteSpace(category))
return;
try
{
lock (_highlightLock)
{
if (!_activeHighlights.ContainsKey(category))
return;
_activeHighlights.Remove(category);
var doc = Application.ActiveDocument;
doc.Models.ResetAllTemporaryMaterials();
foreach (var kvp in _activeHighlights)
{
var color = GetCategoryColor(kvp.Key);
doc.Models.OverrideTemporaryColor(kvp.Value, color);
}
}
}
catch (Exception ex)
{
LogManager.Error($"清除高亮类别失败[{category}]: {ex.Message}");
}
}
/// <summary>
/// 按类别管理高亮显示
/// </summary>
/// <param name="category">高亮类别(如"animation", "independent", "report"等)</param>
/// <param name="results">碰撞结果</param>
/// <param name="highlightColor">高亮颜色</param>
/// <param name="clearOtherCategories">是否清除其他类别的高亮</param>
/// <param name="clearOtherCategories">是否在高亮前清除该类别以避免叠加</param>
public void ManageHighlightsByCategory(string category, List<CollisionResult> results,
Color highlightColor, bool clearOtherCategories = false)
{
try
{
lock (_highlightLock)
var collidingItems = new List<ModelItem>();
if (results != null)
{
var doc = Application.ActiveDocument;
// 清除其他类别的高亮(如果需要)
if (clearOtherCategories)
foreach (var result in results)
{
doc.Models.ResetAllTemporaryMaterials();
_activeHighlights.Clear();
}
else if (_activeHighlights.ContainsKey(category))
{
// 只清除当前类别的高亮
var existingItems = _activeHighlights[category];
// Navisworks不支持按对象清除高亮需要全部重置后重新应用其他类别
doc.Models.ResetAllTemporaryMaterials();
_activeHighlights.Remove(category);
// 重新应用其他类别的高亮
foreach (var kvp in _activeHighlights)
if (result?.Item1 != null && !collidingItems.Contains(result.Item1) && IsModelItemValid(result.Item1))
{
// 这里需要根据类别使用不同颜色重新高亮
var categoryColor = GetCategoryColor(kvp.Key);
doc.Models.OverrideTemporaryColor(kvp.Value, categoryColor);
}
}
if (results != null && results.Count > 0)
{
var collidingItems = new ModelItemCollection();
foreach (var result in results)
{
if (result.Item1 != null && !collidingItems.Contains(result.Item1))
collidingItems.Add(result.Item1);
if (result.Item2 != null && !collidingItems.Contains(result.Item2))
collidingItems.Add(result.Item2);
collidingItems.Add(result.Item1);
}
// 应用高亮
doc.Models.OverrideTemporaryColor(collidingItems, highlightColor);
// 记录活跃高亮
_activeHighlights[category] = collidingItems;
if (result?.Item2 != null && !collidingItems.Contains(result.Item2) && IsModelItemValid(result.Item2))
{
collidingItems.Add(result.Item2);
}
}
}
if (clearOtherCategories)
{
ModelHighlightHelper.ClearCategory(category);
}
ModelHighlightHelper.HighlightItems(category, collidingItems, highlightColor);
}
catch (Exception ex)
{
@ -952,30 +841,6 @@ namespace NavisworksTransport
}
}
/// <summary>
/// 根据类别获取默认颜色
/// </summary>
private Color GetCategoryColor(string category)
{
switch (category.ToLower())
{
case "animation":
case "runtime":
return Color.Red; // 动画过程:红色
case "independent":
case "static":
return Color.Red; // 独立检测:红色 (Navisworks API中没有DarkRed)
case "report":
return Color.Green; // 报告查看:绿色 (Navisworks API中没有Orange)
case "preview":
return Color.Blue; // 预览:蓝色 (Navisworks API中没有Yellow)
case "manualtargets":
return Color.FromByteRGB(255, 170, 0); // 琥珀色手工目标
default:
return Color.White; // 未知类别:白色 (Navisworks API中没有Magenta)
}
}
/// <summary>
/// 获取当前活跃高亮信息
/// </summary>
@ -983,30 +848,23 @@ namespace NavisworksTransport
{
try
{
lock (_highlightLock)
var snapshot = ModelHighlightHelper.GetActiveHighlightSnapshot();
if (snapshot.Count == 0)
{
if (_activeHighlights.Count == 0)
{
return "当前无活跃高亮";
}
var info = new StringBuilder();
info.AppendLine("=== 当前活跃高亮 ===");
foreach (var kvp in _activeHighlights)
{
var category = kvp.Key;
var items = kvp.Value;
var color = GetCategoryColor(category);
info.AppendLine($"类别: {category}");
info.AppendLine($" 对象数量: {items.Count}");
info.AppendLine($" 颜色: {color}");
info.AppendLine();
}
return info.ToString();
return "当前无活跃高亮";
}
var info = new StringBuilder();
info.AppendLine("=== 当前活跃高亮 ===");
foreach (var entry in snapshot)
{
info.AppendLine($"类别: {entry.Category}");
info.AppendLine($" 对象数量: {entry.Count}");
info.AppendLine($" 颜色: {entry.Color}");
info.AppendLine();
}
return info.ToString();
}
catch (Exception ex)
{
@ -1246,7 +1104,7 @@ namespace NavisworksTransport
_currentCollisions?.Clear();
// 清空缓存的结果
lock (_highlightLock)
lock (_resultsLock)
{
_cachedResults?.Clear();
}
@ -1441,16 +1299,11 @@ namespace NavisworksTransport
return;
}
// 清除临时高亮
try
{
document.Models.ResetAllTemporaryMaterials();
ModelHighlightHelper.ClearAllHighlights();
LogManager.Info("已清除临时材质高亮");
}
catch (ObjectDisposedException)
{
LogManager.Info("文档对象已释放,跳过材质清理");
}
catch (Exception ex)
{
LogManager.Warning($"清除临时材质失败: {ex.Message}");
@ -1458,12 +1311,9 @@ namespace NavisworksTransport
// 清空内存中的结果
_currentCollisions?.Clear();
_cachedResults?.Clear();
// 清理高亮管理器
lock (_highlightLock)
lock (_resultsLock)
{
_activeHighlights?.Clear();
_cachedResults?.Clear();
}
// 清理.NET API引用

View File

@ -5,6 +5,7 @@ using System.Windows.Forms;
using System.Windows.Forms.Integration;
using NavisworksTransport.Core;
using NavisworksTransport.Core.Animation;
using NavisworksTransport.Utils;
using NavisApplication = Autodesk.Navisworks.Api.Application;
namespace NavisworksTransport
@ -286,7 +287,7 @@ namespace NavisworksTransport
// 尝试清除临时高亮
if (NavisApplication.ActiveDocument?.Models != null)
{
NavisApplication.ActiveDocument.Models.ResetAllTemporaryMaterials();
ModelHighlightHelper.ClearAllHighlights();
LogManager.Info("[全局异常] 已清除临时材质");
}
@ -620,7 +621,7 @@ namespace NavisworksTransport
var activeDoc = NavisApplication.ActiveDocument;
if (activeDoc?.Models != null)
{
activeDoc.Models.ResetAllTemporaryMaterials();
ModelHighlightHelper.ClearAllHighlights();
}
}
catch (Exception ex)

View File

@ -5,6 +5,7 @@ using Autodesk.Navisworks.Api;
using System.Text;
using System.Linq;
using System.IO;
using NavisworksTransport.Utils;
namespace NavisworksTransport
{
@ -877,6 +878,7 @@ namespace NavisworksTransport
private ModelItemCollection _selectedChannels;
private ChannelSelectionMethod _selectionMethod;
private double _heightLimit;
private const string ChannelPreviewHighlightCategory = "channel_preview";
/// <summary>
/// 选中的通道
@ -1240,8 +1242,7 @@ namespace NavisworksTransport
{
// 高亮显示选中的通道
var navisColor = new Autodesk.Navisworks.Api.Color(0.0, 1.0, 0.0); // 绿色
Application.ActiveDocument.Models.OverrideTemporaryColor(selectedItems, navisColor);
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
ModelHighlightHelper.HighlightItems(ChannelPreviewHighlightCategory, selectedItems, navisColor);
}
}
catch (Exception ex)
@ -1258,8 +1259,7 @@ namespace NavisworksTransport
{
try
{
Application.ActiveDocument.Models.ResetAllTemporaryMaterials();
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
ModelHighlightHelper.ClearCategory(ChannelPreviewHighlightCategory);
}
catch (Exception ex)
{
@ -1291,8 +1291,7 @@ namespace NavisworksTransport
// 清除高亮
try
{
Application.ActiveDocument.Models.ResetAllTemporaryMaterials();
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
ModelHighlightHelper.ClearCategory(ChannelPreviewHighlightCategory);
}
catch { }
}

View File

@ -127,9 +127,12 @@ 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 = "manualTargets";
private const string ManualTargetsHighlightCategory = ModelHighlightHelper.ManualTargetsCategory;
private const string CollisionResultsHighlightCategory = ModelHighlightHelper.CollisionResultsCategory;
private static readonly Color ManualTargetHighlightColor = Color.FromByteRGB(255, 170, 0);
private static readonly Color CollisionResultHighlightColor = Color.Red;
#endregion
@ -216,7 +219,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public bool HasCollisionResults
{
get => _hasCollisionResults;
set => SetProperty(ref _hasCollisionResults, value);
set
{
if (SetProperty(ref _hasCollisionResults, value))
{
System.Windows.Input.CommandManager.InvalidateRequerySuggested();
}
}
}
@ -596,6 +605,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 PlayForwardCommand { get; private set; }
@ -726,6 +737,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);
PlayForwardCommand = new RelayCommand(ExecutePlayForward, CanExecuteMediaCommands);
PlayReverseCommand = new RelayCommand(ExecutePlayReverse, CanExecuteMediaCommands);
StepForwardCommand = new RelayCommand(ExecuteStepForward, CanExecuteMediaCommands);
@ -1219,14 +1232,22 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// </summary>
private async void OnCollisionDetected(object sender, CollisionDetectedEventArgs e)
{
HasCollisionResults = e.Results.Count > 0;
_latestCollisionResults = e?.Results?.Where(r => r != null).ToList() ?? new List<CollisionResult>();
HasCollisionResults = _latestCollisionResults.Count > 0;
if (e.Results.Count > 0)
if (!HasCollisionResults)
{
ModelHighlightHelper.ClearCategory(CollisionResultsHighlightCategory);
}
var collisionCount = _latestCollisionResults.Count;
if (collisionCount > 0)
{
try
{
UpdateMainStatus($"发现 {e.Results.Count} 个碰撞点,正在生成报告...", -1, true);
LogManager.Info($"碰撞检测完成,发现 {e.Results.Count} 个碰撞,开始自动生成报告");
UpdateMainStatus($"发现 {collisionCount} 个碰撞点,正在生成报告...", -1, true);
LogManager.Info($"碰撞检测完成,发现 {collisionCount} 个碰撞,开始自动生成报告");
// 自动生成碰撞报告
var generateReportCommand = NavisworksTransport.Commands.GenerateCollisionReportCommand.CreateComprehensive();
@ -1240,19 +1261,19 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 保存到数据库
await SaveCollisionReportToDatabase(reportResult.Data);
UpdateMainStatus($"✅ 碰撞报告已生成并保存:{e.Results.Count} 个碰撞");
UpdateMainStatus($"✅ 碰撞报告已生成并保存:{collisionCount} 个碰撞");
LogManager.Info("碰撞报告已自动生成并保存到数据库");
}
else
{
UpdateMainStatus($"发现 {e.Results.Count} 个碰撞点(报告生成失败)");
UpdateMainStatus($"发现 {collisionCount} 个碰撞点(报告生成失败)");
LogManager.Error($"自动生成碰撞报告失败: {result.ErrorMessage}");
}
}
catch (Exception ex)
{
LogManager.Error($"处理碰撞检测事件失败: {ex.Message}", ex);
UpdateMainStatus($"发现 {e.Results.Count} 个碰撞点(报告生成异常)");
UpdateMainStatus($"发现 {collisionCount} 个碰撞点(报告生成异常)");
}
}
else
@ -1434,6 +1455,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 清理碰撞检测结果
HasCollisionResults = false;
_latestCollisionResults.Clear();
ModelHighlightHelper.ClearCategory(CollisionResultsHighlightCategory);
UpdateMainStatus("碰撞检测重置");
// 清除高亮构件
@ -1543,7 +1566,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
_manualCollisionTargets.Clear();
_manualTargetsLastSyncTime = null;
_clashIntegration?.ClearHighlightCategory(ManualTargetsHighlightCategory);
ModelHighlightHelper.ClearCategory(ManualTargetsHighlightCategory);
SyncManualCollisionTargetsToAnimationManager();
UpdateManualCollisionTargetSummary();
UpdateMainStatus("已清空手工碰撞对象");
@ -1562,7 +1585,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
if (_manualCollisionTargets.Count == 0)
{
_clashIntegration?.ClearHighlightCategory(ManualTargetsHighlightCategory);
ModelHighlightHelper.ClearCategory(ManualTargetsHighlightCategory);
}
else
{
@ -1582,12 +1605,35 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private void ExecuteClearManualHighlights()
{
_clashIntegration?.ClearHighlightCategory(ManualTargetsHighlightCategory);
ModelHighlightHelper.ClearCategory(ManualTargetsHighlightCategory);
UpdateMainStatus("已清除手工对象高亮");
}
#endregion
#region
private void ExecuteHighlightCollisionResults()
{
if (_latestCollisionResults == null || _latestCollisionResults.Count == 0)
{
UpdateMainStatus("没有可高亮的碰撞结果对象");
return;
}
_clashIntegration?.HighlightCollisions(_latestCollisionResults, CollisionResultHighlightColor, false);
UpdateMainStatus($"已高亮 {_latestCollisionResults.Count} 个碰撞结果");
LogManager.Info($"[碰撞结果高亮] 已高亮 {_latestCollisionResults.Count} 个结果");
}
private void ExecuteClearCollisionHighlights()
{
ModelHighlightHelper.ClearCategory(CollisionResultsHighlightCategory);
UpdateMainStatus("已清除碰撞结果高亮");
}
#endregion
/// <summary>
/// 异步预计算碰撞排除列表
/// </summary>
@ -1800,17 +1846,17 @@ namespace NavisworksTransport.UI.WPF.ViewModels
var validItems = GetValidManualCollisionTargets();
if (validItems.Count == 0)
{
_clashIntegration.ClearHighlightCategory(ManualTargetsHighlightCategory);
ModelHighlightHelper.ClearCategory(ManualTargetsHighlightCategory);
return;
}
if (IsManualTargetModeActive || forceHighlight)
{
_clashIntegration.HighlightModelItems(ManualTargetsHighlightCategory, validItems, ManualTargetHighlightColor);
ModelHighlightHelper.HighlightItems(ManualTargetsHighlightCategory, validItems, ManualTargetHighlightColor);
}
else
{
_clashIntegration.ClearHighlightCategory(ManualTargetsHighlightCategory);
ModelHighlightHelper.ClearCategory(ManualTargetsHighlightCategory);
}
}
catch (Exception ex)
@ -1984,6 +2030,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
LogManager.Info($"虚拟车辆尺寸: {VirtualVehicleLength:F1}×{VirtualVehicleWidth:F1}×{VirtualVehicleHeight:F1}m");
}
if (IsManualCollisionTargetEnabled)
{
RefreshManualTargetHighlights(forceHighlight: true);
}
// 更新状态
UpdateAnimationButtonStates();
UpdateMainStatus("动画生成成功");
@ -2442,6 +2493,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 清空碰撞结果
HasCollisionResults = false;
_latestCollisionResults.Clear();
ModelHighlightHelper.ClearCategory(CollisionResultsHighlightCategory);
UpdateMainStatus("已重置");
}
@ -2528,11 +2581,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
try
{
_clashIntegration?.ClearHighlightCategory(ManualTargetsHighlightCategory);
ModelHighlightHelper.ClearCategory(ManualTargetsHighlightCategory);
ModelHighlightHelper.ClearCategory(CollisionResultsHighlightCategory);
}
catch (Exception highlightEx)
{
LogManager.Warning($"清除手工碰撞高亮时出现警告: {highlightEx.Message}");
LogManager.Warning($"清除高亮时出现警告: {highlightEx.Message}");
}
// 3. 不再清理PathAnimationManager - 现在使用单例模式,由应用程序生命周期管理

View File

@ -885,7 +885,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
var collisions = new List<CollisionResult> { item.CollisionData };
var highlightColor = Autodesk.Navisworks.Api.Color.Green; // 使用Navisworks API中可用的绿色
clashIntegration.ManageHighlightsByCategory("selected", collisions, highlightColor, true);
clashIntegration.ManageHighlightsByCategory(ModelHighlightHelper.CollisionResultsCategory, collisions, highlightColor, true);
LogManager.Info($"高亮碰撞对象: {item.Title}");
}
}

View File

@ -377,7 +377,17 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
<Button Content="查看碰撞报告"
Command="{Binding ViewCollisionReportCommand}"
IsEnabled="{Binding HasCollisionResults}"
Style="{StaticResource ActionButtonStyle}"/>
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}"/>
</StackPanel>

View File

@ -0,0 +1,234 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
namespace NavisworksTransport.Utils
{
/// <summary>
/// 统一管理 Navisworks 临时高亮的工具类,支持按类别高亮与清除。
/// </summary>
public static class ModelHighlightHelper
{
public const string CollisionResultsCategory = "collisionresults";
public const string ManualTargetsCategory = "manualTargets";
public const string ChannelPreviewCategory = "channel_preview";
private class HighlightEntry
{
public Color Color { get; set; }
public ModelItemCollection Items { get; set; }
}
public class HighlightInfo
{
public string Category { get; set; } = string.Empty;
public Color Color { get; set; }
public int Count { get; set; }
}
private static readonly object _syncRoot = new object();
private static readonly Dictionary<string, HighlightEntry> _activeHighlights =
new Dictionary<string, HighlightEntry>(StringComparer.OrdinalIgnoreCase);
private static readonly Dictionary<string, Color> _categoryColors =
new Dictionary<string, Color>(StringComparer.OrdinalIgnoreCase)
{
{ "animation", Color.Red },
{ "runtime", Color.Red },
{ "independent", Color.Red },
{ "static", Color.Red },
{ "report", Color.Green },
{ "preview", Color.Blue },
{ ManualTargetsCategory, Color.FromByteRGB(255, 170, 0) },
{ CollisionResultsCategory, Color.Red },
{ ChannelPreviewCategory, Color.Green }
};
/// <summary>
/// 高亮指定对象集合。
/// </summary>
public static void HighlightItems(string category, IEnumerable<ModelItem> items, Color color)
{
if (items == null)
return;
var document = Application.ActiveDocument;
if (document?.Models == null)
return;
if (string.IsNullOrWhiteSpace(category))
{
category = "default";
}
lock (_syncRoot)
{
if (_activeHighlights.ContainsKey(category))
{
_activeHighlights.Remove(category);
ResetAllHighlights(document);
ReapplyHighlights(document);
}
var collection = BuildCollection(items);
if (collection.Count == 0)
{
_activeHighlights.Remove(category);
return;
}
document.Models.OverrideTemporaryColor(collection, color);
_activeHighlights[category] = new HighlightEntry
{
Color = color,
Items = collection
};
RequestRedraw(document);
}
}
public static void HighlightItems(string category, IEnumerable<ModelItem> items)
{
if (string.IsNullOrWhiteSpace(category))
{
category = "default";
}
var color = GetCategoryColor(category);
HighlightItems(category, items, color);
}
/// <summary>
/// 清除指定类别的高亮。
/// </summary>
public static void ClearCategory(string category)
{
if (string.IsNullOrWhiteSpace(category))
return;
var document = Application.ActiveDocument;
if (document?.Models == null)
return;
lock (_syncRoot)
{
if (!_activeHighlights.Remove(category))
return;
ResetAllHighlights(document);
ReapplyHighlights(document);
RequestRedraw(document);
}
}
/// <summary>
/// 清除全部高亮。
/// </summary>
public static void ClearAllHighlights()
{
var document = Application.ActiveDocument;
if (document?.Models == null)
return;
lock (_syncRoot)
{
ResetAllHighlights(document);
_activeHighlights.Clear();
RequestRedraw(document);
}
}
/// <summary>
/// 获取当前高亮快照。
/// </summary>
public static List<HighlightInfo> GetActiveHighlightSnapshot()
{
lock (_syncRoot)
{
return _activeHighlights
.Select(kvp => new HighlightInfo
{
Category = kvp.Key,
Color = kvp.Value.Color,
Count = kvp.Value.Items?.Count ?? 0
})
.ToList();
}
}
public static Color GetCategoryColor(string category)
{
if (string.IsNullOrWhiteSpace(category))
{
category = "default";
}
if (_categoryColors.TryGetValue(category, out var color))
{
return color;
}
return Color.White;
}
private static ModelItemCollection BuildCollection(IEnumerable<ModelItem> items)
{
var collection = new ModelItemCollection();
if (items == null)
return collection;
foreach (var item in items)
{
if (item == null)
continue;
try
{
// 访问属性以检测对象是否有效
_ = item.DisplayName;
}
catch
{
continue;
}
if (!collection.Contains(item))
{
collection.Add(item);
}
}
return collection;
}
private static void ResetAllHighlights(Document document)
{
document.Models.ResetAllTemporaryMaterials();
}
private static void ReapplyHighlights(Document document)
{
foreach (var entry in _activeHighlights.Values)
{
if (entry.Items == null || entry.Items.Count == 0)
continue;
document.Models.OverrideTemporaryColor(entry.Items, entry.Color);
}
}
private static void RequestRedraw(Document document)
{
try
{
document.ActiveView?.RequestDelayedRedraw(ViewRedrawRequests.All);
}
catch
{
// 忽略重绘异常
}
}
}
}