Refine collision analysis dialog and rail assembly markers

This commit is contained in:
tian 2026-03-26 22:49:45 +08:00
parent 9f1924a797
commit a5d1db6416
4 changed files with 178 additions and 115 deletions

View File

@ -3103,50 +3103,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{ {
var dialog = new CollisionAnalysisDialog(hotspots, totalCollisions); var dialog = new CollisionAnalysisDialog(hotspots, totalCollisions);
DialogHelper.SetOwnerSafely(dialog); DialogHelper.SetOwnerSafely(dialog);
var result = dialog.ShowDialog(); dialog.Closed += (_, __) => HandleCollisionAnalysisDialogClosed(dialog, totalCollisions);
dialog.Show();
if (result == null) dialog.Activate();
{
// 用户取消
UpdateMainStatus("预计算碰撞分析已取消");
return;
}
if (dialog.ExcludedObjects.Count > 0)
{
// 用户选择了排除某些物体并重新生成
LogManager.Info($"[碰撞分析] 用户选择排除 {dialog.ExcludedObjects.Count} 个物体并重新生成");
// 🔥 添加排除对象到UI列表合并自动去重
AddExcludedObjectsToUIList(dialog.ExcludedObjects);
// 🔥 从UI列表获取所有排除对象包括之前手工添加的设置到Manager并重新生成
var allExcludedObjects = _excludedObjects.Select(e => e.ModelItem).Where(m => m != null).ToList();
_pathAnimationManager.SetExcludedObjectsAndClearCache(allExcludedObjects);
// 触发重新生成(使用 Dispatcher 避免阻塞 UI
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
ExecuteGenerateAnimation();
}), DispatcherPriority.Background);
UpdateMainStatus($"已排除 {allExcludedObjects.Count} 个物体,正在重新生成...");
}
else
{
// 用户选择直接继续(无排除对象)
LogManager.Info("[碰撞分析] 用户选择直接继续生成");
UpdateMainStatus($"预计算碰撞分析完成,共 {totalCollisions} 个候选碰撞");
// 🔥 保存检测记录到数据库(保存测试配置)
var recordId = SaveCollisionDetectionRecord();
if (recordId.HasValue && IsReusedHistoryRecord(recordId.Value))
{
// 用户选择使用历史记录,跳过后续流程
LogManager.Info("[碰撞分析] 用户选择使用历史记录,跳过动画生成");
return;
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -3154,6 +3113,57 @@ namespace NavisworksTransport.UI.WPF.ViewModels
} }
} }
private void HandleCollisionAnalysisDialogClosed(CollisionAnalysisDialog dialog, int totalCollisions)
{
try
{
if (dialog == null)
{
return;
}
switch (dialog.SelectedAction)
{
case CollisionAnalysisDialog.CollisionAnalysisAction.Regenerate:
LogManager.Info($"[碰撞分析] 用户选择排除 {dialog.ExcludedObjects.Count} 个物体并重新生成");
AddExcludedObjectsToUIList(dialog.ExcludedObjects);
var allExcludedObjects = _excludedObjects.Select(e => e.ModelItem).Where(m => m != null).ToList();
_pathAnimationManager.SetExcludedObjectsAndClearCache(allExcludedObjects);
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
ExecuteGenerateAnimation();
}), DispatcherPriority.Background);
UpdateMainStatus($"已排除 {allExcludedObjects.Count} 个物体,正在重新生成...");
break;
case CollisionAnalysisDialog.CollisionAnalysisAction.Continue:
LogManager.Info("[碰撞分析] 用户选择直接继续生成");
UpdateMainStatus($"预计算碰撞分析完成,共 {totalCollisions} 个候选碰撞");
var recordId = SaveCollisionDetectionRecord();
if (recordId.HasValue && IsReusedHistoryRecord(recordId.Value))
{
LogManager.Info("[碰撞分析] 用户选择使用历史记录,跳过动画生成");
}
break;
case CollisionAnalysisDialog.CollisionAnalysisAction.Cancel:
case CollisionAnalysisDialog.CollisionAnalysisAction.None:
default:
UpdateMainStatus("预计算碰撞分析已取消");
break;
}
}
catch (Exception ex)
{
LogManager.Error($"[碰撞分析] 处理分析窗口结果失败: {ex.Message}", ex);
}
}
/// <summary> /// <summary>
/// 保存检测记录到数据库 /// 保存检测记录到数据库
/// 在生成动画完成后调用,创建检测记录并保存当时的完整配置 /// 在生成动画完成后调用,创建检测记录并保存当时的完整配置

