NavisworksTransport/src/Utils/ModelHighlightHelper.cs
2026-01-14 13:18:43 +08:00

402 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 PrecomputeCollisionResultsCategory = "collisionResults";
public const string ManualTargetsCategory = "manualTargets";
public const string ChannelPreviewCategory = "channelPreview";
public const string ClashDetectiveResultsCategory = "clashDetectiveResults";
public const string AnimatedObjectCategory = "animatedObject";
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) },
{ PrecomputeCollisionResultsCategory, Color.FromByteRGB(244, 67, 54) }, // Material Red预计算碰撞
{ ChannelPreviewCategory, Color.Green },
{ ClashDetectiveResultsCategory, Color.Red },
{ AnimatedObjectCategory, Color.FromByteRGB(76, 175, 80) } // Material Green动画车辆
};
/// <summary>
/// 高亮指定对象集合(使用类别默认颜色)。
/// </summary>
public static void HighlightItems(string category, IEnumerable<ModelItem> items)
{
if (items == null)
return;
var document = Application.ActiveDocument;
if (document?.Models == null)
return;
if (string.IsNullOrWhiteSpace(category))
{
category = "default";
}
var color = GetCategoryColor(category);
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);
}
}
/// <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>
/// 清除所有碰撞相关高亮预计算碰撞和ClashDetective碰撞
/// </summary>
public static void ClearCollisionHighlights()
{
lock (_syncRoot)
{
ClearCategory(PrecomputeCollisionResultsCategory);
ClearCategory(ClashDetectiveResultsCategory);
}
}
/// <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
{
// 忽略重绘异常
}
}
#region
/// <summary>
/// 高亮显示碰撞对象(使用类别默认颜色)
/// </summary>
/// <param name="results">碰撞结果列表</param>
/// <param name="clearPrevious">是否清除之前的高亮</param>
public static void HighlightCollisionResults(List<CollisionResult> results, bool clearPrevious = true)
{
try
{
var validResults = results?.Where(r => r != null).ToList() ?? new List<CollisionResult>();
if (validResults.Count == 0)
{
if (clearPrevious)
{
ClearCategory(PrecomputeCollisionResultsCategory);
}
return;
}
if (clearPrevious)
{
ClearCategory(PrecomputeCollisionResultsCategory);
}
var highlightItems = new List<ModelItem>();
foreach (var collision in validResults)
{
var item1 = collision.Item1;
var item2 = collision.Item2;
// 只高亮被撞物体Item2排除车辆对象Item1
// 车辆对象由 AnimatedObjectCategory 单独高亮为绿色
if (item2 != null && !highlightItems.Contains(item2))
{
highlightItems.Add(item2);
}
}
HighlightItems(PrecomputeCollisionResultsCategory, highlightItems);
}
catch (Exception ex)
{
LogManager.Error($"高亮显示碰撞对象失败: {ex.Message}");
}
}
/// <summary>
/// 按类别管理碰撞结果高亮
/// </summary>
/// <param name="category">类别名称</param>
/// <param name="results">碰撞结果列表</param>
/// <param name="clearOtherCategories">是否清除其他类别</param>
public static void ManageCollisionHighlightsByCategory(string category, List<CollisionResult> results,
bool clearOtherCategories = false)
{
try
{
var collidingItems = new List<ModelItem>();
if (results != null)
{
foreach (var result in results)
{
var item1 = result.Item1;
var item2 = result.Item2;
// 只高亮被撞物体Item2排除车辆对象Item1
if (item2 != null && !collidingItems.Contains(item2))
{
collidingItems.Add(item2);
}
}
}
if (clearOtherCategories)
{
ClearCategory(category);
}
HighlightItems(category, collidingItems);
}
catch (Exception ex)
{
LogManager.Error($"按类别管理碰撞高亮失败 [{category}]: {ex.Message}");
}
}
/// <summary>
/// 高亮ClashDetective测试结果
/// </summary>
/// <param name="testName">测试名称</param>
/// <param name="getResultsFunc">获取碰撞结果的函数</param>
public static void HighlightClashDetectiveResults(string testName, Func<string, List<CollisionResult>> getResultsFunc)
{
try
{
if (getResultsFunc == null)
{
LogManager.Warning("[ClashDetective高亮] 获取结果的函数为空");
return;
}
// 获取碰撞结果
var clashResults = getResultsFunc(testName);
if (clashResults == null || clashResults.Count == 0)
{
LogManager.Info("[ClashDetective高亮] 指定测试中未找到碰撞结果");
return;
}
// 提取碰撞对象
var highlightItems = new List<ModelItem>();
foreach (var clash in clashResults)
{
// 只高亮被撞物体Item2排除车辆对象Item1
// 🔥 移除去重逻辑:应该显示所有被撞物体,包括重复的
if (clash.Item2 != null)
{
highlightItems.Add(clash.Item2);
}
}
if (highlightItems.Count > 0)
{
HighlightItems(ClashDetectiveResultsCategory, highlightItems);
LogManager.Info($"[ClashDetective高亮] 已高亮 {highlightItems.Count} 个对象,来自 {clashResults.Count} 个碰撞结果");
}
else
{
LogManager.Info("[ClashDetective高亮] 没有有效的碰撞对象可高亮");
}
}
catch (Exception ex)
{
LogManager.Error($"[ClashDetective高亮] 高亮失败: {ex.Message}");
}
}
/// <summary>
/// 清除ClashDetective高亮
/// </summary>
public static void ClearClashDetectiveHighlights()
{
try
{
ClearCategory(ClashDetectiveResultsCategory);
LogManager.Info("[ClashDetective高亮] 已清除高亮");
}
catch (Exception ex)
{
LogManager.Error($"[ClashDetective高亮] 清除高亮失败: {ex.Message}");
}
}
#endregion
}
}