孔隙检测模块引入到CNC
This commit is contained in:
@@ -481,6 +481,10 @@ namespace XplorePlane.ViewModels.ImageProcessing
|
|||||||
pipeline.UpdatedAt = DateTime.UtcNow;
|
pipeline.UpdatedAt = DateTime.UtcNow;
|
||||||
targetModuleNode.Pipeline = pipeline;
|
targetModuleNode.Pipeline = pipeline;
|
||||||
|
|
||||||
|
// 强制刷新右侧检测模块面板:将选中节点切换到目标检测模块,触发重新加载
|
||||||
|
_cncEditorViewModel.SelectedNode = null;
|
||||||
|
_cncEditorViewModel.SelectedNode = targetModuleNode;
|
||||||
|
|
||||||
MessageBox.Show(
|
MessageBox.Show(
|
||||||
$"已将 BGA 检测参数插入到检测模块「{targetModuleNode.Name}」。",
|
$"已将 BGA 检测参数插入到检测模块「{targetModuleNode.Name}」。",
|
||||||
"插入成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
"插入成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
|||||||
@@ -14,24 +14,35 @@ using Prism.Mvvm;
|
|||||||
using XP.ImageProcessing.Processors;
|
using XP.ImageProcessing.Processors;
|
||||||
using XP.ImageProcessing.RoiControl.Controls;
|
using XP.ImageProcessing.RoiControl.Controls;
|
||||||
using XP.ImageProcessing.RoiControl.Models;
|
using XP.ImageProcessing.RoiControl.Models;
|
||||||
|
using XplorePlane.Models;
|
||||||
using XplorePlane.Services.MainViewport;
|
using XplorePlane.Services.MainViewport;
|
||||||
|
using XplorePlane.ViewModels.Cnc;
|
||||||
|
|
||||||
namespace XplorePlane.ViewModels.ImageProcessing
|
namespace XplorePlane.ViewModels.ImageProcessing
|
||||||
{
|
{
|
||||||
public class VoidDetectionViewModel : BindableBase
|
public class VoidDetectionViewModel : BindableBase
|
||||||
{
|
{
|
||||||
private readonly IMainViewportService _viewportService;
|
private readonly IMainViewportService _viewportService;
|
||||||
|
private CncEditorViewModel _cncEditorViewModel;
|
||||||
private BitmapSource _originalImage;
|
private BitmapSource _originalImage;
|
||||||
private System.Threading.CancellationTokenSource _debounceCts;
|
private System.Threading.CancellationTokenSource _debounceCts;
|
||||||
private const int DebounceMs = 300;
|
private const int DebounceMs = 300;
|
||||||
|
private const string VoidMeasurementOperatorKey = "VoidMeasurement";
|
||||||
|
|
||||||
public VoidDetectionViewModel(IMainViewportService viewportService)
|
public VoidDetectionViewModel(IMainViewportService viewportService)
|
||||||
{
|
{
|
||||||
_viewportService = viewportService;
|
_viewportService = viewportService;
|
||||||
ExecuteCommand = new DelegateCommand(Execute);
|
ExecuteCommand = new DelegateCommand(Execute);
|
||||||
|
InsertToCncCommand = new DelegateCommand(ExecuteInsertToCnc);
|
||||||
PropertyChanged += OnAnyPropertyChanged;
|
PropertyChanged += OnAnyPropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>设置 CNC 编辑器 ViewModel 引用,用于插入参数到激活的 CNC 位置节点</summary>
|
||||||
|
public void SetCncEditorViewModel(CncEditorViewModel cncEditorViewModel)
|
||||||
|
{
|
||||||
|
_cncEditorViewModel = cncEditorViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnAnyPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
private void OnAnyPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.PropertyName == nameof(ResultText) || e.PropertyName == nameof(ResultImage) || e.PropertyName == nameof(RoiEnabled))
|
if (e.PropertyName == nameof(ResultText) || e.PropertyName == nameof(ResultImage) || e.PropertyName == nameof(RoiEnabled))
|
||||||
@@ -166,6 +177,7 @@ namespace XplorePlane.ViewModels.ImageProcessing
|
|||||||
public ObservableCollection<VoidResultItem> Results { get; } = new();
|
public ObservableCollection<VoidResultItem> Results { get; } = new();
|
||||||
|
|
||||||
public DelegateCommand ExecuteCommand { get; }
|
public DelegateCommand ExecuteCommand { get; }
|
||||||
|
public DelegateCommand InsertToCncCommand { get; }
|
||||||
|
|
||||||
private void Execute()
|
private void Execute()
|
||||||
{
|
{
|
||||||
@@ -235,6 +247,113 @@ namespace XplorePlane.ViewModels.ImageProcessing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将当前 ROI 和算子参数插入到激活的 CNC 位置节点的检测模块中空隙检测模块的参数
|
||||||
|
/// </summary>
|
||||||
|
private void ExecuteInsertToCnc()
|
||||||
|
{
|
||||||
|
if (_cncEditorViewModel == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show("CNC 编辑器未就绪,无法插入参数。", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedNode = _cncEditorViewModel.SelectedNode;
|
||||||
|
CncNodeViewModel targetModuleNode = null;
|
||||||
|
|
||||||
|
if (selectedNode == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show("请先在 CNC 编辑器中选择一个位置节点或检测模块。", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedNode.IsInspectionModule)
|
||||||
|
{
|
||||||
|
targetModuleNode = selectedNode;
|
||||||
|
}
|
||||||
|
else if (selectedNode.IsSavePosition)
|
||||||
|
{
|
||||||
|
targetModuleNode = selectedNode.Children.FirstOrDefault(c => c.IsInspectionModule);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var allNodes = _cncEditorViewModel.Nodes;
|
||||||
|
CncNodeViewModel ownerPosition = null;
|
||||||
|
foreach (var node in allNodes)
|
||||||
|
{
|
||||||
|
if (node.IsSavePosition)
|
||||||
|
ownerPosition = node;
|
||||||
|
if (node.Id == selectedNode.Id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ownerPosition != null)
|
||||||
|
targetModuleNode = ownerPosition.Children.FirstOrDefault(c => c.IsInspectionModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetModuleNode == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show("未找到激活的检测模块节点。\n请在 CNC 编辑器中选择一个包含检测模块的位置节点。", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取或创建 Pipeline
|
||||||
|
var pipeline = targetModuleNode.Pipeline ?? new PipelineModel { Name = targetModuleNode.Name };
|
||||||
|
|
||||||
|
// 查找已有的 VoidMeasurement 算子节点
|
||||||
|
var voidNode = pipeline.Nodes.FirstOrDefault(n =>
|
||||||
|
string.Equals(n.OperatorKey, VoidMeasurementOperatorKey, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (voidNode == null)
|
||||||
|
{
|
||||||
|
voidNode = new PipelineNodeModel
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
OperatorKey = VoidMeasurementOperatorKey,
|
||||||
|
Order = pipeline.Nodes.Count,
|
||||||
|
IsEnabled = true,
|
||||||
|
Parameters = new Dictionary<string, object>()
|
||||||
|
};
|
||||||
|
pipeline.Nodes.Add(voidNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入当前参数
|
||||||
|
var parameters = voidNode.Parameters;
|
||||||
|
parameters["MinThreshold"] = MinThreshold;
|
||||||
|
parameters["MaxThreshold"] = MaxThreshold;
|
||||||
|
parameters["MinVoidArea"] = MinVoidArea;
|
||||||
|
parameters["MergeRadius"] = MergeRadius;
|
||||||
|
parameters["BlurSize"] = BlurSize;
|
||||||
|
parameters["VoidLimit"] = VoidLimit;
|
||||||
|
|
||||||
|
// 写入 ROI 参数
|
||||||
|
if (RoiEnabled && _roiShape != null && _roiShape.Points.Count >= 3)
|
||||||
|
{
|
||||||
|
int count = Math.Min(_roiShape.Points.Count, 32);
|
||||||
|
parameters["PolyCount"] = count;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
parameters[$"PolyX{i}"] = (int)_roiShape.Points[i].X;
|
||||||
|
parameters[$"PolyY{i}"] = (int)_roiShape.Points[i].Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parameters["PolyCount"] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新 Pipeline 到节点
|
||||||
|
pipeline.UpdatedAt = DateTime.UtcNow;
|
||||||
|
targetModuleNode.Pipeline = pipeline;
|
||||||
|
|
||||||
|
// 强制刷新右侧检测模块面板
|
||||||
|
_cncEditorViewModel.SelectedNode = null;
|
||||||
|
_cncEditorViewModel.SelectedNode = targetModuleNode;
|
||||||
|
|
||||||
|
MessageBox.Show(
|
||||||
|
$"已将空隙检测参数插入到检测模块「{targetModuleNode.Name}」。",
|
||||||
|
"插入成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
}
|
||||||
|
|
||||||
private void ShowResultOnOverlay(BitmapSource resultBmp)
|
private void ShowResultOnOverlay(BitmapSource resultBmp)
|
||||||
{
|
{
|
||||||
if (_canvas == null) return;
|
if (_canvas == null) return;
|
||||||
|
|||||||
@@ -76,12 +76,12 @@
|
|||||||
<Button Style="{StaticResource IconBtnStyle}" Command="{Binding ExecuteCommand}" ToolTip="执行检测" Margin="0,0,6,0">
|
<Button Style="{StaticResource IconBtnStyle}" Command="{Binding ExecuteCommand}" ToolTip="执行检测" Margin="0,0,6,0">
|
||||||
<Image Source="/Assets/Icons/run32.png" Width="20" Height="20" />
|
<Image Source="/Assets/Icons/run32.png" Width="20" Height="20" />
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button Style="{StaticResource IconBtnStyle}" Click="Close_Click" ToolTip="关闭" Margin="0,0,6,0">
|
||||||
|
<Image Source="/Assets/Icons/ok.png" Width="20" Height="20" />
|
||||||
|
</Button>
|
||||||
<Button Style="{StaticResource IconBtnStyle}" Command="{Binding InsertToCncCommand}" ToolTip="将当前参数插入到激活的CNC检测模块" Margin="0,0,6,0">
|
<Button Style="{StaticResource IconBtnStyle}" Command="{Binding InsertToCncCommand}" ToolTip="将当前参数插入到激活的CNC检测模块" Margin="0,0,6,0">
|
||||||
<TextBlock Text="插入CNC" FontSize="11" VerticalAlignment="Center" />
|
<TextBlock Text="插入CNC" FontSize="11" VerticalAlignment="Center" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button Style="{StaticResource IconBtnStyle}" Click="Close_Click" ToolTip="关闭">
|
|
||||||
<Image Source="/Assets/Icons/ok.png" Width="20" Height="20" />
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- BGA定位参数卡片 -->
|
<!-- BGA定位参数卡片 -->
|
||||||
|
|||||||
@@ -72,9 +72,13 @@
|
|||||||
<Button Style="{StaticResource IconBtnStyle}" Command="{Binding ExecuteCommand}" ToolTip="执行检测" Margin="0,0,6,0">
|
<Button Style="{StaticResource IconBtnStyle}" Command="{Binding ExecuteCommand}" ToolTip="执行检测" Margin="0,0,6,0">
|
||||||
<Image Source="/Assets/Icons/run32.png" Width="20" Height="20" />
|
<Image Source="/Assets/Icons/run32.png" Width="20" Height="20" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button Style="{StaticResource IconBtnStyle}" Click="Close_Click" ToolTip="关闭">
|
|
||||||
|
<Button Style="{StaticResource IconBtnStyle}" Click="Close_Click" ToolTip="关闭" Margin="0,0,6,0">
|
||||||
<Image Source="/Assets/Icons/ok.png" Width="20" Height="20" />
|
<Image Source="/Assets/Icons/ok.png" Width="20" Height="20" />
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button Style="{StaticResource IconBtnStyle}" Command="{Binding InsertToCncCommand}" ToolTip="将当前参数插入到激活的CNC检测模块" Margin="0,0,6,0">
|
||||||
|
<TextBlock Text="插入CNC" FontSize="11" VerticalAlignment="Center" />
|
||||||
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- 参数卡片 -->
|
<!-- 参数卡片 -->
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System.Windows;
|
|||||||
using Prism.Ioc;
|
using Prism.Ioc;
|
||||||
using XP.ImageProcessing.RoiControl.Controls;
|
using XP.ImageProcessing.RoiControl.Controls;
|
||||||
using XplorePlane.Services.MainViewport;
|
using XplorePlane.Services.MainViewport;
|
||||||
|
using XplorePlane.ViewModels.Cnc;
|
||||||
using XplorePlane.ViewModels.ImageProcessing;
|
using XplorePlane.ViewModels.ImageProcessing;
|
||||||
|
|
||||||
namespace XplorePlane.Views.ImageProcessing
|
namespace XplorePlane.Views.ImageProcessing
|
||||||
@@ -23,6 +24,17 @@ namespace XplorePlane.Views.ImageProcessing
|
|||||||
if (DataContext is VoidDetectionViewModel vm)
|
if (DataContext is VoidDetectionViewModel vm)
|
||||||
vm.SetCanvas(canvas);
|
vm.SetCanvas(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从 MainViewModel 获取 CncEditorViewModel 引用
|
||||||
|
if (DataContext is VoidDetectionViewModel voidVm && Owner?.DataContext is ViewModels.MainViewModel mainVm)
|
||||||
|
{
|
||||||
|
var cncEditorField = mainVm.GetType().GetField("_cncEditorViewModel",
|
||||||
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||||
|
if (cncEditorField?.GetValue(mainVm) is CncEditorViewModel cncEditor)
|
||||||
|
{
|
||||||
|
voidVm.SetCncEditorViewModel(cncEditor);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Closed += (s, e) =>
|
Closed += (s, e) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user