View File

@ -125,7 +125,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private const double DefaultAssemblyReferenceRodLengthInMeters = 20.0; private const double DefaultAssemblyReferenceRodLengthInMeters = 20.0;
private static readonly double DefaultAssemblyReferenceRodDiameterInMeters = CalculateDefaultAssemblyReferenceRodDiameterInMeters(); private static readonly double DefaultAssemblyReferenceRodDiameterInMeters = CalculateDefaultAssemblyReferenceRodDiameterInMeters();
private const double DefaultAssemblyAnchorVerticalOffsetInMeters = 0.0; private const double DefaultAssemblyAnchorVerticalOffsetInMeters = 0.0;
private const double AssemblyVisualizationPointDiameterInMeters = 0.10; private const double AssemblyVisualizationPointDiameterInMeters = 0.05;
private const double RailNormalOffsetNudgeStepInMeters = 0.1; private const double RailNormalOffsetNudgeStepInMeters = 0.1;
private const double DefaultAssemblySphereCenterX = 0.0; private const double DefaultAssemblySphereCenterX = 0.0;
private const double DefaultAssemblySphereCenterY = 0.0; private const double DefaultAssemblySphereCenterY = 0.0;
@ -1749,7 +1749,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private void CreateAssemblyLinearRoute(Point3D startPoint) private void CreateAssemblyLinearRoute(Point3D startPoint)
{ {
Point3D endPoint = AssemblyReferencePathManager.Instance.ReferenceLineEnd; Point3D endPoint = AssemblyReferencePathManager.Instance.ReferenceLineEnd;
string routeName = $"直线装配_{_pathPlanningManager.Routes.Count + 1}"; string routeName = $"人工_{DateTime.Now:MMdd_HHmmss}";
var route = new PathRoute(routeName) var route = new PathRoute(routeName)
{ {
@ -1768,7 +1768,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
_assemblyInstallationPlaneNormal.Z); _assemblyInstallationPlaneNormal.Z);
} }
route.AddPoint(new PathPoint(startPoint, "装配起点", PathPointType.StartPoint)); route.AddPoint(new PathPoint(startPoint, "起点", PathPointType.StartPoint));
route.AddPoint(new PathPoint(endPoint, "装配终点", PathPointType.EndPoint)); route.AddPoint(new PathPoint(endPoint, "装配终点", PathPointType.EndPoint));
if (!_pathPlanningManager.AddRoute(route)) if (!_pathPlanningManager.AddRoute(route))

View File

