添加 MX-PD-盘古 项目文件

将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
Shi.Ji
2026-05-18 11:43:09 +08:00
parent 03632a379d
commit e31d3560bb
739 changed files with 99783 additions and 0 deletions

View File

@@ -0,0 +1,448 @@
using MainShell.AlgorithmCalib.Model;
using MainShell.AlgorithmCalib.Service;
using MainShell.Common;
using MainShell.Common.Display.ViewModel;
using MainShell.Hardware;
using MainShell.Motion;
using MaxwellFramework.Core.Interfaces;
using MwFramework.Controls.ControlCanvas.Model;
using MwFramework.ManagerService;
using SemiconductorVisionAlgorithm.SemiParams;
using Stylet;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using SemiPoint = SemiconductorVisionAlgorithm.SemiParams.Point;
namespace MainShell.AlgorithmCalib.ViewModel
{
/// <summary>
/// 融合对位验证VM
/// 3步对位流程抓Pad点 → Die网格飞拍 → 选择Die点对位Pad
/// </summary>
public class FusionAlignVerifyViewModel : Screen, IPage
{
private readonly FusionCalibMotionService _motionService;
private readonly HardwareManager _hardware;
private FusionAlignProcessor _alignProcessor;
private CancellationTokenSource _cts;
private ApproachAlignmentService _approachAlignmentService;
public string Name { get; set; } = "FusionAlignVerify";
public string CalibName { get; set; } = "整体对位验证";
#region
private FusionCalibModuleItem _moduleItem = new FusionCalibModuleItem();
public FusionCalibModuleItem ModuleItem
{
get => _moduleItem;
set => SetAndNotify(ref _moduleItem, value);
}
// DieFusionCalibView 绑定
public FusionCalibModuleItem WsFusionCalibParItem
{
get => _moduleItem;
set { _moduleItem = value; NotifyOfPropertyChange(nameof(WsFusionCalibParItem)); }
}
// PadFusionCalibView 绑定
public FusionCalibModuleItem FusionCalibParItem
{
get => _moduleItem;
set { _moduleItem = value; NotifyOfPropertyChange(nameof(FusionCalibParItem)); }
}
private CameraAxisViewModel _cameraAxisViewModelSevice;
public CameraAxisViewModel CameraAxisViewModelSevice
{
get => _cameraAxisViewModelSevice;
set => SetAndNotify(ref _cameraAxisViewModelSevice, value);
}
private DelegateBase _motion = new DelegateBase();
public DelegateBase Motion
{
get => _motion;
set => SetAndNotify(ref _motion, value);
}
private string _progressMessage = "";
public string ProgressMessage
{
get => _progressMessage;
set => SetAndNotify(ref _progressMessage, value);
}
private bool _isRunning;
public bool IsRunning
{
get => _isRunning;
set => SetAndNotify(ref _isRunning, value);
}
private string _alignResultText = "";
public string AlignResultText
{
get => _alignResultText;
set => SetAndNotify(ref _alignResultText, value);
}
// ===== 步骤1Pad捕获 =====
private double _padCapturedX;
public double PadCapturedX
{
get => _padCapturedX;
set => SetAndNotify(ref _padCapturedX, value);
}
private double _padCapturedY;
public double PadCapturedY
{
get => _padCapturedY;
set => SetAndNotify(ref _padCapturedY, value);
}
// ===== 步骤2Die网格飞拍 =====
private double _dieFirstX;
public double DieFirstX
{
get => _dieFirstX;
set => SetAndNotify(ref _dieFirstX, value);
}
private double _dieFirstY;
public double DieFirstY
{
get => _dieFirstY;
set => SetAndNotify(ref _dieFirstY, value);
}
private int _flyScanXCount = 3;
public int FlyScanXCount
{
get => _flyScanXCount;
set => SetAndNotify(ref _flyScanXCount, value);
}
private int _flyScanYCount = 3;
public int FlyScanYCount
{
get => _flyScanYCount;
set => SetAndNotify(ref _flyScanYCount, value);
}
private double _flyScanStep = 1.0;
public double FlyScanStep
{
get => _flyScanStep;
set => SetAndNotify(ref _flyScanStep, value);
}
private string _flyScanResultText = "";
public string FlyScanResultText
{
get => _flyScanResultText;
set => SetAndNotify(ref _flyScanResultText, value);
}
private ObservableCollection<DieGridPointDisplay> _displayDieGridPoints = new ObservableCollection<DieGridPointDisplay>();
public ObservableCollection<DieGridPointDisplay> DisplayDieGridPoints
{
get => _displayDieGridPoints;
set => SetAndNotify(ref _displayDieGridPoints, value);
}
// ===== 步骤3对位选择 =====
private int _selectedRow;
public int SelectedRow
{
get => _selectedRow;
set => SetAndNotify(ref _selectedRow, value);
}
private int _selectedCol;
public int SelectedCol
{
get => _selectedCol;
set => SetAndNotify(ref _selectedCol, value);
}
#endregion
#region
public FusionAlignVerifyViewModel() { }
//public FusionAlignVerifyViewModel(List<HardwareDevice> device,
// HardwareManager hardware,
// FusionCalibMotionService motion)
//{
// _approachAlignmentService = IoC.Get<ApproachAlignmentService>();
// _cameraAxisViewModelSevice = IoC.Get<CameraAxisViewModel>();
// _cameraAxisViewModelSevice.CameraAxisDevices.HardwareDeviceList = device;
// _hardware = hardware;
// _motionService = motion;
// _alignProcessor= new FusionAlignProcessor(motion, hardware, ModuleItem, GetRoiRect);
// _alignProcessor.ProgressChanged += (s, e) =>
// {
// Application.Current.Dispatcher.Invoke(() =>
// {
// ProgressMessage = e.Message;
// });
// };
//}
public FusionAlignVerifyViewModel(HardwareManager hardware, FusionCalibMotionService motion)
{
_hardware = hardware;
_motionService = motion;
_approachAlignmentService = IoC.Get<ApproachAlignmentService>();
}
public static FusionAlignVerifyViewModel Create(
List<HardwareDevice> device,
HardwareManager hardware,
FusionCalibMotionService motion)
{
var vm = new FusionAlignVerifyViewModel(hardware, motion);
vm.CameraAxisViewModelSevice = IoC.Get<CameraAxisViewModel>();
vm.CameraAxisViewModelSevice.CameraAxisDevices.HardwareDeviceList = device;
vm._alignProcessor = new FusionAlignProcessor(motion, hardware, vm.ModuleItem, vm.GetRoiRect);
vm._alignProcessor.ProgressChanged += (s, e) =>
{
Application.Current.Dispatcher.Invoke(() =>
{
vm.ProgressMessage = e.Message;
});
};
return vm;
}
#endregion
#region
/// <summary>
/// 步骤1抓Pad点
/// 框选ROI区域识别Pad目标点记录pad坐标(X1,Y2)
/// </summary>
public void btnCapturePad()
{
if (MwMessageBox.Show("是否在当前位置框选ROI抓Pad点?", "确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
return;
_cts = new CancellationTokenSource();
Task.Run(async () =>
{
try
{
IsRunning = true;
await _alignProcessor.CapturePadPointAsync(_cts.Token);
Application.Current.Dispatcher.Invoke(() =>
{
PadCapturedX = _moduleItem.PadRulerX;
PadCapturedY = _moduleItem.PadRulerY;
});
MwMessageBox.Show($"抓Pad点完成\nPad: ({PadCapturedX:F4}, {PadCapturedY:F4})");
}
catch (OperationCanceledException) { MwMessageBox.Show("已取消"); }
catch (Exception ex) { MwMessageBox.Show($"抓Pad点失败{ex.Message}"); }
finally { IsRunning = false; }
});
}
/// <summary>
/// 步骤2a抓Die首点
/// 框选ROI区域识别Die首点坐标(X2,Y1)
/// </summary>
public void btnCaptureDieFirst()
{
if (MwMessageBox.Show("是否在当前位置框选ROI抓Die首点?", "确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
return;
_cts = new CancellationTokenSource();
Task.Run(async () =>
{
try
{
IsRunning = true;
await _alignProcessor.CaptureDieFirstPointAsync(_cts.Token);
Application.Current.Dispatcher.Invoke(() =>
{
DieFirstX = _moduleItem.DieRulerX;
DieFirstY = _moduleItem.DieRulerY;
});
MwMessageBox.Show($"抓Die首点完成\nDie: ({DieFirstX:F4}, {DieFirstY:F4})");
}
catch (OperationCanceledException) { MwMessageBox.Show("已取消"); }
catch (Exception ex) { MwMessageBox.Show($"抓Die首点失败{ex.Message}"); }
finally { IsRunning = false; }
});
}
/// <summary>
/// 步骤2b执行Die网格飞拍
/// 以Die首点为起点按step和count执行蛇形网格飞拍
/// </summary>
public void btnStartFlyScan()
{
if (FlyScanXCount <= 0 || FlyScanYCount <= 0)
{
MwMessageBox.Show("请设置有效的X Count和Y Count需大于0");
return;
}
if (FlyScanStep <= 0)
{
MwMessageBox.Show("请设置有效的Step需大于0");
return;
}
if (MwMessageBox.Show($"是否以首点({DieFirstX:F4}, {DieFirstY:F4})为起点开始飞拍?\n" +
$"网格:{FlyScanXCount}×{FlyScanYCount},步长:{FlyScanStep}mm",
"确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
return;
// 将飞拍参数同步到processor
_alignProcessor.SetFlyScanParams(DieFirstX, DieFirstY, FlyScanXCount, FlyScanYCount, FlyScanStep);
_cts = new CancellationTokenSource();
Task.Run(async () =>
{
try
{
IsRunning = true;
await _alignProcessor.ExecuteDieGridFlyScanAsync(_cts.Token);
Application.Current.Dispatcher.Invoke(() =>
{
FlyScanResultText = $"飞拍完成,共获取 {_moduleItem.DieGridPoints.Count} 个Die点";
DisplayDieGridPoints.Clear();
for (int i = 0; i < _moduleItem.DieGridPoints.Count; i++)
{
var pt = _moduleItem.DieGridPoints[i];
DisplayDieGridPoints.Add(new DieGridPointDisplay
{
Row = pt.Item1,
Col = pt.Item2,
X = pt.Item3.X,
Y = pt.Item3.Y
});
}
});
MwMessageBox.Show($"飞拍完成,共获取 {_moduleItem.DieGridPoints.Count} 个Die点");
}
catch (OperationCanceledException) { MwMessageBox.Show("已取消"); }
catch (Exception ex) { MwMessageBox.Show($"飞拍失败:{ex.Message}"); }
finally { IsRunning = false; }
});
}
/// <summary>
/// 步骤3执行对位
/// 用户选择网格中的一个Die点与Pad点执行对位
/// </summary>
public void btnExecuteAlign()
{
if (_moduleItem.DieGridPoints == null || _moduleItem.DieGridPoints.Count == 0)
{
MwMessageBox.Show("请先执行Die网格飞拍");
return;
}
if (SelectedRow < 0 || SelectedCol < 0)
{
MwMessageBox.Show("请输入有效的行列号从0开始");
return;
}
bool found = _moduleItem.DieGridPoints.Any(p => p.Item1 == SelectedRow && p.Item2 == SelectedCol);
if (!found)
{
MwMessageBox.Show($"未找到第{SelectedRow}行第{SelectedCol}列的Die点请检查输入");
return;
}
if (MwMessageBox.Show($"是否将Die[{SelectedRow},{SelectedCol}]与Pad({PadCapturedX:F4}, {PadCapturedY:F4})对位?",
"确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
return;
_cts = new CancellationTokenSource();
Task.Run(async () =>
{
try
{
IsRunning = true;
await _alignProcessor.ExecuteAlignAsync(_cts.Token, SelectedRow, SelectedCol);
Application.Current.Dispatcher.Invoke(() =>
{
AlignResultText = $"选择Die点: [{SelectedRow},{SelectedCol}]\n" +
$"Die坐标(X2,Y1): ({_moduleItem.DieRealX:F4}, {_moduleItem.DieRealY:F4})\n" +
$"Pad坐标(X1,Y2): ({_moduleItem.PadRealX:F4}, {_moduleItem.PadRealY:F4})\n" +
$"对齐后 X1: {_moduleItem.AlignResultX:F4}\n" +
$"对齐后 Y1: {_moduleItem.AlignResultY:F4}\n" +
$"X2补偿: {_moduleItem.AlignResultX2:F4}";
});
MwMessageBox.Show("对位完成!");
}
catch (OperationCanceledException) { MwMessageBox.Show("已取消"); }
catch (Exception ex) { MwMessageBox.Show($"对位失败:{ex.Message}"); }
finally { IsRunning = false; }
});
}
private Rectangle1 GetRoiRect()
{
try
{
var region = CameraAxisViewModelSevice?.Regions;
if (region?.Count > 0 && region[0].Region is RectRegion rect)
{
return new Rectangle1
{
Start_X = rect.CenterPoint.Y - rect.Height / 2,
Start_Y = rect.CenterPoint.X - rect.Width / 2,
End_X = rect.CenterPoint.Y + rect.Height / 2,
End_Y = rect.CenterPoint.X + rect.Width / 2
};
}
}
catch { }
return null;
}
/// <summary>
/// 停止
/// </summary>
public void btnStopAlign()
{
_cts?.Cancel();
}
#endregion
}
/// <summary>
/// Die网格点显示模型用于DataGrid绑定
/// </summary>
public class DieGridPointDisplay
{
public int Row { get; set; }
public int Col { get; set; }
public double X { get; set; }
public double Y { get; set; }
}
}

View File

@@ -0,0 +1,155 @@
using MainShell.AlgorithmCalib.Service;
using MainShell.Hardware;
using MaxwellFramework.Core.Interfaces;
using MwFramework.Controls.Components;
using MwFramework.ManagerService;
using Stylet;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
namespace MainShell.AlgorithmCalib.ViewModel
{
/// <summary>
/// 融合标定页面主VM对标 MotionCalibContentsViewModel
/// 管理 Die融合 和 Pad融合 两个子页面
/// </summary>
public class FusionCalibContentsViewModel : Screen, IPage
{
private readonly HardwareManager _hardware;
private readonly FusionCalibMotionService _fusionCalibMotionService;
private bool _isInit = false;
public string Name { get; set; } = "FusionCalib";
public ICommand PrevCommand { get; set; }
public ICommand NextCommand { get; set; }
private ObservableCollection<Screen> _screens;
public ObservableCollection<Screen> Screens
{
get => _screens;
set => SetAndNotify(ref _screens, value);
}
private Screen _showScreenVM;
public Screen ShowScreenVM
{
get => _showScreenVM;
set => SetAndNotify(ref _showScreenVM, value);
}
private string _currentCalibName;
public string CurrentCalibName
{
get => _currentCalibName;
set => SetAndNotify(ref _currentCalibName, value);
}
private string _progressText;
public string ProgressText
{
get => _progressText;
set => SetAndNotify(ref _progressText, value);
}
private int _showIndex;
public int ShowIndex
{
get => _showIndex;
set => SetAndNotify(ref _showIndex, value);
}
private bool _isEnablePrev;
public bool IsEnablePrev
{
get => _isEnablePrev;
set => SetAndNotify(ref _isEnablePrev, value);
}
private bool _isEnableNext = true;
public bool IsEnableNext
{
get => _isEnableNext;
set => SetAndNotify(ref _isEnableNext, value);
}
public FusionCalibContentsViewModel()
{
_hardware = IoC.Get<HardwareManager>();
_fusionCalibMotionService = IoC.Get<FusionCalibMotionService>();
PrevCommand = new DelegateCommand(() => OnPrev());
NextCommand = new DelegateCommand(() => OnNext());
}
protected override void OnViewLoaded()
{
if (_isInit) return;
Screens = new ObservableCollection<Screen>();
// Pad融合多区域打开子窗口
Screens.Add(FusionMultipleCalibViewModel.Create(
"Pad融合标定", "topCameraFusion",
_hardware.CameraAxisManager.TopCameraAxisDevices,
_hardware, _fusionCalibMotionService));
// Die融合单页面
Screens.Add(FusionCalibViewModel.Create(
"Die融合标定", "topWsCameraFusion",
_hardware.CameraAxisManager.TopCameraWsAxisDevices,
_hardware, _fusionCalibMotionService, isWaferCalib: true));
// 融合标定验证
Screens.Add(FusionAlignVerifyViewModel.Create(
_hardware.CameraAxisManager.TopCameraWsAxisDevices,
_hardware, _fusionCalibMotionService));
ShowIndex = 0;
ShowScreenVM = Screens[0];
UpdateNavigationState();
_isInit = true;
}
public void viewUnLoad()
{
if (Screens != null)
{
foreach (var screen in Screens)
{
if (screen is FusionMultipleCalibViewModel menuVm)
menuVm.CleanupCalibWindows();
}
}
}
private void OnPrev()
{
if (ShowIndex <= 0) return;
ShowIndex--;
ShowScreenVM = Screens[ShowIndex];
UpdateNavigationState();
}
private void OnNext()
{
if (ShowIndex >= Screens.Count - 1) return;
ShowIndex++;
ShowScreenVM = Screens[ShowIndex];
UpdateNavigationState();
}
private void UpdateNavigationState()
{
IsEnablePrev = ShowIndex > 0;
IsEnableNext = ShowIndex < Screens.Count - 1;
if (ShowScreenVM is FusionMultipleCalibViewModel multiVm)
CurrentCalibName = multiVm.CalibName;
if (ShowScreenVM is FusionCalibViewModel calibVm)
CurrentCalibName = calibVm.CalibName;
ProgressText = $"{ShowIndex + 1} / {Screens.Count}";
}
}
}

View File

@@ -0,0 +1,728 @@
using MainShell.AlgorithmCalib.Common;
using MainShell.AlgorithmCalib.Model;
using MainShell.AlgorithmCalib.Service;
using MainShell.Common;
using MainShell.Common.Display.ViewModel;
using MainShell.Hardware;
using MainShell.Motion;
using MainShell.PageCalib.OriginCalib.Service;
using MaxwellFramework.Core.Interfaces;
using MwFramework.Controls.ControlCanvas.Model;
using MwFramework.Device;
using MwFramework.ManagerService;
using SemiconductorVisionAlgorithm.SemiParams;
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using CameraAxisViewModel = MainShell.Common.Display.ViewModel.CameraAxisViewModel;
using SemiPoint = SemiconductorVisionAlgorithm.SemiParams.Point;
namespace MainShell.AlgorithmCalib.ViewModel
{
/// <summary>
/// 融合标定子窗口VMDie/Pad共用
/// 对标 MotionCalibViewModel
/// </summary>
public class FusionCalibViewModel : Screen, IPage
{
private readonly FusionCalibMotionService _fusionCalibMotionService;
private readonly HardwareManager _hardware;
private CancellationTokenSource _cts;
public string Name { get; set; } = "FusionCalib";
public string CalibName { get; set; }
public string CameraName { get; set; }
public string FileSaveDir { get; set; }
// 是否Wafer标定true=Die用WS轴, false=Pad用PHS轴
public bool IsWaferCalib { get; private set; }
#region
private FusionCalibModuleItem _moduleItem = new FusionCalibModuleItem();
public FusionCalibModuleItem ModuleItem
{
get => _moduleItem;
set => SetAndNotify(ref _moduleItem, value);
}
// PadFusionCalibView 绑定这个
public FusionCalibModuleItem FusionCalibParItem
{
get => _moduleItem;
set { _moduleItem = value; NotifyOfPropertyChange(nameof(FusionCalibParItem)); }
}
// DieFusionCalibView 绑定这个
public FusionCalibModuleItem WsFusionCalibParItem
{
get => _moduleItem;
set { _moduleItem = value; NotifyOfPropertyChange(nameof(WsFusionCalibParItem)); }
}
private CameraAxisViewModel _cameraAxisViewModelSevice;
public CameraAxisViewModel CameraAxisViewModelSevice
{
get => _cameraAxisViewModelSevice;
set => SetAndNotify(ref _cameraAxisViewModelSevice, value);
}
private DelegateBase _motion = new DelegateBase();
public DelegateBase Motion
{
get => _motion;
set => SetAndNotify(ref _motion, value);
}
private FusionCalibPostProcessor _postProcessor;
public FusionCalibPostProcessor PostProcessor
{
get => _postProcessor;
set => SetAndNotify(ref _postProcessor, value);
}
private ApproachAlignmentService _approachAlignmentService;
public ApproachAlignmentService ApproachAlignmentService
{
get => _approachAlignmentService;
set => SetAndNotify(ref _approachAlignmentService, value);
}
private bool _isCalibrating;
public bool IsCalibrating
{
get => _isCalibrating;
set { SetAndNotify(ref _isCalibrating, value); NotifyOfPropertyChange(nameof(CanStartCalib)); }
}
public bool CanStartCalib => !IsCalibrating;
#endregion
#region
private string _progressMessage = "";
public string ProgressMessage
{
get => _progressMessage;
set => SetAndNotify(ref _progressMessage, value);
}
private int _progressCurrent;
public int ProgressCurrent
{
get => _progressCurrent;
set => SetAndNotify(ref _progressCurrent, value);
}
private int _progressTotal;
public int ProgressTotal
{
get => _progressTotal;
set
{
SetAndNotify(ref _progressTotal, value);
NotifyOfPropertyChange(nameof(ProgressPercentage));
NotifyOfPropertyChange(nameof(ProgressText));
}
}
public double ProgressPercentage => ProgressTotal > 0 ? (double)ProgressCurrent / ProgressTotal * 100 : 0;
public string ProgressText => ProgressTotal > 0 ? $"{ProgressCurrent}/{ProgressTotal}" : "";
private bool _isProgressVisible;
public bool IsProgressVisible
{
get => _isProgressVisible;
set => SetAndNotify(ref _isProgressVisible, value);
}
#endregion
#region &
public FusionCalibViewModel() { }
public FusionCalibViewModel(HardwareManager hardware, FusionCalibMotionService motion)
{
_hardware = hardware;
_fusionCalibMotionService = motion;
_approachAlignmentService = IoC.Get<ApproachAlignmentService>();
}
/// <summary>
/// Die融合用单页面模式
/// </summary>
public static FusionCalibViewModel Create(string calibName, string saveFileName,
List<HardwareDevice> device, HardwareManager hardware,
FusionCalibMotionService motion, bool isWaferCalib)
{
var vm = new FusionCalibViewModel(hardware, motion);
vm.CalibName = calibName;
vm.FileSaveDir = saveFileName;
vm.IsWaferCalib = isWaferCalib;
vm.CameraAxisViewModelSevice = IoC.Get<CameraAxisViewModel>();
vm.CameraAxisViewModelSevice.CameraAxisDevices.HardwareDeviceList = device;
vm.ModuleItem = new FusionCalibModuleItem
{
ModuleName = isWaferCalib ? FusionCalibModuleNames.DieFusion : FusionCalibModuleNames.PadFusion,
Camera_ID = hardware.TopWsCameraExtend.Id ,
IsWaferCalib = isWaferCalib,
CalibStep = 0.4,
CalibCount = 10,
Count = 4,
Step = 5.0,
};
vm.PostProcessor = new FusionCalibPostProcessor(motion, hardware, vm.ModuleItem, vm.GetRoiRect);
vm.SubscribeToProgress();
return vm;
}
/// <summary>
/// Pad融合用子窗口模式
/// </summary>
public static FusionCalibViewModel Create(string calibName,
List<HardwareDevice> device, FusionCalibModuleItem param,
HardwareManager hardware, FusionCalibMotionService motion, bool isWaferCalib)
{
var vm = new FusionCalibViewModel(hardware, motion);
vm.CalibName = calibName;
vm.CameraName = hardware.TopCameraExtend.Id;
vm.IsWaferCalib = isWaferCalib;
vm.ModuleItem = param;
vm.CameraAxisViewModelSevice = IoC.Get<CameraAxisViewModel>();
vm.CameraAxisViewModelSevice.CameraAxisDevices.HardwareDeviceList = device;
vm.PostProcessor = new FusionCalibPostProcessor(motion, hardware, param, vm.GetRoiRect);
vm.SubscribeToProgress();
return vm;
}
#endregion
#region
private void SubscribeToProgress()
{
if (PostProcessor != null) PostProcessor.ProgressChanged += OnProgressChanged;
}
private void UnsubscribeFromProgress()
{
if (PostProcessor != null) PostProcessor.ProgressChanged -= OnProgressChanged;
}
private void OnProgressChanged(object sender, CalibrationProgressEventArgs e)
{
Application.Current.Dispatcher.Invoke(() =>
{
ProgressMessage = e.Message;
ProgressCurrent = e.Current;
ProgressTotal = e.Total;
NotifyOfPropertyChange(nameof(ProgressPercentage));
NotifyOfPropertyChange(nameof(ProgressText));
});
}
#endregion
#region Die/Pad共用逻辑XAML通过不同View绑定
public void btnMoveWSCalibPosPosition() => MoveToCalibPos();
public void btnMovePhsCalibPosPosition() => MoveToCalibPos();
private void MoveToCalibPos()
{
Task.Run(() =>
{
try
{
if (IsWaferCalib)
{
// Die: 移动X1到标定位置然后移动X2,Y1到逼近位置
_fusionCalibMotionService.SafeMove(_hardware.Axis_X1, ModuleItem.MoveAxisPos);
_fusionCalibMotionService.MoveWsAvoidance(ModuleItem.ApproachXPos, ModuleItem.ApproachYPos);
}
else
{
// Pad: 移动Y1到标定位置然后移动X1,Y2到逼近位置
_fusionCalibMotionService.SafeMove(_hardware.Axis_Y1, ModuleItem.MoveAxisPos);
_fusionCalibMotionService.MovePhsAvoidance(ModuleItem.ApproachXPos, ModuleItem.ApproachYPos);
}
}
catch (Exception ex) { MwMessageBox.Show($"移动失败:{ex.Message}"); }
});
}
public void btnApproachWSCalibPosition() => DoApproach();
public void btnApproachPhsCalibPosition() => DoApproach();
private void DoApproach()
{
Task.Run(async () =>
{
try
{
bool success = await FindPointCircleAsync(CancellationToken.None);
if (success)
{
if (IsWaferCalib)
{
// Die: 读取当前X2,Y1位置作为逼近值
ModuleItem.ApproachXPos = _hardware.Axis_X2.State.ActualPos;
ModuleItem.ApproachYPos = _hardware.Axis_Y1.State.ActualPos;
}
else
{
// Pad: 读取当前X1,Y2位置作为逼近值
ModuleItem.ApproachXPos = _hardware.Axis_X1.State.ActualPos;
ModuleItem.ApproachYPos = _hardware.Axis_Y2.State.ActualPos;
}
MwMessageBox.Show($"对齐值X:{ModuleItem.ApproachXPos},Y:{ModuleItem.ApproachYPos}");
}
else
{
MwMessageBox.Show("对齐失败!");
}
}
catch (Exception ex) { MwMessageBox.Show($"异常:{ex.Message}"); }
});
}
public void btnCalculateCameraPosition()
{
try
{
int offset = -10;
double minPos = 0;
if (IsWaferCalib)
{
// Die: 计算X1相机轴起始位置
_hardware.Axis_X2.GetSoftMel(ref minPos);
var delx = ModuleItem.ApproachXPos - minPos + offset;
ModuleItem.CameraAxisPos = ModuleItem.MoveAxisPos - delx;
}
else
{
// Pad: 计算Y1相机轴起始位置
_hardware.Axis_Y2.GetSoftMel(ref minPos);
var delx = ModuleItem.ApproachYPos - minPos + offset;
ModuleItem.CameraAxisPos = ModuleItem.MoveAxisPos - delx;
}
}
catch (Exception ex) { MwMessageBox.Show($"计算失败:{ex.Message}"); }
}
public void btnSetCameraPosition()
{
if (MwMessageBox.Show("是否使用当前位置?", "确认", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
// Die: 读取X1当前位置 Pad: 读取Y1当前位置
ModuleItem.CameraAxisPos = IsWaferCalib
? _hardware.Axis_X1.State.ActualPos
: _hardware.Axis_Y1.State.ActualPos;
}
}
public void btnMoveCameraPosition()
{
if (MwMessageBox.Show("是否移动到该点?", "确认", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
Task.Run(() =>
{
try
{
// Die: 移动X1 Pad: 移动Y1
if (IsWaferCalib)
_fusionCalibMotionService.SafeMove(_hardware.Axis_X1, ModuleItem.CameraAxisPos);
else
_fusionCalibMotionService.SafeMove(_hardware.Axis_Y1, ModuleItem.CameraAxisPos);
}
catch (Exception ex) { MwMessageBox.Show($"移动失败:{ex.Message}"); }
});
}
}
public void btnCalculateWSPosition() => CalculateStartPositions();
public void btnCalculatePhsPosition() => CalculateStartPositions();
private void CalculateStartPositions()
{
try
{
int offset = -10;
double minPos = 0;
if (IsWaferCalib)
{
// Die: 计算WS起始位置
_hardware.Axis_X2.GetSoftMel(ref minPos);
var delx = ModuleItem.ApproachXPos - minPos + offset;
ModuleItem.CameraAxisPos = ModuleItem.MoveAxisPos - delx;
double x11Offset = ModuleItem.CameraAxisPos - ModuleItem.MoveAxisPos;
ModuleItem.StartX = ModuleItem.ApproachXPos + x11Offset;
ModuleItem.StartY = ModuleItem.ApproachYPos;
}
else
{
// Pad: 计算PHS起始位置
_hardware.Axis_Y2.GetSoftMel(ref minPos);
var delx = ModuleItem.ApproachYPos - minPos + offset;
ModuleItem.CameraAxisPos = ModuleItem.MoveAxisPos - delx;
double y11Offset = ModuleItem.CameraAxisPos - ModuleItem.MoveAxisPos;
ModuleItem.StartX = ModuleItem.ApproachXPos;
ModuleItem.StartY = ModuleItem.ApproachYPos + y11Offset;
}
}
catch (Exception ex) { MwMessageBox.Show($"计算失败:{ex.Message}"); }
}
public void btnSetWaferStartPosition() => SetCurrentPos();
public void btnSetStageStartPosition() => SetCurrentPos();
private void SetCurrentPos()
{
if (MwMessageBox.Show("是否使用当前位置?", "确认", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
Task.Run(() =>
{
if (IsWaferCalib)
{
// Die: 读取X2,Y1当前位置
ModuleItem.StartX = _hardware.Axis_X2.State.ActualPos;
ModuleItem.StartY = _hardware.Axis_Y1.State.ActualPos;
}
else
{
// Pad: 读取X1,Y2当前位置
ModuleItem.StartX = _hardware.Axis_X1.State.ActualPos;
ModuleItem.StartY = _hardware.Axis_Y2.State.ActualPos;
}
});
}
}
public void btnMoveWaferStartPosition() => MoveToStart();
public void btnMoveStageStartPosition() => MoveToStart();
private void MoveToStart()
{
if (MwMessageBox.Show("是否移动到该点?", "确认", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
if (IsWaferCalib)
_fusionCalibMotionService.MoveWsAvoidance(ModuleItem.StartX, ModuleItem.StartY);
else
_fusionCalibMotionService.MovePhsAvoidance(ModuleItem.StartX, ModuleItem.StartY);
}
}
public void btnMoveToCenter()
{
Task.Run(() =>
{
try
{
if (IsWaferCalib)
{
ModuleItem.WaferStartVerifyX = _hardware.Axis_X2.State.ActualPos;
ModuleItem.WaferStartVerifyY = _hardware.Axis_Y1.State.ActualPos;
}
else
{
ModuleItem.WaferStartVerifyX = _hardware.Axis_X1.State.ActualPos;
ModuleItem.WaferStartVerifyY = _hardware.Axis_Y2.State.ActualPos;
}
MwMessageBox.Show("设置起点完成");
}
catch (Exception ex) { MwMessageBox.Show($"设置失败:{ex.Message}"); }
});
}
#endregion
#region
private bool _stopVerifyMotion = false;
public void btnMoveToStartPoint()
{
if (MwMessageBox.Show("是否移动到验证起点?", "确认", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
try
{
if (IsWaferCalib)
_fusionCalibMotionService.MoveWsAvoidance(ModuleItem.WaferStartVerifyX, ModuleItem.WaferStartVerifyY);
else
_fusionCalibMotionService.MovePhsAvoidance(ModuleItem.WaferStartVerifyX, ModuleItem.WaferStartVerifyY);
}
catch (Exception ex) { MwMessageBox.Show($"移动失败:{ex.Message}"); }
}
}
public void btnMoveWafer()
{
ModuleItem.RulerPoints = new List<SemiPoint>();
ModuleItem.RealPoints = new List<SemiPoint>();
Task.Run(() =>
{
try
{
_stopVerifyMotion = false;
for (int i = 0; i < ModuleItem.WaferVerityCountY; i++)
{
for (int j = 0; j < ModuleItem.WaferVerityCountX; j++)
{
if (_stopVerifyMotion)
{
_stopVerifyMotion = false;
return;
}
double yPos = ModuleItem.WaferStartVerifyY + i * ModuleItem.WaferVerityStep;
double xPos;
if (i % 2 == 0)
xPos = ModuleItem.WaferStartVerifyX + j * ModuleItem.WaferVerityStep;
else
xPos = ModuleItem.WaferStartVerifyX + (ModuleItem.WaferVerityCountX - j - 1) *
ModuleItem.WaferVerityStep;
if (IsWaferCalib)
_fusionCalibMotionService.MoveWsAvoidance(xPos, yPos);
else
_fusionCalibMotionService.MovePhsAvoidance(xPos, yPos);
// TODO: 调用逼近识别 ApproachPointCircle
if (IsWaferCalib)
{
SemiPoint ruler = new SemiPoint(_hardware.Axis_X2.State.ActualPos,
_hardware.Axis_Y1.State.ActualPos);
ModuleItem.RulerPoints.Add(ruler);
}
else
{
SemiPoint ruler = new SemiPoint(_hardware.Axis_X1.State.ActualPos,
_hardware.Axis_Y2.State.ActualPos);
ModuleItem.RulerPoints.Add(ruler);
}
}
}
MwMessageBox.Show("飞拍结束");
}
catch (Exception ex) { MwMessageBox.Show($"飞拍失败:{ex.Message}"); }
});
}
public void btnVerityWafer()
{
if (ModuleItem.RulerPoints == null || ModuleItem.RulerPoints.Count == 0)
{
MwMessageBox.Show("请先执行飞拍!");
return;
}
if (MwMessageBox.Show("是否已移动到对应位置,确认开始验证?", "确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
return;
Task.Run(() =>
{
try
{
_stopVerifyMotion = false;
List<SemiPoint> rulerThenList = new List<SemiPoint>();
List<SemiPoint> rulerNowList = new List<SemiPoint>();
for (int i = 0; i < ModuleItem.RulerPoints.Count; i++)
{
if (_stopVerifyMotion)
{
_stopVerifyMotion = false;
return;
}
// TODO: 使用融合位置表计算期望坐标
SemiPoint rulerPoint = ModuleItem.RulerPoints[i]; // 暂时直接使用飞拍点
rulerThenList.Add(rulerPoint);
if (IsWaferCalib)
_fusionCalibMotionService.MoveWsAvoidance(rulerPoint.X, rulerPoint.Y);
else
_fusionCalibMotionService.MovePhsAvoidance(rulerPoint.X, rulerPoint.Y);
// TODO: 逼近识别,获取实际坐标
if (IsWaferCalib)
{
SemiPoint rulerNow = new SemiPoint(_hardware.Axis_X2.State.ActualPos, _hardware.Axis_Y1.State.ActualPos);
rulerNowList.Add(rulerNow);
}
else
{
SemiPoint rulerNow = new SemiPoint(_hardware.Axis_X1.State.ActualPos, _hardware.Axis_Y2.State.ActualPos);
rulerNowList.Add(rulerNow);
}
}
// TODO: 输出验证结果
// 对应旧项目: JM1Manager.Instance.pos_verify(filePath, rulerThenList, rulerNowList)
double totalError = 0;
for (int i = 0; i < rulerThenList.Count; i++)
{
double dx = rulerThenList[i].X - rulerNowList[i].X;
double dy = rulerThenList[i].Y - rulerNowList[i].Y;
totalError += Math.Sqrt(dx * dx + dy * dy);
}
double avgError = rulerThenList.Count > 0 ? totalError / rulerThenList.Count : 0;
MwMessageBox.Show($"验证完成!平均误差: {avgError:F4}mm");
}
catch (Exception ex) { MwMessageBox.Show($"验证失败:{ex.Message}"); }
});
}
public void btnStopVerityWafer()
{
var result = MwMessageBox.Show("是否停止验证?", "确认停止", MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes)
{
_stopVerifyMotion = true;
}
}
#endregion
#region
public async Task StartCalib()
{
if (IsCalibrating) return;
IsCalibrating = true;
IsProgressVisible = true;
_cts = new CancellationTokenSource();
try
{
if (PostProcessor != null)
await PostProcessor.ExecuteAsync(null, _cts.Token);
MwMessageBox.Show("标定完成!");
}
catch (OperationCanceledException)
{
MwMessageBox.Show("标定已取消。");
}
catch (Exception ex)
{
MwMessageBox.Show($"标定失败:{ex.Message}");
}
finally
{
IsCalibrating = false;
IsProgressVisible = false;
}
}
public void btnStart() => _ = StartCalib();
public void btnStop() => _cts?.Cancel();
#endregion
#region ROI
private Rectangle1 GetRoiRect()
{
try
{
var region = CameraAxisViewModelSevice?.Regions;
if (region?.Count > 0 && region[0].Region is RectRegion rect)
{
return new Rectangle1
{
Start_X = rect.CenterPoint.Y - rect.Height / 2,
Start_Y = rect.CenterPoint.X - rect.Width / 2,
End_X = rect.CenterPoint.Y + rect.Height / 2,
End_Y = rect.CenterPoint.X + rect.Width / 2
};
}
}
catch { }
return null;
}
#endregion
private async Task<bool> FindPointCircleAsync(CancellationToken token)
{
var roiRect = GetRoiRect();
if (IsWaferCalib)
{
var request = new ApproachAlignmentRequest(
axes: new[]
{
new ApproachAlignmentAxis(_hardware.Axis_X2.Name, 0.005),
new ApproachAlignmentAxis(_hardware.Axis_Y1.Name, 0.005)
},
camera: CameraType.TopPositionCamera)
{
MaxIterations = 3,
RecognitionTimeoutMilliseconds = 5000,
RecognitionParameters = new CenterRecognitionParameters()
{
Type = CenterRecognitionType.EdgeCircle,
rectangle = roiRect
}
};
var result = await _approachAlignmentService
.ApproachAlignmentAsync(request, token);
return result.Succeeded;
}
else
{
var request = new ApproachAlignmentRequest(
axes: new[]
{
new ApproachAlignmentAxis(_hardware.Axis_X1.Name, 0.005),
new ApproachAlignmentAxis(_hardware.Axis_Y2.Name, 0.005)
},
camera: CameraType.TopPositionCamera)
{
MaxIterations = 3,
RecognitionTimeoutMilliseconds = 5000,
RecognitionParameters = new CenterRecognitionParameters()
{
Type = CenterRecognitionType.EdgeCircle,
rectangle = roiRect
}
};
var result = await _approachAlignmentService
.ApproachAlignmentAsync(request, token);
return result.Succeeded;
}
}
private static string GetAxisName(IAxis axis)
{
if (axis == null)
{
return string.Empty;
}
return axis.Name;
}
protected override void OnDeactivate()
{
UnsubscribeFromProgress();
base.OnDeactivate();
}
}
}

View File

@@ -0,0 +1,354 @@
using JM1.VisionModule;
using MainShell.AlgorithmCalib.Model;
using MainShell.AlgorithmCalib.Service;
using MainShell.AlgorithmCalib.View;
using MainShell.Common;
using MainShell.Common.Display.ViewModel;
using MainShell.Filewritable;
using MainShell.Hardware;
using MaxwellFramework.Core.Interfaces;
using MwFramework.ManagerService;
using Stylet;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace MainShell.AlgorithmCalib.ViewModel
{
/// <summary>
/// Pad融合标定 - 多区域管理VM对标 MotionMultipleCalibViewModel
/// 管理4组标定区域每组可打开子窗口标定
/// </summary>
public class FusionMultipleCalibViewModel : Screen, IPage
{
#region &
private const int CalibAreaCount = 4;
private const string PointsFileExt = ".csv";
private const string AreaFilePrefix = "Fusion_Time";
private readonly HashSet<string> _forceCloseIds = new HashSet<string>();
private readonly Dictionary<string, Window> _calibWindows = new Dictionary<string, Window>();
private bool _isDataLoaded = false;
#endregion
#region
public string Name { get; set; } = "FusionMultipleCalib";
public string CalibName { get; set; }
public string FileSaveDir { get; set; }
private CameraAxisViewModel _cameraAxisViewModelService;
public CameraAxisViewModel CameraAxisViewModelService
{
get => _cameraAxisViewModelService;
set => SetAndNotify(ref _cameraAxisViewModelService, value);
}
private ObservableCollection<FusionCalibModuleItem> _calibItems = new
ObservableCollection<FusionCalibModuleItem>();
public ObservableCollection<FusionCalibModuleItem> CalibItems
{
get => _calibItems;
set => SetAndNotify(ref _calibItems, value);
}
private FusionCalibModuleItem _selectedItem;
public FusionCalibModuleItem SelectedItem
{
get => _selectedItem;
set => SetAndNotify(ref _selectedItem, value);
}
private FusionCalibSetting _setting;
private List<HardwareDevice> _hardwareDevice;
public List<HardwareDevice> HardwareDevice
{
get => _hardwareDevice;
set => SetAndNotify(ref _hardwareDevice, value);
}
private HardwareManager _hardware;
public HardwareManager Hardware
{
get => _hardware;
set => SetAndNotify(ref _hardware, value);
}
private FusionCalibMotionService _fusionCalibMotionService;
#endregion
#region &
public FusionMultipleCalibViewModel()
{
_cameraAxisViewModelService = IoC.Get<CameraAxisViewModel>();
}
public static FusionMultipleCalibViewModel Create(string calibName, string saveFileName,
List<HardwareDevice> device, HardwareManager hardware, FusionCalibMotionService motion)
{
var vm = new FusionMultipleCalibViewModel();
vm.Initialize(calibName, saveFileName, device, hardware, motion);
return vm;
}
#endregion
#region &
private void Initialize(string calibName, string saveFileName,
List<HardwareDevice> device, HardwareManager hardware, FusionCalibMotionService motion)
{
CalibName = calibName;
Hardware = hardware;
HardwareDevice = device;
_fusionCalibMotionService = motion;
FileSaveDir = Path.Combine(Paths.CalibSettingPath, "fusionCalib");
_setting = FusionCalibSetting.LoadOrCreate();
}
protected override void OnViewLoaded()
{
base.OnViewLoaded();
if (_hardware != null)
{
_cameraAxisViewModelService.CameraAxisDevices.HardwareDeviceList = HardwareDevice;
NotifyOfPropertyChange(nameof(CameraAxisViewModelService));
}
if (!_isDataLoaded)
{
ReadCalibData();
_isDataLoaded = true;
}
}
#endregion
#region
public void btnOpenCalibWindow()
{
if (SelectedItem == null)
{
MwMessageBox.Show("请先选择一组标定数据。", "提示",
MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
string calibId = SelectedItem.Camera_ID;
if (_calibWindows.TryGetValue(calibId, out var existingWindow))
{
if (existingWindow.WindowState == WindowState.Minimized)
existingWindow.WindowState = WindowState.Normal;
existingWindow.Show();
existingWindow.Activate();
return;
}
// 创建子窗口 VMPad模式
var calibVM = FusionCalibViewModel.Create(
CalibName, HardwareDevice, SelectedItem, Hardware, _fusionCalibMotionService, isWaferCalib:
false);
calibVM.FileSaveDir = FileSaveDir;
var window = CreateCalibWindow(calibId, calibVM);
_calibWindows[calibId] = window;
window.Show();
}
private Window CreateCalibWindow(string calibId, FusionCalibViewModel calibVM)
{
var calibView = new PadFusionCalibView { DataContext = calibVM };
var window = new Window
{
Title = $"Pad融合标定 - {calibId}",
Width = 1100,
Height = 750,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Owner = Application.Current.MainWindow,
ResizeMode = ResizeMode.CanResize,
Content = calibView
};
window.Closing += (s, args) =>
{
if (_forceCloseIds.Contains(calibId))
{
_forceCloseIds.Remove(calibId);
return;
}
args.Cancel = true;
SyncResultBack(calibVM);
window.Hide();
};
return window;
}
#endregion
#region
private void SyncResultBack(FusionCalibViewModel calibVM)
{
var source = calibVM.ModuleItem;
if (source == null) return;
var target = CalibItems.FirstOrDefault(p => p.Camera_ID == source.Camera_ID);
if (target == null) return;
target.MoveAxisPos = source.MoveAxisPos;
target.ApproachXPos = source.ApproachXPos;
target.ApproachYPos = source.ApproachYPos;
target.CameraAxisPos = source.CameraAxisPos;
target.StartX = source.StartX;
target.StartY = source.StartY;
target.Step = source.Step;
target.Count = source.Count;
target.CalibStep = source.CalibStep;
target.CalibCount = source.CalibCount;
target.RulerPoints = source.RulerPoints;
target.RealPoints = source.RealPoints;
OnPropertyChanged(nameof(CalibItems));
}
#endregion
#region &
public void btnReadCalibData()
{
var result = MwMessageBox.Show("确认读取本地标定数据?", "确认读取",
MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
if (!ReadCalibData())
MwMessageBox.Show("读取本地标定数据失败!", "提示", MessageBoxButton.OK,
MessageBoxImage.Error);
}
}
public bool ReadCalibData()
{
try
{
var items = new ObservableCollection<FusionCalibModuleItem>();
for (int i = 0; i < CalibAreaCount; i++)
{
var module = i < _setting.PadModules.Count
? _setting.PadModules[i]
: new FusionCalibModuleItem
{
Index = i + 1,
Camera_ID = $"{AreaFilePrefix}{i + 1}",
IsWaferCalib = false,
};
var pointsPath = Path.Combine(FileSaveDir,$"{AreaFilePrefix}{module.Index}{PointsFileExt}");
if (File.Exists(pointsPath))
{
MotionCalibFileService.ReadCalibPointsFile(pointsPath, out var real, out var ruler);
module.RealPoints = real;
module.RulerPoints = ruler;
}
items.Add(module);
}
CalibItems = items;
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[FusionMultiple] ReadCalibData 失败: {ex}");
return false;
}
}
public void btnSaveCalibData()
{
var result = MwMessageBox.Show("确认保存当前全部标定数据?", "确认保存",
MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
if (SaveCalibData())
MwMessageBox.Show("保存成功!", "提示", MessageBoxButton.OK,
MessageBoxImage.Information);
else
MwMessageBox.Show("保存失败!", "提示", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private bool SaveCalibData()
{
try
{
Directory.CreateDirectory(FileSaveDir);
_setting.PadModules = new List<FusionCalibModuleItem>(CalibItems);
_setting.Write();
foreach (var par in CalibItems)
{
if (par.RealPoints?.Count > 0 && par.RulerPoints?.Count > 0)
{
var pointsPath = Path.Combine(FileSaveDir,$"{AreaFilePrefix}{par.Index}{PointsFileExt}");
MotionCalibFileService.SaveCalibPointsFile(pointsPath, par.RealPoints,par.RulerPoints);
}
}
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[FusionMultiple] SaveCalibData 失败: {ex}");
return false;
}
}
#endregion
#region
public void btnApplyCalibData()
{
if (CalibItems.Count != CalibAreaCount)
{
MwMessageBox.Show("标定数据不足!", "提示", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
var result = MwMessageBox.Show("确认应用标定数据?", "确认应用",
MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
// TODO: 调用融合应用算法
MwMessageBox.Show("应用成功!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
#endregion
#region
public void CleanupCalibWindows()
{
foreach (var kvp in _calibWindows) _forceCloseIds.Add(kvp.Key);
foreach (var kvp in _calibWindows)
{
try { kvp.Value.Close(); }
catch { }
}
_calibWindows.Clear();
_forceCloseIds.Clear();
}
#endregion
}
}