增加碰撞构件清单

This commit is contained in:
tian 2026-01-14 13:18:43 +08:00
parent 760786d9b1
commit 519382f375
6 changed files with 268 additions and 30 deletions

View File

@ -2440,7 +2440,7 @@ namespace NavisworksTransport.Core.Animation
else
{
// 无碰撞:清除碰撞高亮(保留车辆高亮)
ModelHighlightHelper.ClearCategory(ModelHighlightHelper.CollisionResultsCategory);
ModelHighlightHelper.ClearCategory(ModelHighlightHelper.PrecomputeCollisionResultsCategory);
LogManager.Debug($"[高亮状态] 帧{_currentFrameIndex}: 清除碰撞高亮");
}

View File

@ -17,7 +17,7 @@ namespace NavisworksTransport
public class ClashDetectiveIntegration
{
private static ClashDetectiveIntegration _instance;
private const string CollisionHighlightsCategory = ModelHighlightHelper.CollisionResultsCategory;
private const string CollisionHighlightsCategory = ModelHighlightHelper.PrecomputeCollisionResultsCategory;
private DocumentClash _documentClash;
private List<ClashResult> _currentCollisions;

View File

@ -77,30 +77,78 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public Guid InstanceGuid { get; }
}
/// <summary>
/// 碰撞构件ViewModel
/// </summary>
public class CollisionObjectViewModel
{
public int Index { get; set; }
public string DisplayName { get; set; }
public string ObjectName { get; set; }
public string ModelPath { get; set; }
public int ResultId { get; set; }
public string TestName { get; set; }
public int? ModelIndex { get; set; }
public string PathId { get; set; }
public ModelItem ModelItem { get; set; }
public ICommand HighlightCommand { get; set; }
public ICommand ClearHighlightCommand { get; set; }
}
/// <summary>
/// ClashDetective碰撞检测结果视图模型
/// </summary>
public class ClashDetectiveResultViewModel
{
private readonly Action _refreshCallback;
public ClashDetectiveResultViewModel(ClashDetectiveResultRecord record, Action refreshCallback)
{
Record = record ?? throw new ArgumentNullException(nameof(record));
_refreshCallback = refreshCallback ?? throw new ArgumentNullException(nameof(refreshCallback));
ViewCommand = new RelayCommand(() => ExecuteView());
ReportCommand = new RelayCommand(() => ExecuteReport());
DeleteCommand = new RelayCommand(() => ExecuteDelete());
}
private readonly Action _refreshCallback;
public ClashDetectiveResultViewModel(ClashDetectiveResultRecord record, Action refreshCallback)
{
Record = record ?? throw new ArgumentNullException(nameof(record));
_refreshCallback = refreshCallback ?? throw new ArgumentNullException(nameof(refreshCallback));
ViewCommand = new RelayCommand(() => ExecuteView());
ReportCommand = new RelayCommand(() => ExecuteReport());
DeleteCommand = new RelayCommand(() => ExecuteDelete());
CollisionObjects = new ObservableCollection<CollisionObjectViewModel>();
}
public ClashDetectiveResultRecord Record { get; }
public string TestTimeDisplay => Record.TestTime.ToString("MM-dd HH:mm:ss");
public string CollisionCountDisplay => $"{Record.CollisionCount}个";
public ICommand ViewCommand { get; }
public ICommand ReportCommand { get; }
public ICommand DeleteCommand { get; }
public ObservableCollection<CollisionObjectViewModel> CollisionObjects { get; }
public void ExecuteHighlightCollisionObject(CollisionObjectViewModel collisionObject)
{
if (collisionObject == null) return;
public ClashDetectiveResultRecord Record { get; }
public string TestTimeDisplay => Record.TestTime.ToString("MM-dd HH:mm:ss");
public string CollisionCountDisplay => $"{Record.CollisionCount}个";
public ICommand ViewCommand { get; }
public ICommand ReportCommand { get; }
public ICommand DeleteCommand { get; }
try
{
LogManager.Info($"[碰撞构件] 高亮显示构件: {collisionObject.DisplayName}");
private void ExecuteView()
// 清除之前的高亮
ModelHighlightHelper.ClearAllHighlights();
// 直接使用ModelItem高亮
if (collisionObject.ModelItem != null && ModelItemAnalysisHelper.IsModelItemValid(collisionObject.ModelItem))
{
ModelHighlightHelper.HighlightItems(
ModelHighlightHelper.ClashDetectiveResultsCategory,
new[] { collisionObject.ModelItem });
LogManager.Info($"[碰撞构件] 已高亮构件: {collisionObject.DisplayName}");
}
else
{
LogManager.Warning($"[碰撞构件] ModelItem无效或为空: {collisionObject.DisplayName}");
}
}
catch (Exception ex)
{
LogManager.Error($"[碰撞构件] 高亮显示失败: {ex.Message}", ex);
}
} private void ExecuteView()
{
// 高亮显示该次检测的碰撞对象
var clashIntegration = ClashDetectiveIntegration.Instance;
@ -191,7 +239,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private DateTime? _manualTargetsLastSyncTime;
private const int ManualCollisionTargetLimit = 60;
private const string ManualTargetsHighlightCategory = ModelHighlightHelper.ManualTargetsCategory;
private const string CollisionResultsHighlightCategory = ModelHighlightHelper.CollisionResultsCategory;
private const string CollisionResultsHighlightCategory = ModelHighlightHelper.PrecomputeCollisionResultsCategory;
#endregion
@ -596,13 +644,29 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#region ClashDetective结果管理
private ObservableCollection<ClashDetectiveResultViewModel> _clashDetectiveResults = new ObservableCollection<ClashDetectiveResultViewModel>();
private ClashDetectiveResultViewModel _selectedClashDetectiveResult;
public ObservableCollection<ClashDetectiveResultViewModel> ClashDetectiveResults => _clashDetectiveResults;
public ClashDetectiveResultViewModel SelectedClashDetectiveResult
{
get => _selectedClashDetectiveResult;
set
{
if (_selectedClashDetectiveResult != value)
{
_selectedClashDetectiveResult = value;
OnPropertyChanged();
}
}
}
public ICommand RefreshClashDetectiveResultsCommand { get; private set; }
#endregion
#region
/// <summary>
@ -753,6 +817,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
DocumentStateManager.Instance.DocumentInvalidated += OnDocumentInvalidated;
DocumentStateManager.Instance.DocumentReady += OnDocumentReady;
// 设置静态实例
_instance = this;
LogManager.Info("AnimationControlViewModel初始化完成 - 支持统一状态栏");
}
catch (Exception ex)
@ -1770,7 +1837,61 @@ namespace NavisworksTransport.UI.WPF.ViewModels
foreach (var record in records)
{
_clashDetectiveResults.Add(new ClashDetectiveResultViewModel(record, RefreshClashDetectiveResultsList));
var resultViewModel = new ClashDetectiveResultViewModel(record, RefreshClashDetectiveResultsList);
// 同时加载该结果的碰撞构件清单
var collisionObjectRecords = pathDatabase.GetClashDetectiveCollisionObjects(record.Id);
if (collisionObjectRecords != null)
{
int index = 1;
foreach (var objRecord in collisionObjectRecords)
{
CollisionObjectViewModel objViewModel = null;
ModelItem modelItem = null;
string modelPath = "路径获取失败";
// 通过 ModelIndex 和 PathId 重建 ModelItem
if (objRecord.ModelIndex.HasValue && !string.IsNullOrEmpty(objRecord.PathId))
{
try
{
var pathIdObj = new Autodesk.Navisworks.Api.DocumentParts.ModelItemPathId
{
ModelIndex = objRecord.ModelIndex.Value,
PathId = objRecord.PathId
};
modelItem = Application.ActiveDocument.Models.ResolvePathId(pathIdObj);
// 获取完整的节点树路径
if (modelItem != null)
{
modelPath = BuildModelPath(modelItem);
}
}
catch (Exception ex)
{
LogManager.Warning($"[碰撞构件] 无法通过 PathId 找到 ModelItem: ModelIndex={objRecord.ModelIndex}, PathId={objRecord.PathId}, 错误: {ex.Message}");
}
}
objViewModel = new CollisionObjectViewModel
{
Index = index++,
DisplayName = objRecord.DisplayName,
ObjectName = objRecord.ObjectName,
ModelPath = modelPath,
ResultId = objRecord.ResultId,
TestName = record.TestName,
ModelIndex = objRecord.ModelIndex,
PathId = objRecord.PathId,
ModelItem = modelItem,
HighlightCommand = new RelayCommand(() => resultViewModel.ExecuteHighlightCollisionObject(objViewModel))
};
resultViewModel.CollisionObjects.Add(objViewModel);
}
}
_clashDetectiveResults.Add(resultViewModel);
}
// 更新HasClashDetectiveResults属性

View File

@ -432,7 +432,9 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
MinHeight="120"
MaxHeight="200"
BorderBrush="#FFE2E8F0"
BorderThickness="1">
BorderThickness="1"
SelectionMode="Single"
SelectionChanged="OnClashDetectiveResultSelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="测试名称" Width="140">
@ -461,7 +463,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="操作" Width="200">
<GridViewColumn Header="操作" Width="260">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
@ -495,7 +497,73 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
</StackPanel>
</Border>
<!-- 区域6: 当前路径信息 -->
<!-- 区域7: 碰撞构件清单 -->
<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 ClearClashDetectiveHighlightsCommand}"
Style="{StaticResource SecondaryButtonStyle}"
Height="22"
Padding="8,2"
Margin="0,0,0,0"/>
</Grid>
<TextBlock Text="请先在碰撞检测历史中选择一个检测结果"
Style="{StaticResource StatusTextStyle}"
Foreground="#FF777777"
Visibility="{Binding ClashDetectiveResults.Count, Converter={StaticResource BoolToVisConverter}, ConverterParameter=Inverse}"
Margin="0,5,0,0"/>
<ListView ItemsSource="{Binding SelectedClashDetectiveResult.CollisionObjects}"
Margin="0,5,0,0"
Visibility="{Binding SelectedClashDetectiveResult.CollisionObjects.Count, Converter={StaticResource BoolToVisConverter}}"
MinHeight="120"
MaxHeight="200"
BorderBrush="#FFE2E8F0"
BorderThickness="1"
SelectionMode="Single"
SelectionChanged="OnCollisionObjectSelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="序号" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Index}"
HorizontalAlignment="Center"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="构件名称" Width="400">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding DisplayName}"
FontWeight="SemiBold"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding DisplayName}"/>
<TextBlock Text="{Binding ModelPath}"
Style="{StaticResource StatusTextStyle}"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding ModelPath}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
</Border>
<!-- 区域8: 当前路径信息 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,0,0,0" Padding="12">
<StackPanel>
<Label Content="当前路径信息" Style="{StaticResource SectionHeaderStyle}"/>