@ -8,7 +8,6 @@
Height="720" Width="720" Height="720" Width="720"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
ResizeMode="CanResize" ResizeMode="CanResize"
Topmost="True"
Background="White"> Background="White">
<Window.Resources> <Window.Resources>
@ -97,67 +96,89 @@
<!-- 热点列表 --> <!-- 热点列表 -->
<Border Grid.Row="3" BorderBrush="{StaticResource NavisworksLightBrush}" <Border Grid.Row="3" BorderBrush="{StaticResource NavisworksLightBrush}"
BorderThickness="1" CornerRadius="3" Margin="0,0,0,12"> BorderThickness="1" CornerRadius="3" Margin="0,0,0,12">
<DataGrid x:Name="HotspotsDataGrid" <Grid>
AutoGenerateColumns="False" <Grid.RowDefinitions>
CanUserAddRows="False" <RowDefinition Height="Auto"/>
SelectionMode="Single" <RowDefinition Height="*"/>
GridLinesVisibility="Horizontal" </Grid.RowDefinitions>
BorderThickness="0"
HeadersVisibility="Column" <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="10,10,10,8">
RowBackground="White" <TextBlock Text="批量选择:" VerticalAlignment="Center" FontSize="11"
AlternatingRowBackground="{StaticResource NavisworksBackgroundBrush}" Foreground="{StaticResource NavisworksTextBrush}" Margin="0,0,8,0"/>
SelectionChanged="HotspotsDataGrid_SelectionChanged"> <Button Content="全选"
<DataGrid.Columns> Width="70"
<DataGridTextColumn Header="序号" Width="45" Margin="0,0,6,0"
Binding="{Binding Index}" IsReadOnly="True"> Click="SelectAllButton_Click"
<DataGridTextColumn.ElementStyle> Style="{StaticResource SecondaryButtonStyle}"/>
<Style TargetType="TextBlock"> <Button Content="全取消"
<Setter Property="HorizontalAlignment" Value="Center"/> Width="80"
<Setter Property="FontSize" Value="11"/> Click="ClearAllButton_Click"
</Style> Style="{StaticResource SecondaryButtonStyle}"/>
</DataGridTextColumn.ElementStyle> </StackPanel>
</DataGridTextColumn>
<DataGridCheckBoxColumn Header="排除" Width="50" <DataGrid Grid.Row="1"
Binding="{Binding IsExcluded, Mode=TwoWay}"/> x:Name="HotspotsDataGrid"
<DataGridTextColumn Header="物体名称" Width="*" AutoGenerateColumns="False"
Binding="{Binding ObjectName}" IsReadOnly="True"> CanUserAddRows="False"
<DataGridTextColumn.ElementStyle> SelectionMode="Single"
<Style TargetType="TextBlock"> GridLinesVisibility="Horizontal"
<Setter Property="FontSize" Value="11"/> BorderThickness="0"
</Style> HeadersVisibility="Column"
</DataGridTextColumn.ElementStyle> RowBackground="White"
</DataGridTextColumn> AlternatingRowBackground="{StaticResource NavisworksBackgroundBrush}"
<DataGridTextColumn Header="碰撞次数" Width="80" SelectionChanged="HotspotsDataGrid_SelectionChanged">
Binding="{Binding CollisionCount}" IsReadOnly="True"> <DataGrid.Columns>
<DataGridTextColumn.ElementStyle> <DataGridTextColumn Header="序号" Width="45"
<Style TargetType="TextBlock"> Binding="{Binding Index}" IsReadOnly="True">
<Setter Property="HorizontalAlignment" Value="Center"/> <DataGridTextColumn.ElementStyle>
<Setter Property="FontSize" Value="11"/> <Style TargetType="TextBlock">
<Setter Property="FontWeight" Value="Bold"/> <Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="Black"/> <Setter Property="FontSize" Value="11"/>
</Style> </Style>
</DataGridTextColumn.ElementStyle> </DataGridTextColumn.ElementStyle>
</DataGridTextColumn> </DataGridTextColumn>
<DataGridTextColumn Header="占比" Width="60" <DataGridCheckBoxColumn Header="排除" Width="50"
Binding="{Binding Percentage, StringFormat={}{0:F1}%}" IsReadOnly="True"> Binding="{Binding IsExcluded, Mode=TwoWay}"/>
<DataGridTextColumn.ElementStyle> <DataGridTextColumn Header="物体名称" Width="*"
<Style TargetType="TextBlock"> Binding="{Binding ObjectName}" IsReadOnly="True">
<Setter Property="HorizontalAlignment" Value="Center"/> <DataGridTextColumn.ElementStyle>
<Setter Property="FontSize" Value="11"/> <Style TargetType="TextBlock">
</Style> <Setter Property="FontSize" Value="11"/>
</DataGridTextColumn.ElementStyle> </Style>
</DataGridTextColumn> </DataGridTextColumn.ElementStyle>
<DataGridTextColumn Header="原因分析" Width="200" </DataGridTextColumn>
Binding="{Binding Reason}" IsReadOnly="True"> <DataGridTextColumn Header="碰撞次数" Width="80"
<DataGridTextColumn.ElementStyle> Binding="{Binding CollisionCount}" IsReadOnly="True">
<Style TargetType="TextBlock"> <DataGridTextColumn.ElementStyle>
<Setter Property="FontSize" Value="10"/> <Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource NavisworksTextBrush}"/> <Setter Property="HorizontalAlignment" Value="Center"/>
</Style> <Setter Property="FontSize" Value="11"/>
</DataGridTextColumn.ElementStyle> <Setter Property="FontWeight" Value="Bold"/>
</DataGridTextColumn> <Setter Property="Foreground" Value="Black"/>
</DataGrid.Columns> </Style>
</DataGrid> </DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="占比" Width="60"
Binding="{Binding Percentage, StringFormat={}{0:F1}%}" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="11"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="原因分析" Width="200"
Binding="{Binding Reason}" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="{StaticResource NavisworksTextBrush}"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Border> </Border>
<!-- 选中物体详情 --> <!-- 选中物体详情 -->

