diff --git a/XplorePlane/ViewModels/ImageProcessing/BgaDetectionViewModel.cs b/XplorePlane/ViewModels/ImageProcessing/BgaDetectionViewModel.cs
index 55885f3..f30ea24 100644
--- a/XplorePlane/ViewModels/ImageProcessing/BgaDetectionViewModel.cs
+++ b/XplorePlane/ViewModels/ImageProcessing/BgaDetectionViewModel.cs
@@ -481,6 +481,10 @@ namespace XplorePlane.ViewModels.ImageProcessing
pipeline.UpdatedAt = DateTime.UtcNow;
targetModuleNode.Pipeline = pipeline;
+ // 强制刷新右侧检测模块面板:将选中节点切换到目标检测模块,触发重新加载
+ _cncEditorViewModel.SelectedNode = null;
+ _cncEditorViewModel.SelectedNode = targetModuleNode;
+
MessageBox.Show(
$"已将 BGA 检测参数插入到检测模块「{targetModuleNode.Name}」。",
"插入成功", MessageBoxButton.OK, MessageBoxImage.Information);
diff --git a/XplorePlane/ViewModels/ImageProcessing/VoidDetectionViewModel.cs b/XplorePlane/ViewModels/ImageProcessing/VoidDetectionViewModel.cs
index 96e7646..bc1296a 100644
--- a/XplorePlane/ViewModels/ImageProcessing/VoidDetectionViewModel.cs
+++ b/XplorePlane/ViewModels/ImageProcessing/VoidDetectionViewModel.cs
@@ -14,24 +14,35 @@ using Prism.Mvvm;
using XP.ImageProcessing.Processors;
using XP.ImageProcessing.RoiControl.Controls;
using XP.ImageProcessing.RoiControl.Models;
+using XplorePlane.Models;
using XplorePlane.Services.MainViewport;
+using XplorePlane.ViewModels.Cnc;
namespace XplorePlane.ViewModels.ImageProcessing
{
public class VoidDetectionViewModel : BindableBase
{
private readonly IMainViewportService _viewportService;
+ private CncEditorViewModel _cncEditorViewModel;
private BitmapSource _originalImage;
private System.Threading.CancellationTokenSource _debounceCts;
private const int DebounceMs = 300;
+ private const string VoidMeasurementOperatorKey = "VoidMeasurement";
public VoidDetectionViewModel(IMainViewportService viewportService)
{
_viewportService = viewportService;
ExecuteCommand = new DelegateCommand(Execute);
+ InsertToCncCommand = new DelegateCommand(ExecuteInsertToCnc);
PropertyChanged += OnAnyPropertyChanged;
}
+ /// 设置 CNC 编辑器 ViewModel 引用,用于插入参数到激活的 CNC 位置节点
+ public void SetCncEditorViewModel(CncEditorViewModel cncEditorViewModel)
+ {
+ _cncEditorViewModel = cncEditorViewModel;
+ }
+
private void OnAnyPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ResultText) || e.PropertyName == nameof(ResultImage) || e.PropertyName == nameof(RoiEnabled))
@@ -166,6 +177,7 @@ namespace XplorePlane.ViewModels.ImageProcessing
public ObservableCollection Results { get; } = new();
public DelegateCommand ExecuteCommand { get; }
+ public DelegateCommand InsertToCncCommand { get; }
private void Execute()
{
@@ -235,6 +247,113 @@ namespace XplorePlane.ViewModels.ImageProcessing
}
}
+ ///
+ /// 将当前 ROI 和算子参数插入到激活的 CNC 位置节点的检测模块中空隙检测模块的参数
+ ///
+ 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()
+ };
+ 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)
{
if (_canvas == null) return;
diff --git a/XplorePlane/Views/ImageProcessing/BgaDetectionPanel.xaml b/XplorePlane/Views/ImageProcessing/BgaDetectionPanel.xaml
index 884d4df..e9991b7 100644
--- a/XplorePlane/Views/ImageProcessing/BgaDetectionPanel.xaml
+++ b/XplorePlane/Views/ImageProcessing/BgaDetectionPanel.xaml
@@ -76,12 +76,12 @@
+
-
diff --git a/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml b/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml
index 71a9587..2a4fa06 100644
--- a/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml
+++ b/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml
@@ -72,9 +72,13 @@
-