View File

@ -82,5 +82,54 @@ namespace NavisworksTransport.UI.WPF.Views
LogManager.Error($"AnimationControlView资源清理失败: {ex.Message}");
}
}
/// <summary>
/// 碰撞检测结果选择变化事件处理
/// </summary>
private void OnClashDetectiveResultSelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
if (ViewModel == null) return;
// 获取选中的结果
var listView = sender as ListView;
if (listView?.SelectedItem is ClashDetectiveResultViewModel selectedResult)
{
ViewModel.SelectedClashDetectiveResult = selectedResult;
}
else
{
ViewModel.SelectedClashDetectiveResult = null;
}
}
catch (Exception ex)
{
LogManager.Error($"[AnimationControlView] 处理碰撞检测结果选择变化失败: {ex.Message}", ex);
}
}
/// <summary>
/// 碰撞构件选择变化事件处理
/// </summary>
private void OnCollisionObjectSelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
if (ViewModel == null || ViewModel.SelectedClashDetectiveResult == null) return;
// 获取选中的构件
var listView = sender as ListView;
if (listView?.SelectedItem is CollisionObjectViewModel selectedObject)
{
// 触发高亮
ViewModel.SelectedClashDetectiveResult.ExecuteHighlightCollisionObject(selectedObject);
}
}
catch (Exception ex)
{
LogManager.Error($"[AnimationControlView] 处理碰撞构件选择变化失败: {ex.Message}", ex);
}
}
}
}