View File

@ -15,8 +15,17 @@ namespace NavisworksTransport.UI.WPF.Views
/// </summary> /// </summary>
public partial class CollisionAnalysisDialog : Window public partial class CollisionAnalysisDialog : Window
{ {
public enum CollisionAnalysisAction
{
None,
Continue,
Regenerate,
Cancel
}
private List<HotspotViewModel> _viewModels; private List<HotspotViewModel> _viewModels;
public List<ModelItem> ExcludedObjects { get; private set; } public List<ModelItem> ExcludedObjects { get; private set; }
public CollisionAnalysisAction SelectedAction { get; private set; } = CollisionAnalysisAction.None;
// 使用项目中定义的预计算碰撞结果高亮类别(紫色 #9C27B0 // 使用项目中定义的预计算碰撞结果高亮类别(紫色 #9C27B0
private const string PrecomputedHighlightCategory = ModelHighlightHelper.PrecomputeCollisionResultsCategory; private const string PrecomputedHighlightCategory = ModelHighlightHelper.PrecomputeCollisionResultsCategory;
@ -122,17 +131,14 @@ namespace NavisworksTransport.UI.WPF.Views
// 清除预计算高亮 // 清除预计算高亮
ModelHighlightHelper.ClearCategory(PrecomputedHighlightCategory); ModelHighlightHelper.ClearCategory(PrecomputedHighlightCategory);
// 根据是否有排除对象设置对话框结果
if (ExcludedObjects.Count > 0) if (ExcludedObjects.Count > 0)
{ {
// 有排除对象,需要重新生成 SelectedAction = CollisionAnalysisAction.Regenerate;
DialogResult = true;
LogManager.Info($"[碰撞分析] 用户选择排除 {ExcludedObjects.Count} 个物体并重新生成"); LogManager.Info($"[碰撞分析] 用户选择排除 {ExcludedObjects.Count} 个物体并重新生成");
} }
else else
{ {
// 没有排除对象,直接继续 SelectedAction = CollisionAnalysisAction.Continue;
DialogResult = false;
LogManager.Info("[碰撞分析] 用户选择直接继续生成(无排除对象)"); LogManager.Info("[碰撞分析] 用户选择直接继续生成(无排除对象)");
} }
@ -144,10 +150,36 @@ namespace NavisworksTransport.UI.WPF.Views
// 清除预计算高亮 // 清除预计算高亮
ModelHighlightHelper.ClearCategory(PrecomputedHighlightCategory); ModelHighlightHelper.ClearCategory(PrecomputedHighlightCategory);
DialogResult = null; SelectedAction = CollisionAnalysisAction.Cancel;
Close(); Close();
} }
private void SelectAllButton_Click(object sender, RoutedEventArgs e)
{
if (_viewModels == null)
{
return;
}
foreach (var viewModel in _viewModels)
{
viewModel.IsExcluded = true;
}
}
private void ClearAllButton_Click(object sender, RoutedEventArgs e)
{
if (_viewModels == null)
{
return;
}
foreach (var viewModel in _viewModels)
{
viewModel.IsExcluded = false;
}
}
/// <summary> /// <summary>
/// 视图模型 /// 视图模型
/// </summary> /// </summary>