View File

@ -10,7 +10,7 @@ namespace NavisworksTransport.Utils
/// </summary>
public static class ModelHighlightHelper
{
public const string CollisionResultsCategory = "collisionResults";
public const string PrecomputeCollisionResultsCategory = "collisionResults";
public const string ManualTargetsCategory = "manualTargets";
public const string ChannelPreviewCategory = "channelPreview";
public const string ClashDetectiveResultsCategory = "clashDetectiveResults";
@ -43,7 +43,7 @@ namespace NavisworksTransport.Utils
{ "report", Color.Green },
{ "preview", Color.Blue },
{ ManualTargetsCategory, Color.FromByteRGB(255, 170, 0) },
{ CollisionResultsCategory, Color.FromByteRGB(244, 67, 54) }, // Material Red预计算碰撞
{ PrecomputeCollisionResultsCategory, Color.FromByteRGB(244, 67, 54) }, // Material Red预计算碰撞
{ ChannelPreviewCategory, Color.Green },
{ ClashDetectiveResultsCategory, Color.Red },
{ AnimatedObjectCategory, Color.FromByteRGB(76, 175, 80) } // Material Green动画车辆
@ -125,7 +125,7 @@ namespace NavisworksTransport.Utils
{
lock (_syncRoot)
{
ClearCategory(CollisionResultsCategory);
ClearCategory(PrecomputeCollisionResultsCategory);
ClearCategory(ClashDetectiveResultsCategory);
}
}
@ -255,14 +255,14 @@ namespace NavisworksTransport.Utils
{
if (clearPrevious)
{
ClearCategory(CollisionResultsCategory);
ClearCategory(PrecomputeCollisionResultsCategory);
}
return;
}
if (clearPrevious)
{
ClearCategory(CollisionResultsCategory);
ClearCategory(PrecomputeCollisionResultsCategory);
}
var highlightItems = new List<ModelItem>();
@ -279,7 +279,7 @@ namespace NavisworksTransport.Utils
}
}
HighlightItems(CollisionResultsCategory, highlightItems);
HighlightItems(PrecomputeCollisionResultsCategory, highlightItems);
}
catch (Exception ex)
{