添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.AlgorithmCalib.Service;
|
||||
using MainShell.Common;
|
||||
using MainShell.Common.Display.ViewModel;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Motion;
|
||||
using Maxwell.SemiFramework.DefaultConfig.Vision;
|
||||
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.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Point = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class CameraFusionCalibVerifyViewModel : Screen, IPage
|
||||
{
|
||||
public string Name { get; set; } = "CameraFusionCalibVerify";
|
||||
|
||||
public string CameraName { get; set; }
|
||||
|
||||
private readonly FusionCalibMotionService _fusionCalibMotionService;
|
||||
|
||||
private HardwareManager _hardware;
|
||||
|
||||
private CameraAxisViewModel _cameraAxisViewModelSevice = new CameraAxisViewModel();
|
||||
public CameraAxisViewModel CameraAxisViewModelSevice
|
||||
{
|
||||
get { return _cameraAxisViewModelSevice; }
|
||||
set
|
||||
{
|
||||
_cameraAxisViewModelSevice = value;
|
||||
OnPropertyChanged(nameof(CameraAxisViewModelSevice));
|
||||
}
|
||||
}
|
||||
|
||||
private FusionCalibVerifyParItem _wsfusionCalibVerifyParItem = new FusionCalibVerifyParItem();
|
||||
public FusionCalibVerifyParItem WsfusionCalibVerifyParItem
|
||||
{
|
||||
get { return _wsfusionCalibVerifyParItem; }
|
||||
set
|
||||
{
|
||||
_wsfusionCalibVerifyParItem = value;
|
||||
OnPropertyChanged(nameof(WsfusionCalibVerifyParItem));
|
||||
}
|
||||
}
|
||||
|
||||
private bool _stopMotion = false;
|
||||
|
||||
public CameraFusionCalibVerifyViewModel(HardwareManager hardware, FusionCalibMotionService fusionCalibMotionService)
|
||||
{
|
||||
_hardware = hardware;
|
||||
_fusionCalibMotionService = fusionCalibMotionService ?? throw new ArgumentNullException(nameof(fusionCalibMotionService));
|
||||
}
|
||||
|
||||
public static CameraFusionCalibVerifyViewModel Create(string name, string cameraName, List<HardwareDevice> device, HardwareManager hardware, FusionCalibMotionService motion)
|
||||
{
|
||||
var vm = new CameraFusionCalibVerifyViewModel(hardware, motion);
|
||||
vm.Initialize(name, device);
|
||||
return vm;
|
||||
}
|
||||
|
||||
private void Initialize(string cameraName, List<HardwareDevice> device)
|
||||
{
|
||||
CameraName = cameraName;
|
||||
Name = cameraName;
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
}
|
||||
|
||||
|
||||
public void btnMoveWSCalibPosPosition()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_fusionCalibMotionService.SafeMove(_hardware.Axis_X1, WsfusionCalibVerifyParItem.MoveAxisPos);
|
||||
_fusionCalibMotionService.MoveWsAvoidance(WsfusionCalibVerifyParItem.ApproachXPos, WsfusionCalibVerifyParItem.ApproachYPos);
|
||||
|
||||
//_safeAxisMotion.SafeAbsoluteMove(_gs.Axis_X11, CameraWaferFusionCalibrationItem.WSPlatCalibXPos, block: false);
|
||||
//_safeAxisMotion.SafeMoveWS(CameraWaferFusionCalibrationItem.WSApproachXPos, CameraWaferFusionCalibrationItem.WSApproachYPos, isBlock: false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnMoveToCenter()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ApproachPointWS(1))
|
||||
{
|
||||
WsfusionCalibVerifyParItem.StartX = _hardware.Axis_X2.State.ActualPos;
|
||||
WsfusionCalibVerifyParItem.StartY = _hardware.Axis_Y1.State.ActualPos;
|
||||
//CameraWaferFusionCalibrationItem.WaferStartVerifyX = _gs.Axis_X21.State.ActualPos;
|
||||
//CameraWaferFusionCalibrationItem.WaferStartVerifyY = _gs.Axis_Y21.State.ActualPos;
|
||||
MwMessageBox.Show("中心对齐完成");
|
||||
}
|
||||
else
|
||||
{
|
||||
MwMessageBox.Show("逼近失败!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnMoveToStartPoint()
|
||||
{
|
||||
//_safeAxisMotion.SafeMoveXY(_gs.Axis_X21, _gs.Axis_Y21, CameraWaferFusionCalibrationItem.WaferStartVerifyX, CameraWaferFusionCalibrationItem.WaferStartVerifyY);
|
||||
_fusionCalibMotionService.MoveWsAvoidance(WsfusionCalibVerifyParItem.StartX, WsfusionCalibVerifyParItem.StartY);
|
||||
}
|
||||
|
||||
public void btnMoveWafer()
|
||||
{
|
||||
//WsfusionCalibVerifyParItem.VerifyRealPts = new List<Point>();
|
||||
//List<Point> points = new List<Point>();
|
||||
//System.Threading.Tasks.Task.Run(() =>
|
||||
//{
|
||||
// for (var i = 0; i < WsfusionCalibVerifyParItem.CountY; i++)
|
||||
// {
|
||||
// for (var j = 0; j < WsfusionCalibVerifyParItem.CountX; j++)
|
||||
// {
|
||||
// if (_stopMotion)
|
||||
// {
|
||||
// _stopMotion = false;
|
||||
// return;
|
||||
// }
|
||||
// double yPos = WsfusionCalibVerifyParItem.StartY + i * WsfusionCalibVerifyParItem.Step;
|
||||
// double xPos;
|
||||
// if (i % 2 == 0)
|
||||
// {
|
||||
// xPos = WsfusionCalibVerifyParItem.StartX + j * WsfusionCalibVerifyParItem.Step;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// xPos = WsfusionCalibVerifyParItem.StartX + (WsfusionCalibVerifyParItem.CountX - j - 1) * WsfusionCalibVerifyParItem.Step;
|
||||
// }
|
||||
// points.Add(new Point(xPos, yPos));
|
||||
// _fusionCalibMotionService.MoveWsAvoidance(xPos, yPos);
|
||||
// if (ApproachPointWS())
|
||||
// {
|
||||
// //WsfusionCalibVerifyParItem.ApproachXPos = _hardware.Axis_X2.State.ActualPos;
|
||||
// //CameraWaferFusionCalibrationItem.WSVerityApproachXpos = _gs.Axis_X21.State.ActualPos;
|
||||
// //CameraWaferFusionCalibrationItem.WSVerityApproachYpos = _gs.Axis_Y21.State.ActualPos;
|
||||
// Point ruler = new Point(_hardware.Axis_X2.State.ActualPos, _hardware.Axis_Y1.State.ActualPos);
|
||||
// Point real = _visionOperation.GetRealByRuler(_hardware.Camera_ExtendWS.Id, ruler);
|
||||
// WsfusionCalibVerifyParItem.VerifyRealPts.Add(new Point(real.X, real.Y));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// MwMessageBox.Show("逼近失败!");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// MwMessageBox.Show("飞拍结束");
|
||||
//});
|
||||
}
|
||||
|
||||
public void btnVerifyWafer()
|
||||
{
|
||||
//if (WsfusionCalibVerifyParItem.VerifyRealPts != null && WsfusionCalibVerifyParItem.VerifyRealPts.Count > 0)
|
||||
//{
|
||||
// var result = MwMessageBox.Show("是否已移动到Pad位置,确认开始验证?", "确认开始", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
// if (result == MessageBoxResult.Yes)
|
||||
// {
|
||||
// System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
// {
|
||||
// List<SemiconductorVisionAlgorithm.SemiParams.Point> WSrulerThen = new List<SemiconductorVisionAlgorithm.SemiParams.Point>();
|
||||
// List<SemiconductorVisionAlgorithm.SemiParams.Point> WSrulerNow = new List<SemiconductorVisionAlgorithm.SemiParams.Point>();
|
||||
// Point padReal = _visionOperation.GetRealByRuler(_gs.Camera_Extend.Id, new Point(_gs.Axis_X11.State.ActualPos, _gs.Axis_Y11.State.ActualPos));
|
||||
// for (var i = 0; i < WsfusionCalibVerifyParItem.VerifyRealPts.Count; i++)
|
||||
// {
|
||||
// if (_stopMotion)
|
||||
// {
|
||||
// _stopMotion = false;
|
||||
// return;
|
||||
// }
|
||||
// SemiconductorVisionAlgorithm.SemiParams.Point rulerPoint = new SemiconductorVisionAlgorithm.SemiParams.Point();
|
||||
// JM1Vision.JM1Manager.Instance.get_ws_pos(_gs.Camera_Extend.Id, _gs.Camera_ExtendWS.Id, new SemiconductorVisionAlgorithm.SemiParams.Point(padReal.X, padReal.Y), new SemiconductorVisionAlgorithm.SemiParams.Point(CameraWaferFusionCalibrationItem.VerityrealPointRealPoints[i].X, CameraWaferFusionCalibrationItem.VerityrealPointRealPoints[i].Y), out rulerPoint);
|
||||
// WSrulerThen.Add(new SemiconductorVisionAlgorithm.SemiParams.Point(rulerPoint.X, rulerPoint.Y));
|
||||
// _fusionCalibMotionService.MoveWsAvoidance(rulerPoint.X, rulerPoint.Y);
|
||||
// //_safeAxisMotion.SafeMoveWS(rulerPoint.X, rulerPoint.Y, isCalib: true);
|
||||
// if (ApproachPointWS())
|
||||
// {
|
||||
// WSrulerNow.Add(new SemiconductorVisionAlgorithm.SemiParams.Point(_hardware.Axis_X2.State.ActualPos, _hardware.Axis_Y1.State.ActualPos));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// MwMessageBox.Show("逼近失败!");
|
||||
// }
|
||||
// }
|
||||
// string filePath = System.AppDomain.CurrentDomain.BaseDirectory + @"CalibData";
|
||||
// JM1Vision.JM1Manager.Instance.pos_verify(filePath, WSrulerThen, WSrulerNow);
|
||||
// MwMessageBox.Show("验证完成!");
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// MwMessageBox.Show("请先执行飞拍!");
|
||||
// return;
|
||||
//}
|
||||
}
|
||||
|
||||
public void btnStopVerifyWafer()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = MwMessageBox.Show("是否停止?", "确认停止", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
_stopMotion = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private bool ApproachPointWS(int approachTime = 10)
|
||||
{
|
||||
return false;
|
||||
//string modelFileName = WsfusionCalibVerifyParItem.ModelPath;
|
||||
//string path = System.AppDomain.CurrentDomain.BaseDirectory + modelFileName;
|
||||
//Rectangle1 r = GetRectangle();
|
||||
|
||||
//VisionOperation visionOperation = IoC.Get<VisionOperation>();
|
||||
////相机拍照
|
||||
//return visionOperation.ApproachPointCircle(_hardware.Camera_ExtendWS, _hardware.Axis_X2, _hardware.Axis_Y1, path, r, out System.Windows.Point point, approachTime);
|
||||
}
|
||||
|
||||
private Rectangle1 GetRectangle()
|
||||
{
|
||||
var region = CameraAxisViewModelSevice.Regions;
|
||||
Rectangle rectangle = null;
|
||||
Rectangle1 r = null;
|
||||
if (region != null && region.Count > 0)
|
||||
{
|
||||
RectRegion rect = region[0].Region as RectRegion;
|
||||
double start_x = rect.CenterPoint.X - rect.Width / 2;
|
||||
double start_y = rect.CenterPoint.Y - rect.Height / 2;
|
||||
double end_x = rect.CenterPoint.X + rect.Width / 2;
|
||||
double end_y = rect.CenterPoint.Y + rect.Height / 2;
|
||||
rectangle = new Rectangle(new System.Windows.Point(start_y, start_x), new System.Windows.Point(end_y, end_x));
|
||||
r = new Rectangle1();
|
||||
r.Start_X = rectangle.StartPoint.X;
|
||||
r.Start_Y = rectangle.StartPoint.Y;
|
||||
r.End_X = rectangle.EndPoint.X;
|
||||
r.End_Y = rectangle.EndPoint.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("请添加矩形!");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.AlgorithmCalib.Service;
|
||||
using MainShell.Common;
|
||||
using MainShell.Common.Display.ViewModel;
|
||||
using MainShell.Filewritable;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Motion;
|
||||
using Maxwell.SemiFramework.DefaultConfig.Vision;
|
||||
using Maxwell.SemiFramework.WaferCalibration.View;
|
||||
using Maxwell.SemiFramework.WaferCalibration.ViewModel;
|
||||
using MaxwellControl.Tools;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.ControlCanvas.DrawingControl;
|
||||
using MwFramework.Controls.ControlCanvas.Model;
|
||||
using MwFramework.Device;
|
||||
using MwFramework.ManagerService;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using SemiconductorVisionAlgorithm.SemiWaferRecip;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using CameraAxisViewModel = MainShell.Common.Display.ViewModel.CameraAxisViewModel;
|
||||
using Point = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class CameraFusionCalibViewModel:Screen,IPage
|
||||
{
|
||||
private bool _stopMotion = false;
|
||||
public string Name { get; set; } = "CameraFusionCalib";
|
||||
public string CalibName { get; set; }
|
||||
|
||||
public string CameraName { get; set; }
|
||||
|
||||
private readonly FusionCalibMotionService _fusionCalibMotionService;
|
||||
|
||||
private HardwareManager _hardware;
|
||||
|
||||
private DelegateBase _motion = new DelegateBase();
|
||||
public DelegateBase Motion
|
||||
{
|
||||
get
|
||||
{
|
||||
return _motion;
|
||||
}
|
||||
set
|
||||
{
|
||||
_motion = value;
|
||||
OnPropertyChanged(nameof(Motion));
|
||||
}
|
||||
}
|
||||
|
||||
private CameraAxisViewModel _cameraAxisViewModelSevice = new CameraAxisViewModel();
|
||||
public CameraAxisViewModel CameraAxisViewModelSevice
|
||||
{
|
||||
get { return _cameraAxisViewModelSevice; }
|
||||
set
|
||||
{
|
||||
_cameraAxisViewModelSevice = value;
|
||||
OnPropertyChanged(nameof(CameraAxisViewModelSevice));
|
||||
}
|
||||
}
|
||||
|
||||
private FusionCalibParItem _wsFusionCalibParItem = new FusionCalibParItem();
|
||||
public FusionCalibParItem WsFusionCalibParItem
|
||||
{
|
||||
get { return _wsFusionCalibParItem; }
|
||||
set
|
||||
{
|
||||
_wsFusionCalibParItem = value;
|
||||
OnPropertyChanged(nameof(WsFusionCalibParItem));
|
||||
}
|
||||
}
|
||||
|
||||
private CameraFusionCalibViewModel _service;
|
||||
public CameraFusionCalibViewModel Service
|
||||
{
|
||||
get { return _service; }
|
||||
set
|
||||
{
|
||||
_service = value;
|
||||
NotifyOfPropertyChange();
|
||||
}
|
||||
}
|
||||
|
||||
public CameraFusionCalibViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private bool _isInitialized = false;
|
||||
|
||||
public void viewLoad()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
|
||||
if (_isInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_hardware != null)
|
||||
{
|
||||
_cameraAxisViewModelSevice = new CameraAxisViewModel();
|
||||
_cameraAxisViewModelSevice.CameraAxisDevices.HardwareDeviceList = _hardware.CameraAxisManager.TopPositionCameraAxisDevices;
|
||||
NotifyOfPropertyChange(nameof(CameraAxisViewModelSevice));
|
||||
}
|
||||
|
||||
//RebuildModuleViewModels();
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
public void viewUnLoad()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public CameraFusionCalibViewModel(HardwareManager hardware, FusionCalibMotionService fusionCalibMotionService)
|
||||
{
|
||||
_hardware = hardware;
|
||||
_fusionCalibMotionService = fusionCalibMotionService ?? throw new ArgumentNullException(nameof(fusionCalibMotionService));
|
||||
|
||||
}
|
||||
|
||||
public static CameraFusionCalibViewModel Create(string name,string cameraName, List<HardwareDevice> device, HardwareManager hardware, FusionCalibMotionService motion)
|
||||
{
|
||||
var vm = new CameraFusionCalibViewModel(hardware,motion);
|
||||
vm.Initialize(name, device);
|
||||
return vm;
|
||||
}
|
||||
|
||||
private void Initialize(string cameraName, List<HardwareDevice> device)
|
||||
{
|
||||
CameraName = cameraName;
|
||||
Name = cameraName;
|
||||
//Hardware = device;
|
||||
//FileSaveDir = Path.Combine(Paths.CalibSettingPath, "bottomCamera");
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
|
||||
Service = new CameraFusionCalibViewModel();
|
||||
//Service.IsShowSolidLine = true;
|
||||
//Service.ShapeThickness = 1;
|
||||
//Service.DrawInConcurrency = false;
|
||||
//Service.IsAxisControlLDBVisible = Visibility.Visible;
|
||||
}
|
||||
|
||||
|
||||
public void btnMoveWSCalibPosPosition()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_fusionCalibMotionService.SafeMove(_hardware.Axis_X1, WsFusionCalibParItem.MoveAxisPos);
|
||||
_fusionCalibMotionService.MoveWsAvoidance(WsFusionCalibParItem.ApproachXPos, WsFusionCalibParItem.ApproachYPos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnApproachWSCalibPosition()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
//if (FindPointWSCircle())
|
||||
{
|
||||
WsFusionCalibParItem.ApproachXPos = _hardware.Axis_X2.State.ActualPos;
|
||||
WsFusionCalibParItem.ApproachYPos = _hardware.Axis_Y1.State.ActualPos;
|
||||
MessageBox.Show($"对齐值,X2:{WsFusionCalibParItem.ApproachXPos},Y1:{WsFusionCalibParItem.ApproachYPos}");
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// MessageBox.Show("对齐失败!");
|
||||
//}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnCalculateCameraPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
//起点覆盖标定范围,起点往负方向6mm
|
||||
int offset = -10;
|
||||
double X2MinPos = 0;
|
||||
_hardware.Axis_X2.GetSoftMel(ref X2MinPos);
|
||||
var delx = WsFusionCalibParItem.ApproachXPos - X2MinPos + offset;
|
||||
WsFusionCalibParItem.CameraAxisPos = WsFusionCalibParItem.MoveAxisPos - delx;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void btnSetCameraPosition()
|
||||
{
|
||||
|
||||
var result = MwMessageBox.Show("是否使用当前位置?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
WsFusionCalibParItem.CameraAxisPos = _hardware.Axis_X1.State.ActualPos;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void btnMoveCameraPosition()
|
||||
{
|
||||
var result = MwMessageBox.Show("是否移动到该点?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_fusionCalibMotionService.SafeMove(_hardware.Axis_X1, WsFusionCalibParItem.CameraAxisPos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void btnCalculateWSPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
//起点覆盖标定范围,起点往负方向6mm
|
||||
int offset = -10;
|
||||
double X2MinPos = 0;
|
||||
_hardware.Axis_X2.GetSoftMel(ref X2MinPos);
|
||||
|
||||
var delx = WsFusionCalibParItem.ApproachXPos - X2MinPos + offset;
|
||||
WsFusionCalibParItem.CameraAxisPos = WsFusionCalibParItem.MoveAxisPos - delx;
|
||||
|
||||
double x11Offset = WsFusionCalibParItem.CameraAxisPos - WsFusionCalibParItem.MoveAxisPos;
|
||||
WsFusionCalibParItem.StartX = WsFusionCalibParItem.ApproachXPos + x11Offset;
|
||||
WsFusionCalibParItem.StartY = WsFusionCalibParItem.ApproachYPos;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void btnSetWaferStartPosition()
|
||||
{
|
||||
var result = MwMessageBox.Show("是否使用当前位置?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
WsFusionCalibParItem.StartX = _hardware.Axis_X2.State.ActualPos;
|
||||
WsFusionCalibParItem.StartY = _hardware.Axis_Y1.State.ActualPos;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void btnMoveWaferStartPosition()
|
||||
{
|
||||
var result = MwMessageBox.Show("是否移动到该点?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fusionCalibMotionService.MoveWsAvoidance(WsFusionCalibParItem.StartX, WsFusionCalibParItem.StartY);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void btnMoveToCenter()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (ApproachPointWS(1))
|
||||
//{
|
||||
// CameraWaferFusionCalibrationItem.WaferStartVerifyX = _gs.Axis_X21.State.ActualPos;
|
||||
// CameraWaferFusionCalibrationItem.WaferStartVerifyY = _gs.Axis_Y21.State.ActualPos;
|
||||
// MwMessageBox.Show("中心对齐完成");
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// MwMessageBox.Show("逼近失败!");
|
||||
//}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnStart()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = MwMessageBox.Show("是否开始?", "确认开始", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
//CameraWaferFusionCalibrationItem.AxisAndPixelPointItemList.Clear();
|
||||
FusionCalib(false);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void btnStop()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = MwMessageBox.Show("是否开始?", "确认开始", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
Motion.Cancel();
|
||||
_stopMotion = true;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void FusionCalib(bool isRecheck, bool isAsyn = true)
|
||||
{
|
||||
Motion = (DelegateBase)TaskManager.Instance.GetIntance(typeof(FusionCalibTask));
|
||||
FusionCalibTask cameraFusionCalibration = Motion as FusionCalibTask;
|
||||
if (cameraFusionCalibration != null)
|
||||
{
|
||||
cameraFusionCalibration.Rectangle = GetRectangle();
|
||||
}
|
||||
TaskManager.Instance.AsyncStart(Motion, new object[] { });
|
||||
}
|
||||
|
||||
private Rectangle1 GetRectangle()
|
||||
{
|
||||
var region = CameraAxisViewModelSevice.Regions;
|
||||
Rectangle rectangle = null;
|
||||
Rectangle1 r = null;
|
||||
if (region != null && region.Count > 0)
|
||||
{
|
||||
RectRegion rect = region[0].Region as RectRegion;
|
||||
double start_x = rect.CenterPoint.X - rect.Width / 2;
|
||||
double start_y = rect.CenterPoint.Y - rect.Height / 2;
|
||||
double end_x = rect.CenterPoint.X + rect.Width / 2;
|
||||
double end_y = rect.CenterPoint.Y + rect.Height / 2;
|
||||
rectangle = new Rectangle(new System.Windows.Point(start_y, start_x), new System.Windows.Point(end_y, end_x));
|
||||
r = new Rectangle1();
|
||||
r.Start_X = rectangle.StartPoint.X;
|
||||
r.Start_Y = rectangle.StartPoint.Y;
|
||||
r.End_X = rectangle.EndPoint.X;
|
||||
r.End_Y = rectangle.EndPoint.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("请添加矩形!");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.AlgorithmCalib.Service;
|
||||
using MainShell.Common;
|
||||
using MainShell.Common.Display.ViewModel;
|
||||
using MainShell.Hardware;
|
||||
using Maxwell.SemiFramework.DefaultConfig.Vision;
|
||||
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.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Point = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class CameraFusionPadCalibVerifyViewModel:Screen,IPage
|
||||
{
|
||||
public string Name { get; set; } = "CameraFusionPadCalibVerify";
|
||||
|
||||
public string CameraName { get; set; }
|
||||
|
||||
private readonly FusionCalibMotionService _fusionCalibMotionService;
|
||||
|
||||
private HardwareManager _hardware;
|
||||
|
||||
private CameraAxisViewModel _cameraAxisViewModelSevice = new CameraAxisViewModel();
|
||||
public CameraAxisViewModel CameraAxisViewModelSevice
|
||||
{
|
||||
get { return _cameraAxisViewModelSevice; }
|
||||
set
|
||||
{
|
||||
_cameraAxisViewModelSevice = value;
|
||||
OnPropertyChanged(nameof(CameraAxisViewModelSevice));
|
||||
}
|
||||
}
|
||||
|
||||
private FusionCalibVerifyParItem _padfusionCalibVerifyParItem = new FusionCalibVerifyParItem();
|
||||
public FusionCalibVerifyParItem PadfusionCalibVerifyParItem
|
||||
{
|
||||
get { return _padfusionCalibVerifyParItem; }
|
||||
set
|
||||
{
|
||||
_padfusionCalibVerifyParItem = value;
|
||||
OnPropertyChanged(nameof(PadfusionCalibVerifyParItem));
|
||||
}
|
||||
}
|
||||
|
||||
private bool _stopMotion = false;
|
||||
|
||||
public CameraFusionPadCalibVerifyViewModel(HardwareManager hardware, FusionCalibMotionService fusionCalibMotionService)
|
||||
{
|
||||
_hardware = hardware;
|
||||
_fusionCalibMotionService = fusionCalibMotionService ?? throw new ArgumentNullException(nameof(fusionCalibMotionService));
|
||||
}
|
||||
|
||||
public static CameraFusionPadCalibVerifyViewModel Create(string name, string cameraName, List<HardwareDevice> device, HardwareManager hardware, FusionCalibMotionService motion)
|
||||
{
|
||||
var vm = new CameraFusionPadCalibVerifyViewModel(hardware, motion);
|
||||
vm.Initialize(name, device);
|
||||
return vm;
|
||||
}
|
||||
|
||||
private void Initialize(string cameraName, List<HardwareDevice> device)
|
||||
{
|
||||
CameraName = cameraName;
|
||||
Name = cameraName;
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
}
|
||||
|
||||
|
||||
public void btnMovePadCalibPosPosition()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_fusionCalibMotionService.SafeMove(_hardware.Axis_X1, PadfusionCalibVerifyParItem.MoveAxisPos);
|
||||
_fusionCalibMotionService.MoveWsAvoidance(PadfusionCalibVerifyParItem.ApproachXPos, PadfusionCalibVerifyParItem.ApproachYPos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnMoveToCenter()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ApproachPointPad(1))
|
||||
{
|
||||
PadfusionCalibVerifyParItem.StartX = _hardware.Axis_X2.State.ActualPos;
|
||||
PadfusionCalibVerifyParItem.StartY = _hardware.Axis_Y1.State.ActualPos;
|
||||
MwMessageBox.Show("中心对齐完成");
|
||||
}
|
||||
else
|
||||
{
|
||||
MwMessageBox.Show("逼近失败!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnMoveToStartPoint()
|
||||
{
|
||||
_fusionCalibMotionService.MovePhsAvoidance(PadfusionCalibVerifyParItem.StartX, PadfusionCalibVerifyParItem.StartY);
|
||||
}
|
||||
|
||||
public void btnMovePad()
|
||||
{
|
||||
//PadfusionCalibVerifyParItem.VerifyRealPts = new List<Point>();
|
||||
//List<Point> points = new List<Point>();
|
||||
//System.Threading.Tasks.Task.Run(() =>
|
||||
//{
|
||||
// for (var i = 0; i < PadfusionCalibVerifyParItem.CountY; i++)
|
||||
// {
|
||||
// for (var j = 0; j < PadfusionCalibVerifyParItem.CountX; j++)
|
||||
// {
|
||||
// if (_stopMotion)
|
||||
// {
|
||||
// _stopMotion = false;
|
||||
// return;
|
||||
// }
|
||||
// double yPos = PadfusionCalibVerifyParItem.StartY + i * PadfusionCalibVerifyParItem.Step;
|
||||
// double xPos;
|
||||
// if (i % 2 == 0)
|
||||
// {
|
||||
// xPos = PadfusionCalibVerifyParItem.StartX + j * PadfusionCalibVerifyParItem.Step;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// xPos = PadfusionCalibVerifyParItem.StartX + (PadfusionCalibVerifyParItem.CountX - j - 1) * PadfusionCalibVerifyParItem.Step;
|
||||
// }
|
||||
// points.Add(new Point(xPos, yPos));
|
||||
// _fusionCalibMotionService.MovePhsAvoidance(xPos, yPos);
|
||||
// if (ApproachPointPad())
|
||||
// {
|
||||
// //WsfusionCalibVerifyParItem.ApproachXPos = _hardware.Axis_X2.State.ActualPos;
|
||||
// //CameraWaferFusionCalibrationItem.WSVerityApproachXpos = _gs.Axis_X21.State.ActualPos;
|
||||
// //CameraWaferFusionCalibrationItem.WSVerityApproachYpos = _gs.Axis_Y21.State.ActualPos;
|
||||
// Point ruler = new Point(_hardware.Axis_X1.State.ActualPos, _hardware.Axis_Y2.State.ActualPos);
|
||||
// Point real = _visionOperation.GetRealByRuler(_hardware.Camera_ExtendWS.Id, ruler);
|
||||
// PadfusionCalibVerifyParItem.VerifyRealPts.Add(new Point(real.X, real.Y));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// MwMessageBox.Show("逼近失败!");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// MwMessageBox.Show("飞拍结束");
|
||||
//});
|
||||
}
|
||||
|
||||
public void btnVerifyPad()
|
||||
{
|
||||
//if (PadfusionCalibVerifyParItem.VerifyRealPts != null && PadfusionCalibVerifyParItem.VerifyRealPts.Count > 0)
|
||||
//{
|
||||
// var result = MwMessageBox.Show("是否已移动到Pad位置,确认开始验证?", "确认开始", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
// if (result == MessageBoxResult.Yes)
|
||||
// {
|
||||
// System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
// {
|
||||
// List<SemiconductorVisionAlgorithm.SemiParams.Point> PadrulerThen = new List<SemiconductorVisionAlgorithm.SemiParams.Point>();
|
||||
// List<SemiconductorVisionAlgorithm.SemiParams.Point> PadrulerNow = new List<SemiconductorVisionAlgorithm.SemiParams.Point>();
|
||||
// Point padReal = _visionOperation.GetRealByRuler(_gs.Camera_Extend.Id, new Point(_gs.Axis_X11.State.ActualPos, _gs.Axis_Y11.State.ActualPos));
|
||||
// for (var i = 0; i < PadfusionCalibVerifyParItem.VerifyRealPts.Count; i++)
|
||||
// {
|
||||
// if (_stopMotion)
|
||||
// {
|
||||
// _stopMotion = false;
|
||||
// return;
|
||||
// }
|
||||
// SemiconductorVisionAlgorithm.SemiParams.Point rulerPoint = new SemiconductorVisionAlgorithm.SemiParams.Point();
|
||||
// JM1Vision.JM1Manager.Instance.get_ws_pos(_gs.Camera_Extend.Id, _gs.Camera_ExtendWS.Id, new SemiconductorVisionAlgorithm.SemiParams.Point(padReal.X, padReal.Y), new SemiconductorVisionAlgorithm.SemiParams.Point(CameraWaferFusionCalibrationItem.VerityrealPointRealPoints[i].X, CameraWaferFusionCalibrationItem.VerityrealPointRealPoints[i].Y), out rulerPoint);
|
||||
// PadrulerThen.Add(new SemiconductorVisionAlgorithm.SemiParams.Point(rulerPoint.X, rulerPoint.Y));
|
||||
// _fusionCalibMotionService.MovePhsAvoidance(rulerPoint.X, rulerPoint.Y);
|
||||
// //_safeAxisMotion.SafeMoveWS(rulerPoint.X, rulerPoint.Y, isCalib: true);
|
||||
// if (ApproachPointPad())
|
||||
// {
|
||||
// PadrulerNow.Add(new SemiconductorVisionAlgorithm.SemiParams.Point(_hardware.Axis_X2.State.ActualPos, _hardware.Axis_Y1.State.ActualPos));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// MwMessageBox.Show("逼近失败!");
|
||||
// }
|
||||
// }
|
||||
// string filePath = System.AppDomain.CurrentDomain.BaseDirectory + @"CalibData";
|
||||
// JM1Vision.JM1Manager.Instance.pos_verify(filePath, PadrulerThen, PadrulerNow);
|
||||
// MwMessageBox.Show("验证完成!");
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// MwMessageBox.Show("请先执行飞拍!");
|
||||
// return;
|
||||
//}
|
||||
}
|
||||
|
||||
public void btnStopVerifyPad()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = MwMessageBox.Show("是否停止?", "确认停止", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
_stopMotion = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private bool ApproachPointPad(int approachTime = 10)
|
||||
{
|
||||
return false;
|
||||
//string modelFileName = PadfusionCalibVerifyParItem.ModelPath;
|
||||
//string path = System.AppDomain.CurrentDomain.BaseDirectory + modelFileName;
|
||||
//Rectangle1 r = GetRectangle();
|
||||
|
||||
//VisionOperation visionOperation = IoC.Get<VisionOperation>();
|
||||
////相机拍照
|
||||
//return visionOperation.ApproachPointCircle(_hardware.Camera_ExtendWS, _hardware.Axis_X2, _hardware.Axis_Y1, path, r, out System.Windows.Point point, approachTime);
|
||||
}
|
||||
|
||||
private Rectangle1 GetRectangle()
|
||||
{
|
||||
var region = CameraAxisViewModelSevice.Regions;
|
||||
Rectangle rectangle = null;
|
||||
Rectangle1 r = null;
|
||||
if (region != null && region.Count > 0)
|
||||
{
|
||||
RectRegion rect = region[0].Region as RectRegion;
|
||||
double start_x = rect.CenterPoint.X - rect.Width / 2;
|
||||
double start_y = rect.CenterPoint.Y - rect.Height / 2;
|
||||
double end_x = rect.CenterPoint.X + rect.Width / 2;
|
||||
double end_y = rect.CenterPoint.Y + rect.Height / 2;
|
||||
rectangle = new Rectangle(new System.Windows.Point(start_y, start_x), new System.Windows.Point(end_y, end_x));
|
||||
r = new Rectangle1();
|
||||
r.Start_X = rectangle.StartPoint.X;
|
||||
r.Start_Y = rectangle.StartPoint.Y;
|
||||
r.End_X = rectangle.EndPoint.X;
|
||||
r.End_Y = rectangle.EndPoint.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("请添加矩形!");
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.AlgorithmCalib.Service;
|
||||
using MainShell.Common;
|
||||
using MainShell.Common.Display.ViewModel;
|
||||
using MainShell.Filewritable;
|
||||
using MainShell.Hardware;
|
||||
using Maxwell.SemiFramework.WaferCalibration.ViewModel;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.SystemCalib;
|
||||
using MwFramework.Controls.UIControl;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using CameraAxisViewModel = MainShell.Common.Display.ViewModel.CameraAxisViewModel;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class CameraFusionPadCalibViewModel:Screen,IPage
|
||||
{
|
||||
private bool _stopMotion = false;
|
||||
public string Name { get; set; } = "CameraFusionPadCalib";
|
||||
|
||||
public string CameraName { get; set; }
|
||||
|
||||
private readonly FusionCalibMotionService _fusionCalibMotionService;
|
||||
|
||||
private HardwareManager _hardware;
|
||||
private string _fileSaveDir = Paths.CalibSettingPath;
|
||||
public string FileSaveDir
|
||||
{
|
||||
get { return _fileSaveDir; }
|
||||
set { SetAndNotify(ref _fileSaveDir, value); }
|
||||
}
|
||||
private CameraAxisViewModel _cameraAxisViewModelSevice;
|
||||
public CameraAxisViewModel CameraAxisViewModelSevice
|
||||
{
|
||||
get { return _cameraAxisViewModelSevice; }
|
||||
set
|
||||
{
|
||||
_cameraAxisViewModelSevice = value;
|
||||
OnPropertyChanged(nameof(CameraAxisViewModelSevice));
|
||||
}
|
||||
}
|
||||
|
||||
private FusionCalibParItem _fusionCalibParItem = new FusionCalibParItem();
|
||||
public FusionCalibParItem FusionCalibParItem
|
||||
{
|
||||
get { return _fusionCalibParItem; }
|
||||
set
|
||||
{
|
||||
_fusionCalibParItem = value;
|
||||
OnPropertyChanged(nameof(FusionCalibParItem));
|
||||
}
|
||||
}
|
||||
|
||||
private FusionCalibParItem _inputParam;
|
||||
public FusionCalibParItem InputParam
|
||||
{
|
||||
get { return _inputParam; }
|
||||
set { SetAndNotify(ref _inputParam, value); }
|
||||
}
|
||||
|
||||
private FusionCalibParItem _resultParam;
|
||||
public FusionCalibParItem ResultParam
|
||||
{
|
||||
get { return _resultParam; }
|
||||
set { SetAndNotify(ref _resultParam, value); }
|
||||
}
|
||||
|
||||
//private CameraFusionPadCalibViewModel _service;
|
||||
//public CameraFusionPadCalibViewModel Service
|
||||
//{
|
||||
// get { return _service; }
|
||||
// set
|
||||
// {
|
||||
// _service = value;
|
||||
// NotifyOfPropertyChange();
|
||||
// }
|
||||
//}
|
||||
|
||||
private bool _isInitialized=false;
|
||||
|
||||
public CameraFusionPadCalibViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public CameraFusionPadCalibViewModel(HardwareManager hardware, FusionCalibMotionService fusionCalibMotionService)
|
||||
{
|
||||
_hardware = hardware;
|
||||
_fusionCalibMotionService = fusionCalibMotionService ?? throw new ArgumentNullException(nameof(fusionCalibMotionService));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 弹窗专用工厂方法(新增):传入标定参数
|
||||
/// </summary>
|
||||
public static CameraFusionPadCalibViewModel Create(
|
||||
string cameraName, string fileSaveName, List<HardwareDevice> device, FusionCalibParItem param, HardwareManager hardware, FusionCalibMotionService fusionCalibMotionService)
|
||||
{
|
||||
var vm = new CameraFusionPadCalibViewModel(hardware,fusionCalibMotionService);
|
||||
vm.InputParam = param;
|
||||
vm.ResultParam = param;
|
||||
vm.Initialize(cameraName, fileSaveName, device, true);
|
||||
return vm;
|
||||
}
|
||||
|
||||
public void viewLoad()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
|
||||
if (_isInitialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_hardware != null)
|
||||
{
|
||||
_cameraAxisViewModelSevice = new CameraAxisViewModel();
|
||||
_cameraAxisViewModelSevice.CameraAxisDevices.HardwareDeviceList = _hardware.CameraAxisManager.TopPositionCameraAxisDevices;
|
||||
NotifyOfPropertyChange(nameof(CameraAxisViewModelSevice));
|
||||
}
|
||||
|
||||
//RebuildModuleViewModels();
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
public void viewUnLoad()
|
||||
{
|
||||
ResultParam = FusionCalibParItem;
|
||||
}
|
||||
private void Initialize(string cameraName, string fileSaveName, List<HardwareDevice> device, bool isSignUp)
|
||||
{
|
||||
//if (isSignUp)
|
||||
//{
|
||||
// IoC.Get<IEventAggregator>().Unsubscribe(this);
|
||||
// IoC.Get<IEventAggregator>().Subscribe(this);
|
||||
//}
|
||||
//CameraName = cameraName;
|
||||
Name = cameraName;
|
||||
//FileSaveName = fileSaveName;
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
|
||||
//Service = new CameraFusionPadCalibViewModel();
|
||||
FusionCalibParItem = InputParam;
|
||||
//string pathSavePath = Path.Combine(FileSaveDir, FileSaveName + ".xml");
|
||||
//Service.SetParaSavePath(pathSavePath);
|
||||
//Service.IsShowSolidLine = true;
|
||||
//Service.ShapeThickness = 1;
|
||||
//Service.DrawInConcurrency = false;
|
||||
//Service.IsAxisControlLDBVisible = Visibility.Visible;
|
||||
}
|
||||
|
||||
public void btnMovePhsCalibPosPosition()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_fusionCalibMotionService.SafeMove(_hardware.Axis_Y1, FusionCalibParItem.MoveAxisPos);
|
||||
_fusionCalibMotionService.MovePhsAvoidance(FusionCalibParItem.ApproachXPos, FusionCalibParItem.ApproachYPos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnApproachPhsCalibPosition()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
//if (FindPointWSCircle())
|
||||
//{
|
||||
FusionCalibParItem.ApproachXPos = _hardware.Axis_X1.State.ActualPos;
|
||||
FusionCalibParItem.ApproachYPos = _hardware.Axis_Y2.State.ActualPos;
|
||||
//CameraWaferFusionCalibrationItem.CenterX = _gs.Axis_X21.State.ActualPos;
|
||||
//CameraWaferFusionCalibrationItem.CenterY = _gs.Axis_Y21.State.ActualPos;
|
||||
MessageBox.Show($"对齐值,X1:{FusionCalibParItem.ApproachXPos},Y2:{FusionCalibParItem.ApproachYPos}");
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// MessageBox.Show("对齐失败!");
|
||||
//}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnCalculateCameraPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
//起点覆盖标定范围,起点往负方向6mm
|
||||
int offset = -10;
|
||||
double Y2MinPos = 0;
|
||||
_hardware.Axis_Y2.GetSoftMel(ref Y2MinPos);
|
||||
var delx = FusionCalibParItem.ApproachYPos - Y2MinPos + offset;
|
||||
FusionCalibParItem.CameraAxisPos = FusionCalibParItem.MoveAxisPos - delx;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void btnSetCameraPosition()
|
||||
{
|
||||
|
||||
var result = MwMessageBox.Show("是否使用当前位置?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
FusionCalibParItem.CameraAxisPos = _hardware.Axis_Y1.State.ActualPos;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void btnMoveCameraPosition()
|
||||
{
|
||||
var result = MwMessageBox.Show("是否移动到该点?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_fusionCalibMotionService.SafeMove(_hardware.Axis_Y1, FusionCalibParItem.CameraAxisPos);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void btnCalculatePhsPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
//起点覆盖标定范围,起点往负方向6mm
|
||||
int offset = -10;
|
||||
double Y2MinPos = 0;
|
||||
_hardware.Axis_Y2.GetSoftMel(ref Y2MinPos);
|
||||
|
||||
var delx = FusionCalibParItem.ApproachXPos - Y2MinPos + offset;
|
||||
FusionCalibParItem.CameraAxisPos = FusionCalibParItem.MoveAxisPos - delx;
|
||||
|
||||
double y11Offset = FusionCalibParItem.CameraAxisPos - FusionCalibParItem.MoveAxisPos;
|
||||
FusionCalibParItem.StartX = FusionCalibParItem.ApproachXPos;
|
||||
FusionCalibParItem.StartY = FusionCalibParItem.ApproachYPos + y11Offset;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void btnSetStageStartPosition()
|
||||
{
|
||||
var result = MwMessageBox.Show("是否使用当前位置?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
FusionCalibParItem.StartX = _hardware.Axis_X1.State.ActualPos;
|
||||
FusionCalibParItem.StartY = _hardware.Axis_Y2.State.ActualPos;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void btnMoveStageStartPosition()
|
||||
{
|
||||
var result = MwMessageBox.Show("是否移动到该点?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
_fusionCalibMotionService.MovePhsAvoidance(FusionCalibParItem.StartX, FusionCalibParItem.StartY);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void btnMoveToCenter()
|
||||
{
|
||||
System.Threading.Tasks.Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (ApproachPointWS(1))
|
||||
//{
|
||||
// CameraWaferFusionCalibrationItem.WaferStartVerifyX = _gs.Axis_X21.State.ActualPos;
|
||||
// CameraWaferFusionCalibrationItem.WaferStartVerifyY = _gs.Axis_Y21.State.ActualPos;
|
||||
// MwMessageBox.Show("中心对齐完成");
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// MwMessageBox.Show("逼近失败!");
|
||||
//}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void btnStart()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void btnStop()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
using MainShell.Hardware;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.Components;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class DistortionCorrectionCalibContentsViewModel:Screen,IPage
|
||||
{
|
||||
private HardwareManager _hardware;
|
||||
public ICommand PrevCommand { get; set; }
|
||||
public ICommand NextCommand { get; set; }
|
||||
private IParameterManager _parameterManager;
|
||||
public string Name { get; set; } = "DistortionCorrectionCalibContents";
|
||||
private bool _isInit = false;
|
||||
|
||||
private ObservableCollection<Screen> _screens;
|
||||
/// <summary>
|
||||
/// 需要显示的界面
|
||||
/// </summary>
|
||||
public ObservableCollection<Screen> Screens
|
||||
{
|
||||
get { return _screens; }
|
||||
set
|
||||
{ SetAndNotify(ref _screens, value); }
|
||||
}
|
||||
private Screen _showScreenVM;
|
||||
/// <summary>
|
||||
/// 当前显示界面的VM
|
||||
/// </summary>
|
||||
public Screen ShowScreenVM
|
||||
{
|
||||
get { return _showScreenVM; }
|
||||
set
|
||||
{ SetAndNotify(ref _showScreenVM, value); }
|
||||
}
|
||||
private string _currentCalibName;
|
||||
/// <summary>
|
||||
/// 当前标定名称,供UI标定
|
||||
/// </summary>
|
||||
public string CurrentCalibName
|
||||
{
|
||||
get { return _currentCalibName; }
|
||||
set { SetAndNotify(ref _currentCalibName, value); }
|
||||
}
|
||||
private string _progressText;
|
||||
/// <summary>
|
||||
/// 进度提示
|
||||
/// </summary>
|
||||
public string ProgressText
|
||||
{
|
||||
get { return _progressText; }
|
||||
set { SetAndNotify(ref _progressText, value); }
|
||||
}
|
||||
private int _ShowIndex;
|
||||
/// <summary>
|
||||
/// 当前显示界面的下标
|
||||
/// </summary>
|
||||
public int ShowIndex
|
||||
{
|
||||
get { return _ShowIndex; }
|
||||
set
|
||||
{ SetAndNotify(ref _ShowIndex, value); }
|
||||
}
|
||||
private bool _isEnablePrev;
|
||||
/// <summary>
|
||||
/// 上一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnablePrev
|
||||
{
|
||||
get { return _isEnablePrev; }
|
||||
set
|
||||
{ SetAndNotify(ref _isEnablePrev, value); }
|
||||
}
|
||||
private bool _isEnableNext = true;
|
||||
/// <summary>
|
||||
/// 下一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnableNext
|
||||
{
|
||||
get { return _isEnableNext; }
|
||||
set
|
||||
{ SetAndNotify(ref _isEnableNext, value); }
|
||||
}
|
||||
|
||||
public DistortionCorrectionCalibContentsViewModel(IParameterManager paraManager)
|
||||
{
|
||||
_hardware = IoC.Get<HardwareManager>();
|
||||
this._parameterManager = paraManager;
|
||||
PrevCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnPrev();
|
||||
});
|
||||
|
||||
NextCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnNext();
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
if (!_isInit)
|
||||
{
|
||||
Screens = new ObservableCollection<Screen>();
|
||||
// ====== 定义5组相机-轴配置 ======
|
||||
var cameraConfigs = new List<(string Name, List<HardwareDevice> Device)>
|
||||
{
|
||||
("上相机畸变标定", _hardware.CameraAxisManager.TopCameraAxisDevices),
|
||||
("上相机WS畸变标定", _hardware.CameraAxisManager.TopCameraWsAxisDevices),
|
||||
("广角相机畸变标定", _hardware.CameraAxisManager.WideCameraAxisDevices),
|
||||
("广角相机WS畸变标定", _hardware.CameraAxisManager.WideCameraWsAxisDevices),
|
||||
("下相机畸变标定", _hardware.CameraAxisManager.BottomCameraAxisDevices),
|
||||
};
|
||||
|
||||
foreach (var (name, device) in cameraConfigs)
|
||||
{
|
||||
Screens.Add(DistortionCorrectionCalibViewModel.Create(name, device));
|
||||
}
|
||||
// 默认显示第一个
|
||||
ShowIndex = 0;
|
||||
ShowScreenVM = Screens[0];
|
||||
UpdateNavigationState();
|
||||
_isInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void viewUnLoad()
|
||||
{
|
||||
//_device.ChangeCameraMode(CameraTriggerMode.On);
|
||||
//_pLCControlOperation.CyliderPress(true);
|
||||
}
|
||||
|
||||
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(); // ← 加上这行
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一更新导航状态和当前相机信息
|
||||
/// </summary>
|
||||
private void UpdateNavigationState()
|
||||
{
|
||||
IsEnablePrev = ShowIndex > 0;
|
||||
IsEnableNext = ShowIndex < Screens.Count - 1;
|
||||
|
||||
// 更新当前相机名称
|
||||
if (ShowScreenVM is DistortionCorrectionCalibViewModel camVm)
|
||||
{
|
||||
CurrentCalibName = camVm.CalibName;
|
||||
}
|
||||
|
||||
// 更新进度
|
||||
ProgressText = $"{ShowIndex + 1} / {Screens.Count}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class DistortionCorrectionCalibViewModel:Screen,IPage
|
||||
{
|
||||
public string Name { get; set; } = "DistortionCorrectionCalib";
|
||||
|
||||
/// <summary>
|
||||
/// 标定名称标识(用于UI显示和逻辑判断)
|
||||
/// </summary>
|
||||
public string CalibName { get; set; }
|
||||
|
||||
private MwFramework.Controls.SystemCalib.DistortionCorrectionCalibViewModel _service;
|
||||
public MwFramework.Controls.SystemCalib.DistortionCorrectionCalibViewModel Service
|
||||
{
|
||||
get { return _service; }
|
||||
set
|
||||
{
|
||||
_service = value;
|
||||
NotifyOfPropertyChange();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 无参构造函数
|
||||
/// </summary>
|
||||
public DistortionCorrectionCalibViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动创建时使用的静态工厂方法
|
||||
/// </summary>
|
||||
/// <param name="calibName">相机名称,如 "BottomCamera"</param>
|
||||
/// <param name="device">对应的硬件设备</param>
|
||||
public static DistortionCorrectionCalibViewModel Create(string calibName, List<HardwareDevice> device)
|
||||
{
|
||||
var vm = new DistortionCorrectionCalibViewModel();
|
||||
vm.Initialize(calibName, device);
|
||||
return vm;
|
||||
}
|
||||
|
||||
private void Initialize(string calibName, List<HardwareDevice> device)
|
||||
{
|
||||
CalibName = calibName;
|
||||
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
|
||||
Service = new MwFramework.Controls.SystemCalib.DistortionCorrectionCalibViewModel(
|
||||
device,
|
||||
paramList,
|
||||
true
|
||||
);
|
||||
Service.IsShowSolidLine = true;
|
||||
Service.ShapeThickness = 1;
|
||||
Service.DrawInConcurrency = false;
|
||||
Service.IsAxisControlLDBVisible = Visibility.Visible;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
// ===== 步骤1:Pad捕获 =====
|
||||
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);
|
||||
}
|
||||
|
||||
// ===== 步骤2:Die网格飞拍 =====
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
/// 融合标定子窗口VM(Die/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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
// 创建子窗口 VM(Pad模式)
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
using MainShell.AlgorithmCalib.Service;
|
||||
using MainShell.Hardware;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.Components;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class FusionCalibViewModel:Screen,IPage
|
||||
{
|
||||
private HardwareManager _hardware;
|
||||
private FusionCalibMotionService _fusionCalibMotionService;
|
||||
public ICommand PrevCommand { get; set; }
|
||||
public ICommand NextCommand { get; set; }
|
||||
private IParameterManager _parameterManager;
|
||||
public string Name { get; set; } = "FusionCalib";
|
||||
private bool _isInit = false;
|
||||
|
||||
private ObservableCollection<Screen> _Screens;
|
||||
/// <summary>
|
||||
/// 需要显示的界面
|
||||
/// </summary>
|
||||
public ObservableCollection<Screen> Screens
|
||||
{
|
||||
get { return _Screens; }
|
||||
set
|
||||
{ SetAndNotify(ref _Screens, value); }
|
||||
}
|
||||
private Screen _ShowScreenVM;
|
||||
/// <summary>
|
||||
/// 当前显示界面的VM
|
||||
/// </summary>
|
||||
public Screen ShowScreenVM
|
||||
{
|
||||
get { return _ShowScreenVM; }
|
||||
set
|
||||
{ SetAndNotify(ref _ShowScreenVM, value); }
|
||||
}
|
||||
private string _currentCalibName;
|
||||
/// <summary>
|
||||
/// 当前标定名称,供UI标定
|
||||
/// </summary>
|
||||
public string CurrentCalibName
|
||||
{
|
||||
get { return _currentCalibName; }
|
||||
set { SetAndNotify(ref _currentCalibName, value); }
|
||||
}
|
||||
private string _progressText;
|
||||
/// <summary>
|
||||
/// 进度提示
|
||||
/// </summary>
|
||||
public string ProgressText
|
||||
{
|
||||
get { return _progressText; }
|
||||
set { SetAndNotify(ref _progressText, value); }
|
||||
}
|
||||
private int _showIndex;
|
||||
/// <summary>
|
||||
/// 当前显示界面的下标
|
||||
/// </summary>
|
||||
public int ShowIndex
|
||||
{
|
||||
get { return _showIndex; }
|
||||
set
|
||||
{ SetAndNotify(ref _showIndex, value); }
|
||||
}
|
||||
private bool _isEnablePrev;
|
||||
/// <summary>
|
||||
/// 上一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnablePrev
|
||||
{
|
||||
get { return _isEnablePrev; }
|
||||
set
|
||||
{ SetAndNotify(ref _isEnablePrev, value); }
|
||||
}
|
||||
private bool _isEnableNext = true;
|
||||
/// <summary>
|
||||
/// 下一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnableNext
|
||||
{
|
||||
get { return _isEnableNext; }
|
||||
set
|
||||
{ SetAndNotify(ref _isEnableNext, value); }
|
||||
}
|
||||
public FusionCalibViewModel(IParameterManager paraManager)
|
||||
{
|
||||
_hardware = IoC.Get<HardwareManager>();
|
||||
_fusionCalibMotionService=IoC.Get<FusionCalibMotionService>();
|
||||
this._parameterManager = paraManager;
|
||||
PrevCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnPrev();
|
||||
});
|
||||
|
||||
NextCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnNext();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
if (!_isInit)
|
||||
{
|
||||
Screens = new ObservableCollection<Screen>();
|
||||
var cameraConfigs = new List<(string Name, string FileSaveName, List<HardwareDevice> Device)>
|
||||
{
|
||||
("Die融合标定","topWsCameraFusion", _hardware.CameraAxisManager.TopCameraWsAxisDevices),
|
||||
("Map相机融合标定","wideCameraFusion", _hardware.CameraAxisManager.WideCameraAxisDevices),
|
||||
};
|
||||
Screens.Add(FusionMenuCalibViewModel.Create("Pad融合标定", "topCameraFusion", _hardware.CameraAxisManager.TopCameraAxisDevices,_hardware,_fusionCalibMotionService));
|
||||
|
||||
foreach (var (name, fileSaveName, device) in cameraConfigs)
|
||||
{
|
||||
Screens.Add(CameraFusionCalibViewModel.Create(name, fileSaveName, device, _hardware, _fusionCalibMotionService));
|
||||
}
|
||||
// 默认显示第一个
|
||||
ShowIndex = 0;
|
||||
ShowScreenVM = Screens[0];
|
||||
UpdateNavigationState();
|
||||
_isInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void viewUnLoad()
|
||||
{
|
||||
//_device.ChangeCameraMode(CameraTriggerMode.On);
|
||||
//_pLCControlOperation.CyliderPress(true);
|
||||
}
|
||||
|
||||
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(); // ← 加上这行
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一更新导航状态和当前相机信息
|
||||
/// </summary>
|
||||
private void UpdateNavigationState()
|
||||
{
|
||||
IsEnablePrev = ShowIndex > 0;
|
||||
IsEnableNext = ShowIndex < Screens.Count - 1;
|
||||
|
||||
// 更新当前相机名称
|
||||
if (ShowScreenVM is CameraFusionCalibViewModel camVm)
|
||||
{
|
||||
CurrentCalibName = camVm.CalibName;
|
||||
}
|
||||
if (ShowScreenVM is FusionMenuCalibViewModel Vm)
|
||||
{
|
||||
CurrentCalibName = Vm.CalibName;
|
||||
}
|
||||
|
||||
// 更新进度
|
||||
ProgressText = $"{ShowIndex + 1} / {Screens.Count}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
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.Controls.SystemCalib;
|
||||
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;
|
||||
using System.Xml;
|
||||
using Point = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class FusionMenuCalibViewModel : Screen, IPage
|
||||
{
|
||||
private readonly Dictionary<string, Window> _calibWindows = new Dictionary<string, Window>();
|
||||
private List<Point> _calibResultRealPoint = new List<Point>();
|
||||
private List<Point> _calibResultAxisPoint = new List<Point>();
|
||||
private MotionFusion _motionFusion = new MotionFusion();
|
||||
private FusionCalibMotionService _fusionCalibMotionService;
|
||||
public string Name { get; set; } = "FusionMenuCalib";
|
||||
public string CalibName { get; set; }
|
||||
public string FileSaveDir { get; set; }
|
||||
private bool _isDataLoaded = false;
|
||||
|
||||
private CameraAxisViewModel _cameraAxisViewModelSevice = new CameraAxisViewModel();
|
||||
public CameraAxisViewModel CameraAxisViewModelSevice
|
||||
{
|
||||
get { return _cameraAxisViewModelSevice; }
|
||||
set
|
||||
{
|
||||
_cameraAxisViewModelSevice = value;
|
||||
OnPropertyChanged(nameof(CameraAxisViewModelSevice));
|
||||
}
|
||||
}
|
||||
private ObservableCollection<FusionCalibParItem> _fusionCalibParItem = new ObservableCollection<FusionCalibParItem>();
|
||||
public ObservableCollection<FusionCalibParItem> FusionCalibParItem
|
||||
{
|
||||
get { return _fusionCalibParItem; }
|
||||
set
|
||||
{
|
||||
_fusionCalibParItem = value;
|
||||
OnPropertyChanged(nameof(FusionCalibParItem));
|
||||
}
|
||||
}
|
||||
private FusionCalibParItem _selectedCalibPar;
|
||||
public FusionCalibParItem SelectedCalibPar
|
||||
{
|
||||
get { return _selectedCalibPar; }
|
||||
set
|
||||
{
|
||||
_selectedCalibPar = value;
|
||||
OnPropertyChanged(nameof(SelectedCalibPar));
|
||||
}
|
||||
}
|
||||
private FusionCalibParItem _inputParam;
|
||||
public FusionCalibParItem InputParam
|
||||
{
|
||||
get { return _inputParam; }
|
||||
set { SetAndNotify(ref _inputParam, value); }
|
||||
}
|
||||
private FusionCalibParItem _resultParam;
|
||||
public FusionCalibParItem ResultParam
|
||||
{
|
||||
get { return _resultParam; }
|
||||
set { SetAndNotify(ref _resultParam, value); }
|
||||
}
|
||||
private List<HardwareDevice> _hardwareDevice;
|
||||
public List<HardwareDevice> HardwareDevice
|
||||
{
|
||||
get { return _hardwareDevice; }
|
||||
set
|
||||
{
|
||||
_hardwareDevice = value;
|
||||
NotifyOfPropertyChange();
|
||||
}
|
||||
}
|
||||
private HardwareManager _hardware;
|
||||
public HardwareManager Hardware
|
||||
{
|
||||
get { return _hardware; }
|
||||
set
|
||||
{
|
||||
_hardware = value;
|
||||
NotifyOfPropertyChange();
|
||||
}
|
||||
}
|
||||
private bool _isCalibFinished;
|
||||
public bool IsCalibFinished
|
||||
{
|
||||
get { return _isCalibFinished; }
|
||||
set { SetAndNotify(ref _isCalibFinished, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 无参构造函数
|
||||
/// </summary>
|
||||
public FusionMenuCalibViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动创建时使用的静态工厂方法
|
||||
/// </summary>
|
||||
/// <param name="cameraName">相机名称,如 "BottomCamera"</param>
|
||||
/// <param name="device">对应的硬件设备</param>
|
||||
public static FusionMenuCalibViewModel Create(string calibName, string fileSaveName, List<HardwareDevice> device, HardwareManager hardware, FusionCalibMotionService motion)
|
||||
{
|
||||
var vm = new FusionMenuCalibViewModel();
|
||||
vm.Initialize(calibName, fileSaveName, device, hardware, motion);
|
||||
return vm;
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
|
||||
if (_hardware != null)
|
||||
{
|
||||
_cameraAxisViewModelSevice = new CameraAxisViewModel();
|
||||
_cameraAxisViewModelSevice.CameraAxisDevices.HardwareDeviceList = HardwareDevice;
|
||||
NotifyOfPropertyChange(nameof(CameraAxisViewModel));
|
||||
}
|
||||
if (!_isDataLoaded)
|
||||
{
|
||||
ReadCalibData();
|
||||
_isDataLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize(string calibName, string fileSaveName, List<HardwareDevice> device, HardwareManager hardware, FusionCalibMotionService motion)
|
||||
{
|
||||
CalibName = calibName;
|
||||
Hardware = hardware;
|
||||
HardwareDevice = device;
|
||||
_fusionCalibMotionService = motion;
|
||||
FileSaveDir = Path.Combine(Paths.CalibSettingPath, "fusionCalib");
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
}
|
||||
|
||||
public void btnOpenCalibWindow()
|
||||
{
|
||||
if (SelectedCalibPar == null)
|
||||
{
|
||||
MwMessageBox.Show("请先选择一组标定数据。", "提示",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
string cameraId = SelectedCalibPar.Camera_ID;
|
||||
|
||||
// ── 如果已有缓存窗口,直接激活显示 ──
|
||||
if (_calibWindows.TryGetValue(cameraId, out var existingWindow))
|
||||
{
|
||||
if (existingWindow.WindowState == WindowState.Minimized)
|
||||
existingWindow.WindowState = WindowState.Normal;
|
||||
existingWindow.Show();
|
||||
existingWindow.Activate();
|
||||
return;
|
||||
}
|
||||
|
||||
var calibVM = CameraFusionPadCalibViewModel.Create("", CalibName, HardwareDevice, SelectedCalibPar, Hardware, _fusionCalibMotionService);
|
||||
calibVM.FileSaveDir = this.FileSaveDir;
|
||||
|
||||
|
||||
|
||||
// ② 创建视图
|
||||
var calibView = new CameraFusionPadCalibView
|
||||
{
|
||||
DataContext = calibVM,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// 4. 创建 Window 包裹这个 UserControl
|
||||
var window = new Window
|
||||
{
|
||||
Title = $"融合标定-{cameraId}",
|
||||
Width = 1100,
|
||||
Height = 750,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
Owner = Application.Current.MainWindow,
|
||||
ResizeMode = ResizeMode.CanResize,
|
||||
Content = calibView
|
||||
};
|
||||
|
||||
// ── 拦截关闭:改为隐藏,保留内存状态 ──
|
||||
window.Closing += (s, args) =>
|
||||
{
|
||||
args.Cancel = true; // 取消真正的关闭
|
||||
window.Hide(); // 仅隐藏,VM 和 View 状态全部保留
|
||||
};
|
||||
|
||||
// ── 用 Unloaded 代替 Closed 做数据同步 ──
|
||||
// 每次隐藏时都把 Service 最新数据写回选中行
|
||||
window.IsVisibleChanged += (s, args) =>
|
||||
{
|
||||
if (!(bool)args.NewValue) // 变为不可见(Hide)
|
||||
{
|
||||
SyncCalibResultBack(calibVM);
|
||||
}
|
||||
};
|
||||
|
||||
// 缓存
|
||||
_calibWindows[cameraId] = window;
|
||||
window.Show();
|
||||
|
||||
|
||||
window.Closed += (s, args) =>
|
||||
{
|
||||
var innerData = calibVM.FusionCalibParItem;
|
||||
if (innerData != null)
|
||||
{
|
||||
SelectedCalibPar.Index = innerData.Index;
|
||||
SelectedCalibPar.MoveAxisPos = innerData.MoveAxisPos;
|
||||
SelectedCalibPar.ApproachXPos = innerData.ApproachXPos;
|
||||
SelectedCalibPar.ApproachYPos = innerData.ApproachYPos;
|
||||
SelectedCalibPar.StartX = innerData.StartX;
|
||||
SelectedCalibPar.StartY = innerData.StartY;
|
||||
SelectedCalibPar.Step = innerData.Step;
|
||||
SelectedCalibPar.Count = innerData.Count;
|
||||
SelectedCalibPar.RulerPoints = innerData.RulerPoints;
|
||||
SelectedCalibPar.RealPoints = innerData.RealPoints;
|
||||
// 刷新 DataGrid
|
||||
OnPropertyChanged(nameof(FusionCalibParItem));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将内部标定窗口的最新数据同步回外部 DataGrid 选中行
|
||||
/// </summary>
|
||||
private void SyncCalibResultBack(CameraFusionPadCalibViewModel calibVM)
|
||||
{
|
||||
var innerData = calibVM.ResultParam;
|
||||
if (innerData != null) return;
|
||||
var target = FusionCalibParItem.FirstOrDefault(p => p.Camera_ID == calibVM.CameraName);
|
||||
if(target == null) return;
|
||||
target.Index = innerData.Index;
|
||||
target.MoveAxisPos = innerData.MoveAxisPos;
|
||||
target.ApproachXPos = innerData.ApproachXPos;
|
||||
target.ApproachYPos = innerData.ApproachYPos;
|
||||
target.StartX = innerData.StartX;
|
||||
target.StartY = innerData.StartY;
|
||||
target.Step = innerData.Step;
|
||||
target.Count = innerData.Count;
|
||||
target.RulerPoints = innerData.RulerPoints;
|
||||
target.RealPoints = innerData.RealPoints;
|
||||
// 刷新 DataGrid
|
||||
OnPropertyChanged(nameof(FusionCalibParItem));
|
||||
}
|
||||
|
||||
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 paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
|
||||
//FusionCalibParItem.CalibParList = new ObservableCollection<FusionSysDataItem>();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var filePath = Path.Combine(FileSaveDir, $"Fusion_Time{i + 1}.xml");
|
||||
var pointsFilePath = Path.Combine(FileSaveDir, $"Fusion_Time{i + 1}.txt");
|
||||
|
||||
bool hasXml = File.Exists(filePath);
|
||||
bool hasTxt = File.Exists(pointsFilePath);
|
||||
|
||||
double moveAxisPos = 0;
|
||||
double approachXPos = 0;
|
||||
double approachYPos = 0;
|
||||
double startX = 0;
|
||||
double startY = 0;
|
||||
double step = 0;
|
||||
int count = 0;
|
||||
List<Point> rulerPoints = new List<Point>();
|
||||
List<Point> realPoints = new List<Point>();
|
||||
|
||||
// ① 有 XML → 读取参数
|
||||
if (hasXml)
|
||||
{
|
||||
//var uiData = UIDataManager.Instance.GetUIData<FusionCalibParItem>(paramList);
|
||||
//uiData.Read(filePath);
|
||||
//var xmlData=XmlReader(filePath);
|
||||
|
||||
//if (xmlData.Datas != null && xmlData.Datas.Count > 0)
|
||||
//{
|
||||
// var item = xmlData.Datas[0]; // 每个文件只有一组数据
|
||||
// index=item.Index;
|
||||
// moveAxisPos = item.MoveAxisPos;
|
||||
// approachXPos = item.ApproachXPos;
|
||||
// approachYPos = item.ApproachYPos;
|
||||
// startX = item.StartX;
|
||||
// startY = item.StartY;
|
||||
// step = item.Step;
|
||||
// count = item.Count;
|
||||
//}
|
||||
}
|
||||
|
||||
// ② 有 TXT → 读取标定点位
|
||||
if (hasTxt)
|
||||
{
|
||||
MotionCalibFileService.ReadCalibPointsFile(
|
||||
pointsFilePath, out realPoints, out rulerPoints);
|
||||
|
||||
rulerPoints = rulerPoints ?? new List<Point>();
|
||||
realPoints = realPoints ?? new List<Point>();
|
||||
}
|
||||
|
||||
// ③ 无论什么情况,都加到列表(保证 5 组都在)
|
||||
var par = new FusionCalibParItem
|
||||
{
|
||||
Index = i + 1,
|
||||
Camera_ID = "Fusion_Time" + (i + 1),
|
||||
MoveAxisPos = moveAxisPos,
|
||||
ApproachXPos = approachXPos,
|
||||
ApproachYPos = approachYPos,
|
||||
StartX = startX,
|
||||
StartY = startY,
|
||||
Step = step,
|
||||
Count = count,
|
||||
RulerPoints = rulerPoints,
|
||||
RealPoints = realPoints,
|
||||
};
|
||||
FusionCalibParItem.Add(par);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void btnApplyCalibData()
|
||||
{
|
||||
//if (FusionCalibParItem.CalibParList.Count != 5)
|
||||
//{
|
||||
// MwMessageBox.Show("标定数据不足,请完成全部标定!", "提示", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
// return;
|
||||
//}
|
||||
//var result = MwMessageBox.Show($"确认应用标定数据?", "确认应用", MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
//if (result == MessageBoxResult.Yes)
|
||||
//{
|
||||
// if (true) //
|
||||
// {
|
||||
|
||||
// MwMessageBox.Show("应用标定数据成功!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
public void ApplayCalibData()
|
||||
{
|
||||
//List<string> cameraIdList = new List<string>();
|
||||
//for (int i = 0; i < 5; i++)
|
||||
//{
|
||||
// var resultPointsList = FusionCalibParItem.CalibParList[i];
|
||||
// _motionFusion.Set(i, resultPointsList.ResultRealPoints, resultPointsList.ResultAxisPoints);
|
||||
// cameraIdList.Add(resultPointsList.CameraId);
|
||||
//}
|
||||
//_motionFusion.AutoSelectPt(cameraIdList[0], cameraIdList[1], cameraIdList[2], cameraIdList[3], out _calibResultRealPoint, out _calibResultAxisPoint);
|
||||
|
||||
//MwAlgorithmHelper.Instance.RulerToRealMaritex("topCameraPad", _calibResultAxisPoint, _calibResultRealPoint, 1, 1, 1, 1, UIDataManager.CalibDataDir);
|
||||
}
|
||||
|
||||
public void XmlReader(string xmlFilePath)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
using MainShell.Hardware;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.Components;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class MotionCalibContentsViewModel : Screen, IPage
|
||||
{
|
||||
private HardwareManager _hardware;
|
||||
public ICommand PrevCommand { get; set; }
|
||||
public ICommand NextCommand { get; set; }
|
||||
private IParameterManager _parameterManager;
|
||||
public string Name { get; set; } = "MotionCalib";
|
||||
private bool _isInit = false;
|
||||
|
||||
private ObservableCollection<Screen> _screens;
|
||||
/// <summary>
|
||||
/// 需要显示的界面
|
||||
/// </summary>
|
||||
public ObservableCollection<Screen> Screens
|
||||
{
|
||||
get { return _screens; }
|
||||
set
|
||||
{ SetAndNotify(ref _screens, value); }
|
||||
}
|
||||
private Screen _showScreenVM;
|
||||
/// <summary>
|
||||
/// 当前显示界面的VM
|
||||
/// </summary>
|
||||
public Screen ShowScreenVM
|
||||
{
|
||||
get { return _showScreenVM; }
|
||||
set
|
||||
{ SetAndNotify(ref _showScreenVM, value); }
|
||||
}
|
||||
private string _currentCalibName;
|
||||
/// <summary>
|
||||
/// 当前标定名称,供UI标定
|
||||
/// </summary>
|
||||
public string CurrentCalibName
|
||||
{
|
||||
get { return _currentCalibName; }
|
||||
set { SetAndNotify(ref _currentCalibName, value); }
|
||||
}
|
||||
private string _progressText;
|
||||
/// <summary>
|
||||
/// 进度提示
|
||||
/// </summary>
|
||||
public string ProgressText
|
||||
{
|
||||
get { return _progressText; }
|
||||
set { SetAndNotify(ref _progressText, value); }
|
||||
}
|
||||
private int _ShowIndex;
|
||||
/// <summary>
|
||||
/// 当前显示界面的下标
|
||||
/// </summary>
|
||||
public int ShowIndex
|
||||
{
|
||||
get { return _ShowIndex; }
|
||||
set
|
||||
{ SetAndNotify(ref _ShowIndex, value); }
|
||||
}
|
||||
private bool _IsEnablePrev;
|
||||
/// <summary>
|
||||
/// 上一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnablePrev
|
||||
{
|
||||
get { return _IsEnablePrev; }
|
||||
set
|
||||
{ SetAndNotify(ref _IsEnablePrev, value); }
|
||||
}
|
||||
private bool _IsEnableNext = true;
|
||||
/// <summary>
|
||||
/// 下一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnableNext
|
||||
{
|
||||
get { return _IsEnableNext; }
|
||||
set
|
||||
{ SetAndNotify(ref _IsEnableNext, value); }
|
||||
}
|
||||
|
||||
public MotionCalibContentsViewModel(IParameterManager paraManager)
|
||||
{
|
||||
_hardware = IoC.Get<HardwareManager>();
|
||||
this._parameterManager = paraManager;
|
||||
PrevCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnPrev();
|
||||
});
|
||||
|
||||
NextCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnNext();
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
if (!_isInit)
|
||||
{
|
||||
Screens = new ObservableCollection<Screen>();
|
||||
Screens.Add(MotionMultipleCalibViewModel.Create("上相机运动系标定", "topCameraMotion", _hardware.CameraAxisManager.TopCameraAxisDevices));
|
||||
var cameraConfigs = new List<(string Name, string FileSaveName, List<HardwareDevice> Device)>
|
||||
{
|
||||
("上相机WS运动系标定","topWsCameraMotion", _hardware.CameraAxisManager.TopCameraWsAxisDevices),
|
||||
("广角相机运动系标定","wideCameraMotion", _hardware.CameraAxisManager.WideCameraAxisDevices),
|
||||
("广角相机WS运动系标定","wideWsCameraMotion", _hardware.CameraAxisManager.WideCameraWsAxisDevices),
|
||||
("下相机运动系标定","bottomCameraMotion", _hardware.CameraAxisManager.BottomCameraAxisDevices),
|
||||
};
|
||||
foreach (var (name, fileSaveName, device) in cameraConfigs)
|
||||
{
|
||||
Screens.Add(MotionCalibViewModel.Create(name, fileSaveName, device));
|
||||
}
|
||||
ShowIndex = 0;
|
||||
ShowScreenVM = Screens[0];
|
||||
UpdateNavigationState();
|
||||
_isInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void viewUnLoad()
|
||||
{
|
||||
// 关闭所有缓存的标定子窗口
|
||||
if (Screens != null)
|
||||
{
|
||||
foreach (var screen in Screens)
|
||||
{
|
||||
if (screen is MotionMultipleCalibViewModel 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(); // ← 加上这行
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一更新导航状态和当前相机信息
|
||||
/// </summary>
|
||||
private void UpdateNavigationState()
|
||||
{
|
||||
IsEnablePrev = ShowIndex > 0;
|
||||
IsEnableNext = ShowIndex < Screens.Count - 1;
|
||||
|
||||
// 更新当前相机名称
|
||||
if (ShowScreenVM is MotionMultipleCalibViewModel camVm)
|
||||
{
|
||||
CurrentCalibName = camVm.CalibName;
|
||||
}
|
||||
|
||||
if (ShowScreenVM is MotionCalibViewModel Vm)
|
||||
{
|
||||
CurrentCalibName = Vm.CalibName;
|
||||
}
|
||||
// 更新进度
|
||||
ProgressText = $"{ShowIndex + 1} / {Screens.Count}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
using MainShell.Filewritable;
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.AlgorithmCalib.Service;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.SystemCalib;
|
||||
using MwFramework.ManagerService;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Point = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class MotionCalibViewModel : Screen, IPage, IHandle<MotionCalibFinishEventArgs>
|
||||
{
|
||||
public string Name { get; set; } = "CameraMotionCalib";
|
||||
public string CalibName { get; private set; }
|
||||
public string CalibId { get; private set; }
|
||||
public string FileSaveName { get; private set; }
|
||||
|
||||
private MotionSysDataItem _inputParam;
|
||||
public MotionSysDataItem InputParam
|
||||
{
|
||||
get => _inputParam;
|
||||
set => SetAndNotify(ref _inputParam, value);
|
||||
}
|
||||
|
||||
private MotionSysDataItem _resultParam;
|
||||
public MotionSysDataItem ResultParam
|
||||
{
|
||||
get => _resultParam;
|
||||
set => SetAndNotify(ref _resultParam, value);
|
||||
}
|
||||
|
||||
private MotionSysDataItem _motionSysDataItem;
|
||||
public MotionSysDataItem MotionSysDataItem
|
||||
{
|
||||
get => _motionSysDataItem;
|
||||
set => SetAndNotify(ref _motionSysDataItem, value);
|
||||
}
|
||||
|
||||
private MotionSysCalibViewModel _service;
|
||||
public MotionSysCalibViewModel Service
|
||||
{
|
||||
get => _service;
|
||||
set => SetAndNotify(ref _service, value);
|
||||
}
|
||||
|
||||
private List<Point> _calibAxisPoints;
|
||||
public List<Point> CalibAxisPoints
|
||||
{
|
||||
get => _calibAxisPoints;
|
||||
set => SetAndNotify(ref _calibAxisPoints, value);
|
||||
}
|
||||
|
||||
private List<Point> _calibRealPoints;
|
||||
public List<Point> CalibRealPoints
|
||||
{
|
||||
get => _calibRealPoints;
|
||||
set => SetAndNotify(ref _calibRealPoints, value);
|
||||
}
|
||||
|
||||
private string _fileSaveDir = Paths.CalibSettingPath;
|
||||
public string FileSaveDir
|
||||
{
|
||||
get => _fileSaveDir;
|
||||
set => SetAndNotify(ref _fileSaveDir, value);
|
||||
}
|
||||
|
||||
private bool _isCalibFinished;
|
||||
public bool IsCalibFinished
|
||||
{
|
||||
get => _isCalibFinished;
|
||||
set => SetAndNotify(ref _isCalibFinished, value);
|
||||
}
|
||||
|
||||
public MotionCalibViewModel() { }
|
||||
|
||||
/// <summary>
|
||||
/// 普通创建:不订阅事件,不使用用户ID
|
||||
/// </summary>
|
||||
public static MotionCalibViewModel Create(
|
||||
string calibName, string fileSaveName, List<HardwareDevice> device)
|
||||
{
|
||||
var vm = new MotionCalibViewModel();
|
||||
vm.Initialize(calibName, fileSaveName, device,
|
||||
subscribeEvents: false, calibId: "", isUseUserId: false);
|
||||
return vm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 弹窗专用:传入标定参数,订阅事件,使用用户ID
|
||||
/// </summary>
|
||||
public static MotionCalibViewModel Create(
|
||||
string calibName, string fileSaveName, List<HardwareDevice> device,
|
||||
MotionSysDataItem param, string calibId = "")
|
||||
{
|
||||
var vm = new MotionCalibViewModel();
|
||||
vm.Initialize(calibName, fileSaveName, device,
|
||||
subscribeEvents: true, calibId: calibId, isUseUserId: true);
|
||||
vm.InputParam = param;
|
||||
return vm;
|
||||
}
|
||||
|
||||
private void Initialize(
|
||||
string calibName, string fileSaveName, List<HardwareDevice> device,
|
||||
bool subscribeEvents, string calibId = "", bool isUseUserId = false)
|
||||
{
|
||||
if (subscribeEvents)
|
||||
{
|
||||
IoC.Get<IEventAggregator>().Unsubscribe(this);
|
||||
IoC.Get<IEventAggregator>().Subscribe(this);
|
||||
}
|
||||
|
||||
CalibName = calibName;
|
||||
CalibId = calibId;
|
||||
FileSaveName = fileSaveName;
|
||||
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
Service = isUseUserId
|
||||
? new MotionSysCalibViewModel(device, paramList, true, true, calibId)
|
||||
: new MotionSysCalibViewModel(device, paramList, true);
|
||||
|
||||
string pathSavePath = Path.Combine(FileSaveDir, FileSaveName + ".xml");
|
||||
Service.SetParaSavePath(pathSavePath);
|
||||
Service.IsShowSolidLine = true;
|
||||
Service.ShapeThickness = 1;
|
||||
Service.DrawInConcurrency = false;
|
||||
Service.IsAxisControlLDBVisible = Visibility.Visible;
|
||||
}
|
||||
|
||||
public void FetchCalibResult()
|
||||
{
|
||||
if (Service == null || !Service.IsCalibTaskCompleted)
|
||||
return;
|
||||
|
||||
var (axisPoints, realPoints) = Service.GetCalibResult();
|
||||
CalibAxisPoints = axisPoints;
|
||||
CalibRealPoints = realPoints;
|
||||
|
||||
var filePath = Path.Combine(FileSaveDir, $"{FileSaveName}.csv");
|
||||
MotionCalibFileService.SaveCalibPointsFile(filePath, CalibRealPoints, CalibAxisPoints);
|
||||
}
|
||||
|
||||
public void Handle(MotionCalibFinishEventArgs message)
|
||||
{
|
||||
FetchCalibResult();
|
||||
}
|
||||
|
||||
// 修复:页面关闭时取消事件订阅,防止内存泄漏
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
IoC.Get<IEventAggregator>().Unsubscribe(this);
|
||||
base.OnDeactivate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,603 @@
|
||||
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 MainShell.Recipe.Models;
|
||||
using MainShell.Recipe.ViewModel;
|
||||
using Maxwell.SemiFramework.WaferCalibration.ViewModel;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.SystemCalib;
|
||||
using MwFramework.Controls.UIControl;
|
||||
using MwFramework.ManagerService;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using CameraAxisViewModel = MainShell.Common.Display.ViewModel.CameraAxisViewModel;
|
||||
using Point = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class MotionMultipleCalibViewModel:Screen,IPage
|
||||
{
|
||||
#region 常量
|
||||
|
||||
private const int CalibAreaCount = 5;
|
||||
private const string PointsFileExt = ".csv";
|
||||
private const string AreaFilePrefix = "Camera_Area";
|
||||
|
||||
#endregion
|
||||
|
||||
#region 字段
|
||||
|
||||
private readonly HashSet<string> _forceCloseIds = new HashSet<string>();
|
||||
private readonly Dictionary<string, Window> _calibWindows = new Dictionary<string, Window>();
|
||||
private readonly MotionFusion _motionFusion = new MotionFusion();
|
||||
private List<Point> _calibResultRealPoint = new List<Point>();
|
||||
private List<Point> _calibResultAxisPoint = new List<Point>();
|
||||
private bool _isDataLoaded = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性
|
||||
|
||||
public string Name { get; set; } = "MotionMenuCalib";
|
||||
public string CalibName { get; set; }
|
||||
public string FileSaveDir { get; set; }
|
||||
|
||||
private CameraAxisViewModel _cameraAxisViewModelService;
|
||||
public CameraAxisViewModel CameraAxisViewModelService
|
||||
{
|
||||
get => _cameraAxisViewModelService;
|
||||
set => SetAndNotify(ref _cameraAxisViewModelService, value);
|
||||
}
|
||||
|
||||
private DelegateBase _motion = new DelegateBase();
|
||||
public DelegateBase Motion
|
||||
{
|
||||
get => _motion;
|
||||
set => SetAndNotify(ref _motion, value);
|
||||
}
|
||||
|
||||
private ObservableCollection<MotionSysDataItem> _motionCalibParItem = new ObservableCollection<MotionSysDataItem>();
|
||||
public ObservableCollection<MotionSysDataItem> MotionCalibParItem
|
||||
{
|
||||
get => _motionCalibParItem;
|
||||
set => SetAndNotify(ref _motionCalibParItem, value);
|
||||
}
|
||||
|
||||
private MotionSysDataItem _selectedCalibPar;
|
||||
public MotionSysDataItem SelectedCalibPar
|
||||
{
|
||||
get => _selectedCalibPar;
|
||||
set => SetAndNotify(ref _selectedCalibPar, value);
|
||||
}
|
||||
|
||||
private List<HardwareDevice> _hardware;
|
||||
public List<HardwareDevice> Hardware
|
||||
{
|
||||
get => _hardware;
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _hardware, value);
|
||||
NotifyOfPropertyChange();
|
||||
}
|
||||
}
|
||||
|
||||
private MotionSysCalibViewModel _service;
|
||||
public MotionSysCalibViewModel Service
|
||||
{
|
||||
get => _service;
|
||||
set => SetAndNotify(ref _service, value);
|
||||
}
|
||||
|
||||
private bool _isCalibFinished;
|
||||
public bool IsCalibFinished
|
||||
{
|
||||
get => _isCalibFinished;
|
||||
set => SetAndNotify(ref _isCalibFinished, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 构造 & 工厂
|
||||
|
||||
public MotionMultipleCalibViewModel()
|
||||
{
|
||||
_cameraAxisViewModelService = IoC.Get<CameraAxisViewModel>();
|
||||
}
|
||||
|
||||
public static MotionMultipleCalibViewModel Create(string calibName, string saveFileName, List<HardwareDevice> device)
|
||||
{
|
||||
var vm = new MotionMultipleCalibViewModel();
|
||||
vm.Initialize(calibName, saveFileName, device);
|
||||
return vm;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 初始化 & 生命周期
|
||||
|
||||
private void Initialize(string calibName, string saveFileName, List<HardwareDevice> device)
|
||||
{
|
||||
CalibName = calibName;
|
||||
Hardware = device;
|
||||
FileSaveDir = Path.Combine(Paths.CalibSettingPath, "motionCalib");
|
||||
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
|
||||
Service = new MotionSysCalibViewModel(device, paramList, true)
|
||||
{
|
||||
IsShowSolidLine = true,
|
||||
ShapeThickness = 1,
|
||||
DrawInConcurrency = false,
|
||||
IsAxisControlLDBVisible = Visibility.Visible
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
|
||||
if (_hardware != null)
|
||||
{
|
||||
_cameraAxisViewModelService.CameraAxisDevices.HardwareDeviceList = Hardware;
|
||||
NotifyOfPropertyChange(nameof(CameraAxisViewModelService));
|
||||
}
|
||||
|
||||
if (!_isDataLoaded)
|
||||
{
|
||||
ReadCalibData();
|
||||
_isDataLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 文件路径辅助
|
||||
|
||||
private string GetXmlPath(int areaIndex) =>
|
||||
Path.Combine(FileSaveDir, $"{AreaFilePrefix}{areaIndex}.xml");
|
||||
|
||||
private string GetPointsPath(int areaIndex) =>
|
||||
Path.Combine(FileSaveDir, $"{AreaFilePrefix}{areaIndex}{PointsFileExt}");
|
||||
|
||||
#endregion
|
||||
|
||||
#region 打开标定窗口
|
||||
|
||||
public void btnOpenCalibWindow()
|
||||
{
|
||||
if (SelectedCalibPar == null)
|
||||
{
|
||||
MwMessageBox.Show("请先选择一组标定数据。", "提示",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
string calibId = SelectedCalibPar.CalibId;
|
||||
|
||||
// 已有缓存窗口 → 激活显示
|
||||
if (_calibWindows.TryGetValue(calibId, out var existingWindow))
|
||||
{
|
||||
if (existingWindow.WindowState == WindowState.Minimized)
|
||||
existingWindow.WindowState = WindowState.Normal;
|
||||
existingWindow.Show();
|
||||
existingWindow.Activate();
|
||||
return;
|
||||
}
|
||||
|
||||
// 首次打开:创建子窗口 VM
|
||||
var calibVM = MotionCalibViewModel.Create(
|
||||
CalibName, SelectedCalibPar.CameraId, Hardware,
|
||||
SelectedCalibPar, SelectedCalibPar.CalibId);
|
||||
calibVM.FileSaveDir = FileSaveDir;
|
||||
|
||||
var window = CreateCalibWindow(calibId, calibVM);
|
||||
|
||||
// 写入当前行数据到子窗口
|
||||
SyncFields(SelectedCalibPar, calibVM.Service?.SelectedSingleUIData);
|
||||
|
||||
_calibWindows[calibId] = window;
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private Window CreateCalibWindow(string calibId, MotionCalibViewModel calibVM)
|
||||
{
|
||||
var calibView = new MotionCalibView { DataContext = calibVM };
|
||||
|
||||
var window = new Window
|
||||
{
|
||||
Title = $"运动系标定 - {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 数据双向同步
|
||||
|
||||
/// <summary>
|
||||
/// 共享的字段映射:将 source 的参数写入 target(单向)
|
||||
/// </summary>
|
||||
private void SyncFields(MotionSysDataItem source, MotionSysDataItem target)
|
||||
{
|
||||
if (source == null || target == null) return;
|
||||
|
||||
target.StartAxisX = source.StartAxisX;
|
||||
target.StartAxisY = source.StartAxisY;
|
||||
target.StartRealX = source.StartRealX;
|
||||
target.StartRealY = source.StartRealY;
|
||||
target.Rows = source.Rows;
|
||||
target.RowStep = source.RowStep;
|
||||
target.Columns = source.Columns;
|
||||
target.ColumnStep = source.ColumnStep;
|
||||
target.XDirSpace = source.XDirSpace;
|
||||
target.CameraZPos = source.CameraZPos;
|
||||
target.Threshold = source.Threshold;
|
||||
|
||||
// 标定点位用深拷贝,避免子窗口和主页面共享同一引用
|
||||
if (source.ResultRealPoints != null && source.ResultRealPoints.Count > 0)
|
||||
target.ResultRealPoints = new List<Point>(source.ResultRealPoints);
|
||||
|
||||
if (source.ResultAxisPoints != null && source.ResultAxisPoints.Count > 0)
|
||||
target.ResultAxisPoints = new List<Point>(source.ResultAxisPoints);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 子窗口关闭时:子窗口 → 主页面对应行
|
||||
/// </summary>
|
||||
private void SyncResultBack(MotionCalibViewModel calibVM)
|
||||
{
|
||||
var innerData = calibVM.Service?.SelectedSingleUIData;
|
||||
if (innerData == null) return;
|
||||
|
||||
var target = MotionCalibParItem.FirstOrDefault(p => p.CalibId == calibVM.CalibId);
|
||||
if (target == null) return;
|
||||
|
||||
SyncFields(innerData, target);
|
||||
OnPropertyChanged(nameof(MotionCalibParItem));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 保存数据
|
||||
|
||||
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
|
||||
{
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
Directory.CreateDirectory(FileSaveDir);
|
||||
|
||||
for (int i = 0; i < MotionCalibParItem.Count; i++)
|
||||
{
|
||||
int areaIndex = i + 1;
|
||||
var par = MotionCalibParItem[i];
|
||||
var xmlPath = GetXmlPath(areaIndex);
|
||||
var pointsPath = GetPointsPath(areaIndex);
|
||||
|
||||
// ① 保存 XML 参数
|
||||
SaveXmlParam(paramList, xmlPath, par);
|
||||
|
||||
// ② 保存标定点位
|
||||
if (HasCalibPoints(par))
|
||||
{
|
||||
MotionCalibFileService.SaveCalibPointsFile(
|
||||
pointsPath, par.ResultRealPoints, par.ResultAxisPoints);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"[MotionMenuCalib] SaveCalibData 失败: {ex}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveXmlParam(IParamList paramList, string xmlPath, MotionSysDataItem par)
|
||||
{
|
||||
var uiData = UIDataManager.Instance.GetUIData<MotionSysData>(paramList);
|
||||
|
||||
// 文件已存在 → 先读取保留完整结构,再回写
|
||||
if (File.Exists(xmlPath))
|
||||
uiData.Read(xmlPath);
|
||||
|
||||
if (uiData.Datas == null)
|
||||
uiData.Datas = new List<MotionSysDataItem>();
|
||||
|
||||
MotionSysDataItem item;
|
||||
if (uiData.Datas.Count > 0)
|
||||
{
|
||||
item = uiData.Datas[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
item = new MotionSysDataItem { Id = par.Id, CameraId = par.CameraId };
|
||||
uiData.Datas.Add(item);
|
||||
}
|
||||
|
||||
CopyParamFields(par, item);
|
||||
|
||||
uiData.IsManualCreated = true;
|
||||
uiData.Write(xmlPath);
|
||||
}
|
||||
|
||||
#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 paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
var items = new ObservableCollection<MotionSysDataItem>();
|
||||
|
||||
for (int i = 1; i <= CalibAreaCount; i++)
|
||||
{
|
||||
var par = ReadSingleArea(paramList, i);
|
||||
items.Add(par);
|
||||
}
|
||||
|
||||
MotionCalibParItem = items;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"[MotionMenuCalib] ReadCalibData 失败: {ex}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private MotionSysDataItem ReadSingleArea(IParamList paramList, int areaIndex)
|
||||
{
|
||||
var xmlPath = GetXmlPath(areaIndex);
|
||||
var pointsPath = GetPointsPath(areaIndex);
|
||||
|
||||
// 默认值
|
||||
double? startAxisX = 0, startAxisY = 0;
|
||||
double? startRealX = 0, startRealY = 0;
|
||||
int? rows = 0, columns = 0;
|
||||
double? rowStep = 0, columnStep = 0;
|
||||
List<Point> axisPoints = new List<Point>();
|
||||
List<Point> realPoints = new List<Point>();
|
||||
|
||||
// ① 读 XML 参数
|
||||
if (File.Exists(xmlPath))
|
||||
{
|
||||
var uiData = UIDataManager.Instance.GetUIData<MotionSysData>(paramList);
|
||||
uiData.Read(xmlPath);
|
||||
|
||||
if (uiData.Datas != null && uiData.Datas.Count > 0)
|
||||
{
|
||||
var item = uiData.Datas[0];
|
||||
startAxisX = item.StartAxisX;
|
||||
startAxisY = item.StartAxisY;
|
||||
startRealX = item.StartRealX;
|
||||
startRealY = item.StartRealY;
|
||||
rows = item.Rows;
|
||||
columns = item.Columns;
|
||||
rowStep = item.RowStep;
|
||||
columnStep = item.ColumnStep;
|
||||
}
|
||||
}
|
||||
|
||||
// ② 读标定点位
|
||||
if (File.Exists(pointsPath))
|
||||
{
|
||||
MotionCalibFileService.ReadCalibPointsFile(pointsPath, out realPoints, out axisPoints);
|
||||
axisPoints = axisPoints ?? new List<Point>();
|
||||
realPoints = realPoints ?? new List<Point>();
|
||||
}
|
||||
|
||||
return new MotionSysDataItem
|
||||
{
|
||||
Id = areaIndex.ToString(),
|
||||
CameraId = Hardware[0].Camera.Id,
|
||||
CalibId = $"{AreaFilePrefix}{areaIndex}",
|
||||
StartAxisX = startAxisX,
|
||||
StartAxisY = startAxisY,
|
||||
StartRealX = startRealX,
|
||||
StartRealY = startRealY,
|
||||
Rows = rows,
|
||||
RowStep = rowStep,
|
||||
Columns = columns,
|
||||
ColumnStep = columnStep,
|
||||
ResultAxisPoints = axisPoints,
|
||||
ResultRealPoints = realPoints
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 应用数据
|
||||
|
||||
public void btnApplyCalibData()
|
||||
{
|
||||
if (MotionCalibParItem.Count != CalibAreaCount)
|
||||
{
|
||||
MwMessageBox.Show("标定数据不足,请完成全部标定!", "提示",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var result = MwMessageBox.Show("确认应用标定数据?", "确认应用",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
if (ApplyCalibData())
|
||||
{
|
||||
MwMessageBox.Show("应用标定数据成功!", "提示",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ApplyCalibData()
|
||||
{
|
||||
try
|
||||
{
|
||||
var cameraIdList = new List<string>();
|
||||
|
||||
for (int i = 0; i < CalibAreaCount; i++)
|
||||
{
|
||||
var par = MotionCalibParItem[i];
|
||||
// Set 内部使用 1-based 区域编号
|
||||
_motionFusion.Set(i + 1, par.ResultRealPoints, par.ResultAxisPoints);
|
||||
cameraIdList.Add(par.CameraId);
|
||||
}
|
||||
|
||||
// AutoSelectPt 需要 4 个 CameraId(四象限融合)
|
||||
_motionFusion.AutoSelectPt(
|
||||
cameraIdList[0], cameraIdList[1],
|
||||
cameraIdList[2], cameraIdList[3],
|
||||
out _calibResultAxisPoint, out _calibResultRealPoint);
|
||||
|
||||
MwAlgorithmHelper.Instance.RulerToRealMaritex(
|
||||
Hardware[0].Camera.Id,
|
||||
_calibResultAxisPoint, _calibResultRealPoint,
|
||||
1, 1, 1, 1,
|
||||
UIDataManager.CalibDataDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"[MotionMenuCalib] ApplyCalibData 失败: {ex}");
|
||||
MwMessageBox.Show($"应用失败:{ex.Message}", "错误",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 公共辅助
|
||||
|
||||
/// <summary>
|
||||
/// 将 source 的参数字段拷贝到 target(不包含 ResultRealPoints / ResultAxisPoints)
|
||||
/// </summary>
|
||||
private static void CopyParamFields(MotionSysDataItem source, MotionSysDataItem target)
|
||||
{
|
||||
target.StartAxisX = source.StartAxisX;
|
||||
target.StartAxisY = source.StartAxisY;
|
||||
target.StartRealX = source.StartRealX;
|
||||
target.StartRealY = source.StartRealY;
|
||||
target.Rows = source.Rows;
|
||||
target.RowStep = source.RowStep;
|
||||
target.Columns = source.Columns;
|
||||
target.ColumnStep = source.ColumnStep;
|
||||
target.XDirSpace = source.XDirSpace;
|
||||
target.CameraZPos = source.CameraZPos;
|
||||
target.Threshold = source.Threshold;
|
||||
}
|
||||
|
||||
private static bool HasCalibPoints(MotionSysDataItem par) =>
|
||||
par.ResultRealPoints != null && par.ResultRealPoints.Count > 0 &&
|
||||
par.ResultAxisPoints != null && par.ResultAxisPoints.Count > 0;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 窗口生命周期
|
||||
|
||||
/// <summary>
|
||||
/// 主页面卸载时彻底关闭所有缓存窗口
|
||||
/// </summary>
|
||||
public void CleanupCalibWindows()
|
||||
{
|
||||
// 先标记所有需要强制关闭的 calibId
|
||||
foreach (var kvp in _calibWindows)
|
||||
_forceCloseIds.Add(kvp.Key);
|
||||
|
||||
// 逐个关闭
|
||||
foreach (var kvp in _calibWindows)
|
||||
{
|
||||
try
|
||||
{
|
||||
kvp.Value.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(
|
||||
$"[MotionMenuCalib] 关闭窗口 {kvp.Key} 失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
_calibWindows.Clear();
|
||||
_forceCloseIds.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
using MainShell.Hardware;
|
||||
using MaxwellFramework.Core.Common;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.Components;
|
||||
using MwFramework.Device;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class PixRatioCalibContentsViewModel:Screen,IPage
|
||||
{
|
||||
private HardwareManager _hardware;
|
||||
public ICommand PrevCommand { get; set; }
|
||||
public ICommand NextCommand { get; set; }
|
||||
private IParameterManager _parameterManager;
|
||||
public string Name { get; set; } = "PixRatioCalib";
|
||||
private bool _isInit = false;
|
||||
|
||||
private ObservableCollection<Screen> _screens;
|
||||
/// <summary>
|
||||
/// 需要显示的界面
|
||||
/// </summary>
|
||||
public ObservableCollection<Screen> Screens
|
||||
{
|
||||
get { return _screens; }
|
||||
set
|
||||
{ SetAndNotify(ref _screens, value); }
|
||||
}
|
||||
private Screen _showScreenVM;
|
||||
/// <summary>
|
||||
/// 当前显示界面的VM
|
||||
/// </summary>
|
||||
public Screen ShowScreenVM
|
||||
{
|
||||
get { return _showScreenVM; }
|
||||
set
|
||||
{ SetAndNotify(ref _showScreenVM, value); }
|
||||
}
|
||||
private string _currentCalibName;
|
||||
/// <summary>
|
||||
/// 当前标定名称,供UI标定
|
||||
/// </summary>
|
||||
public string CurrentCalibName
|
||||
{
|
||||
get { return _currentCalibName; }
|
||||
set { SetAndNotify(ref _currentCalibName, value); }
|
||||
}
|
||||
private string _progressText;
|
||||
/// <summary>
|
||||
/// 进度提示
|
||||
/// </summary>
|
||||
public string ProgressText
|
||||
{
|
||||
get { return _progressText; }
|
||||
set { SetAndNotify(ref _progressText, value); }
|
||||
}
|
||||
private int _showIndex;
|
||||
/// <summary>
|
||||
/// 当前显示界面的下标
|
||||
/// </summary>
|
||||
public int ShowIndex
|
||||
{
|
||||
get { return _showIndex; }
|
||||
set
|
||||
{ SetAndNotify(ref _showIndex, value); }
|
||||
}
|
||||
private bool _isEnablePrev;
|
||||
/// <summary>
|
||||
/// 上一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnablePrev
|
||||
{
|
||||
get { return _isEnablePrev; }
|
||||
set
|
||||
{ SetAndNotify(ref _isEnablePrev, value); }
|
||||
}
|
||||
private bool _isEnableNext = true;
|
||||
/// <summary>
|
||||
/// 下一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnableNext
|
||||
{
|
||||
get { return _isEnableNext; }
|
||||
set
|
||||
{ SetAndNotify(ref _isEnableNext, value); }
|
||||
}
|
||||
|
||||
public PixRatioCalibContentsViewModel(IParameterManager paraManager)
|
||||
{
|
||||
this._hardware = IoC.Get<HardwareManager>();
|
||||
this._parameterManager = paraManager;
|
||||
PrevCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnPrev();
|
||||
});
|
||||
|
||||
NextCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnNext();
|
||||
});
|
||||
}
|
||||
|
||||
#region view加载
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
if (!_isInit)
|
||||
{
|
||||
Screens = new ObservableCollection<Screen>();
|
||||
// ====== 定义5组相机-轴配置 ======
|
||||
var cameraConfigs = new List<(string Name, List<HardwareDevice> Device)>
|
||||
{
|
||||
("上相机像素比标定", _hardware.CameraAxisManager.TopCameraAxisDevices),
|
||||
("上相机WS像素比标定", _hardware.CameraAxisManager.TopCameraWsAxisDevices),
|
||||
("广角相机像素比标定", _hardware.CameraAxisManager.WideCameraAxisDevices),
|
||||
("广角相机WS像素比标定", _hardware.CameraAxisManager.WideCameraWsAxisDevices),
|
||||
("下相机像素比标定", _hardware.CameraAxisManager.BottomCameraAxisDevices),
|
||||
};
|
||||
|
||||
foreach (var (name, device) in cameraConfigs)
|
||||
{
|
||||
Screens.Add(PixRatioCalibViewModel.Create(name, device));
|
||||
}
|
||||
// 默认显示第一个
|
||||
ShowIndex = 0;
|
||||
ShowScreenVM = Screens[0];
|
||||
UpdateNavigationState();
|
||||
_isInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void viewUnLoad()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 按钮
|
||||
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();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 方法
|
||||
/// <summary>
|
||||
/// 统一更新导航状态和当前标定信息
|
||||
/// </summary>
|
||||
private void UpdateNavigationState()
|
||||
{
|
||||
IsEnablePrev = ShowIndex > 0;
|
||||
IsEnableNext = ShowIndex < Screens.Count - 1;
|
||||
|
||||
// 更新当前标定名称
|
||||
if (ShowScreenVM is PixRatioCalibViewModel camVm)
|
||||
{
|
||||
CurrentCalibName = camVm.CalibName;
|
||||
}
|
||||
|
||||
// 更新进度
|
||||
ProgressText = $"{ShowIndex + 1} / {Screens.Count}";
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using MainShell.Hardware;
|
||||
using MaxwellFramework.Core.Common;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.SystemCalib;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class PixRatioCalibViewModel:Screen,IPage
|
||||
{
|
||||
|
||||
public string Name { get; set; } = "CameraPixRatioCalib";
|
||||
public string CalibName { get; set; }
|
||||
|
||||
private CameraParaCalibViewModel _service;
|
||||
public CameraParaCalibViewModel Service
|
||||
{
|
||||
get { return _service; }
|
||||
set
|
||||
{
|
||||
_service = value;
|
||||
NotifyOfPropertyChange();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标定名称标识(用于UI显示和逻辑判断)
|
||||
/// </summary>
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 无参构造函数
|
||||
/// </summary>
|
||||
public PixRatioCalibViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动创建时使用的静态工厂方法
|
||||
/// </summary>
|
||||
/// <param name="calibName">标定名称,如 "上相机像素比标定"</param>
|
||||
/// <param name="device">对应的硬件设备</param>
|
||||
public static PixRatioCalibViewModel Create(string calibName, List<HardwareDevice> device)
|
||||
{
|
||||
var vm = new PixRatioCalibViewModel();
|
||||
vm.Initialize(calibName, device);
|
||||
return vm;
|
||||
}
|
||||
|
||||
private void Initialize(string calibName, List<HardwareDevice> device)
|
||||
{
|
||||
CalibName = calibName;
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
|
||||
Service = new CameraParaCalibViewModel(
|
||||
device,
|
||||
paramList,
|
||||
true
|
||||
);
|
||||
Service.IsShowSolidLine = true;
|
||||
Service.ShapeThickness = 1;
|
||||
Service.DrawInConcurrency = false;
|
||||
Service.IsAxisControlLDBVisible = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
using MainShell.Hardware;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.Components;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class RotateCenterCalibContentsViewModel:Screen,IPage
|
||||
{
|
||||
private HardwareManager _hardware;
|
||||
public ICommand PrevCommand { get; set; }
|
||||
public ICommand NextCommand { get; set; }
|
||||
private IParameterManager _parameterManager;
|
||||
public string Name { get; set; } = "RotateCenterCalib";
|
||||
|
||||
|
||||
private ObservableCollection<Screen> _screens;
|
||||
/// <summary>
|
||||
/// 需要显示的界面
|
||||
/// </summary>
|
||||
public ObservableCollection<Screen> Screens
|
||||
{
|
||||
get { return _screens; }
|
||||
set
|
||||
{ SetAndNotify(ref _screens, value); }
|
||||
}
|
||||
private Screen _showScreenVM;
|
||||
/// <summary>
|
||||
/// 当前显示界面的VM
|
||||
/// </summary>
|
||||
public Screen ShowScreenVM
|
||||
{
|
||||
get { return _showScreenVM; }
|
||||
set
|
||||
{ SetAndNotify(ref _showScreenVM, value); }
|
||||
}
|
||||
private string _currentCalibName;
|
||||
/// <summary>
|
||||
/// 当前标定名称,供UI标定
|
||||
/// </summary>
|
||||
public string CurrentCalibName
|
||||
{
|
||||
get { return _currentCalibName; }
|
||||
set { SetAndNotify(ref _currentCalibName, value); }
|
||||
}
|
||||
private string _progressText;
|
||||
/// <summary>
|
||||
/// 进度提示
|
||||
/// </summary>
|
||||
public string ProgressText
|
||||
{
|
||||
get { return _progressText; }
|
||||
set { SetAndNotify(ref _progressText, value); }
|
||||
}
|
||||
private int _showIndex;
|
||||
/// <summary>
|
||||
/// 当前显示界面的下标
|
||||
/// </summary>
|
||||
public int ShowIndex
|
||||
{
|
||||
get { return _showIndex; }
|
||||
set
|
||||
{ SetAndNotify(ref _showIndex, value); }
|
||||
}
|
||||
private bool _isEnablePrev;
|
||||
/// <summary>
|
||||
/// 上一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnablePrev
|
||||
{
|
||||
get { return _isEnablePrev; }
|
||||
set
|
||||
{ SetAndNotify(ref _isEnablePrev, value); }
|
||||
}
|
||||
private bool _isEnableNext = true;
|
||||
/// <summary>
|
||||
/// 下一个按钮是否启用
|
||||
/// </summary>
|
||||
public bool IsEnableNext
|
||||
{
|
||||
get { return _isEnableNext; }
|
||||
set
|
||||
{ SetAndNotify(ref _isEnableNext, value); }
|
||||
}
|
||||
|
||||
|
||||
public RotateCenterCalibContentsViewModel(IParameterManager paraManager)
|
||||
{
|
||||
_hardware = IoC.Get<HardwareManager>();
|
||||
this._parameterManager = paraManager;
|
||||
PrevCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnPrev();
|
||||
});
|
||||
|
||||
NextCommand = new DelegateCommand(() =>
|
||||
{
|
||||
OnNext();
|
||||
});
|
||||
}
|
||||
|
||||
private bool _isInit = false;
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
base.OnViewLoaded();
|
||||
if (!_isInit)
|
||||
{
|
||||
Screens = new ObservableCollection<Screen>();
|
||||
// ====== 定义5组相机-轴配置 ======
|
||||
var cameraConfigs = new List<(string Name, List<HardwareDevice> Device)>
|
||||
{
|
||||
("上相机旋转中心标定", _hardware.CameraAxisManager.TopCameraAxisDevices),
|
||||
("广角相机旋转中心标定", _hardware.CameraAxisManager.WideCameraAxisDevices),
|
||||
("下相机旋转中心标定", _hardware.CameraAxisManager.BottomCameraAxisDevices),
|
||||
};
|
||||
|
||||
foreach (var (name, device) in cameraConfigs)
|
||||
{
|
||||
Screens.Add(RotateCenterCalibViewModel.Create(name, device, _hardware.Axis_WS_R));
|
||||
}
|
||||
// 默认显示第一个
|
||||
ShowIndex = 0;
|
||||
ShowScreenVM = Screens[0];
|
||||
UpdateNavigationState();
|
||||
_isInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void viewUnLoad()
|
||||
{
|
||||
//_device.ChangeCameraMode(CameraTriggerMode.On);
|
||||
//_pLCControlOperation.CyliderPress(true);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一更新导航状态和当前相机信息
|
||||
/// </summary>
|
||||
private void UpdateNavigationState()
|
||||
{
|
||||
IsEnablePrev = ShowIndex > 0;
|
||||
IsEnableNext = ShowIndex < Screens.Count - 1;
|
||||
|
||||
// 更新当前相机名称
|
||||
if (ShowScreenVM is RotateCenterCalibViewModel camVm)
|
||||
{
|
||||
CurrentCalibName = camVm.CalibName;
|
||||
}
|
||||
|
||||
// 更新进度
|
||||
ProgressText = $"{ShowIndex + 1} / {Screens.Count}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Device;
|
||||
using MwFramework.ManagerService;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
public class RotateCenterCalibViewModel:Screen,IPage
|
||||
{
|
||||
public string Name { get; set; } = "CameraRotateCenterCalib";
|
||||
public string CalibName { get; set; }
|
||||
|
||||
private MwFramework.Controls.SystemCalib.RotateCenterSimpleViewModel _service;
|
||||
public MwFramework.Controls.SystemCalib.RotateCenterSimpleViewModel Service
|
||||
{
|
||||
get { return _service; }
|
||||
set
|
||||
{
|
||||
_service = value;
|
||||
NotifyOfPropertyChange();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 无参构造函数
|
||||
/// </summary>
|
||||
public RotateCenterCalibViewModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动创建时使用的静态工厂方法
|
||||
/// </summary>
|
||||
/// <param name="cameraName">相机名称,如 "BottomCamera"</param>
|
||||
/// <param name="device">对应的硬件设备</param>
|
||||
public static RotateCenterCalibViewModel Create(string calibName, List<HardwareDevice> device, IAxis rotateAxis)
|
||||
{
|
||||
var vm = new RotateCenterCalibViewModel();
|
||||
vm.Initialize(calibName, device, rotateAxis);
|
||||
return vm;
|
||||
}
|
||||
|
||||
private void Initialize(string calibName, List<HardwareDevice> device, IAxis rotateAxis)
|
||||
{
|
||||
CalibName = calibName;
|
||||
var paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
|
||||
Service = new MwFramework.Controls.SystemCalib.RotateCenterSimpleViewModel(
|
||||
device, rotateAxis, paramList);
|
||||
//这里参数站位
|
||||
|
||||
Service.IsShowSolidLine = true;
|
||||
Service.ShapeThickness = 1;
|
||||
Service.DrawInConcurrency = false;
|
||||
Service.IsAxisControlLDBVisible = Visibility.Visible;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.AlgorithmCalib.Service;
|
||||
using MainShell.Common;
|
||||
using MainShell.Common.Display.ViewModel;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Log;
|
||||
using MainShell.Motion;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.ControlCanvas.Model;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 对标 OriginCalibViewModel(页面主VM)
|
||||
/// 原 RotateFormCalibViewModel 中页面级逻辑搬到这里
|
||||
/// </summary>
|
||||
public class RotateMatixFormCalibViewModel : Screen, IPage
|
||||
{
|
||||
public string Name { get; set; } = "RotateFormCalib";
|
||||
|
||||
private readonly RotateMatixFormCalibSetting _setting;
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly RotateMatixFormCalibMotionService _motionService;
|
||||
private readonly ApproachAlignmentService _approachAlignmentService;
|
||||
private bool _isInitialized;
|
||||
|
||||
private RotateMatixFormModuleViewModel _module;
|
||||
public RotateMatixFormModuleViewModel Module
|
||||
{
|
||||
get { return _module; }
|
||||
private set { SetAndNotify(ref _module, value); }
|
||||
}
|
||||
private CameraAxisViewModel _cameraAxisViewModel;
|
||||
public CameraAxisViewModel CameraAxisViewModel
|
||||
{
|
||||
get { return _cameraAxisViewModel; }
|
||||
private set { SetAndNotify(ref _cameraAxisViewModel, value); }
|
||||
}
|
||||
|
||||
public RotateMatixFormCalibViewModel(
|
||||
HardwareManager hardware,
|
||||
RotateMatixFormCalibMotionService motionService,
|
||||
ApproachAlignmentService approachAlignmentService)
|
||||
{
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_motionService = motionService ?? throw new ArgumentNullException(nameof(motionService));
|
||||
_setting = RotateMatixFormCalibSetting.LoadOrCreate();
|
||||
_approachAlignmentService = approachAlignmentService;
|
||||
}
|
||||
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
// TODO: 对标 OriginCalibViewModel.OnViewLoaded()
|
||||
if (_isInitialized) return;
|
||||
|
||||
// 1. 初始化相机
|
||||
CameraAxisViewModel = IoC.Get<CameraAxisViewModel>();
|
||||
CameraAxisViewModel.CameraAxisDevices.HardwareDeviceList = _hardware.CameraAxisManager.TopCameraAxisDevices;
|
||||
|
||||
// 2. 初始化后处理器
|
||||
InitializePostProcessors();
|
||||
|
||||
// 3. 构建模块 ViewModel
|
||||
RebuildModuleViewModels();
|
||||
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对标 OriginCalibViewModel.InitializePostProcessors()
|
||||
/// 为每个模块注入 RotateFormCalibPostProcessor
|
||||
/// </summary>
|
||||
private void InitializePostProcessors()
|
||||
{
|
||||
foreach (var module in _setting.Modules)
|
||||
{
|
||||
module.PostProcessor = new RotateMatixFormCalibPostProcessor(
|
||||
_motionService,
|
||||
_hardware,
|
||||
module,
|
||||
_approachAlignmentService,
|
||||
GetRoiRect
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对标 OriginCalibViewModel.RebuildModuleViewModels()
|
||||
/// </summary>
|
||||
private void RebuildModuleViewModels()
|
||||
{
|
||||
Module = null;
|
||||
if (_setting.Modules.Count > 0)
|
||||
{
|
||||
Module = new RotateMatixFormModuleViewModel(
|
||||
_setting.Modules[0],
|
||||
_hardware,
|
||||
_motionService,
|
||||
_approachAlignmentService,
|
||||
GetRoiRect);
|
||||
Module.Index = 1;
|
||||
NotifyOfPropertyChange(nameof(Module));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对标 OriginCalibViewModel.SaveConfig()
|
||||
/// </summary>
|
||||
public void SaveConfig()
|
||||
{
|
||||
// 填入:
|
||||
try
|
||||
{
|
||||
_setting.Write();
|
||||
MwMessageBox.Show("标定数据已保存。", "旋转表标定",
|
||||
MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MwMessageBox.Show($"保存失败:{ex.Message}", "旋转表标定",
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对标 OriginCalibViewModel.ResetAll()
|
||||
/// </summary>
|
||||
public void ResetAll()
|
||||
{
|
||||
// 填入:
|
||||
Module?.ResetModule();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前 ROI 区域
|
||||
/// </summary>
|
||||
private Rectangle1 GetRoiRect()
|
||||
{
|
||||
try
|
||||
{
|
||||
var region = CameraAxisViewModel?.Regions;
|
||||
if (region != null && region.Count > 0)
|
||||
{
|
||||
RectRegion rect = region[0].Region as RectRegion;
|
||||
if (rect != null)
|
||||
{
|
||||
double start_x = rect.CenterPoint.X - rect.Width / 2;
|
||||
double start_y = rect.CenterPoint.Y - rect.Height / 2;
|
||||
double end_x = rect.CenterPoint.X + rect.Width / 2;
|
||||
double end_y = rect.CenterPoint.Y + rect.Height / 2;
|
||||
|
||||
return new Rectangle1
|
||||
{
|
||||
Start_X = start_y,
|
||||
Start_Y = start_x,
|
||||
End_X = end_y,
|
||||
End_Y = end_x
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
$"获取Region失败:{ex.Message}".LogSysError();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
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 Maxwell.SemiFramework.DefaultConfig.Vision;
|
||||
using MwFramework.Controls.ControlCanvas.Model;
|
||||
using MwFramework.Device;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.ViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 对标 OriginCalibModuleViewModel(模块卡片VM)
|
||||
/// 原 RotateFormCalibViewModel 中模块级逻辑 + 原 Task 的编排逻辑搬到这里
|
||||
/// </summary>
|
||||
public class RotateMatixFormModuleViewModel : PropertyChangedBase
|
||||
{
|
||||
private const string CalibrationDialogCaption = "旋转表标定";
|
||||
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly RotateMatixFormCalibMotionService _motionService;
|
||||
private readonly RotateMatixFormCalibModuleItem _item;
|
||||
private readonly ApproachAlignmentService _approachAlignmentService;
|
||||
private readonly Func<Rectangle1> _roiRectProvider; // ROI 提供者委托
|
||||
|
||||
private int _index;
|
||||
private bool _isCalibrating;
|
||||
private bool _isWritten;
|
||||
private CancellationTokenSource _cts;
|
||||
|
||||
public RotateMatixFormCalibModuleItem Item => _item;
|
||||
|
||||
#region 对标 OriginCalibModuleViewModel 的通用属性
|
||||
|
||||
public int Index
|
||||
{
|
||||
get { return _index; }
|
||||
set { SetAndNotify(ref _index, value); }
|
||||
}
|
||||
|
||||
public string ModuleName
|
||||
{
|
||||
get { return _item.ModuleName; }
|
||||
set { _item.ModuleName = value; NotifyOfPropertyChange(nameof(ModuleName)); }
|
||||
}
|
||||
|
||||
public bool IsCalibrating
|
||||
{
|
||||
get { return _isCalibrating; }
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _isCalibrating, value);
|
||||
NotifyOfPropertyChange(nameof(CanStartCalib));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsWritten
|
||||
{
|
||||
get { return _isWritten; }
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _isWritten, value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanStartCalib => !IsCalibrating;
|
||||
|
||||
private bool _isCalibrated;
|
||||
public bool IsCalibrated
|
||||
{
|
||||
get { return _isCalibrated; }
|
||||
set
|
||||
{
|
||||
SetAndNotify(ref _isCalibrated, value);
|
||||
NotifyOfPropertyChange(nameof(CanWriteToController));
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanWriteToController => !IsCalibrating && _isCalibrated;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 旋转表标定特有参数(绑定到 View)
|
||||
|
||||
public double X1AvoidancePosition
|
||||
{
|
||||
get { return _item.X1AvoidancePosition; }
|
||||
set { _item.X1AvoidancePosition = value; NotifyOfPropertyChange(nameof(X1AvoidancePosition)); }
|
||||
}
|
||||
|
||||
public double RotateStep
|
||||
{
|
||||
get { return _item.RotateStep; }
|
||||
set { _item.RotateStep = value; NotifyOfPropertyChange(nameof(RotateStep)); }
|
||||
}
|
||||
|
||||
public double WaferStep
|
||||
{
|
||||
get { return _item.WaferStep; }
|
||||
set { _item.WaferStep = value; NotifyOfPropertyChange(nameof(WaferStep)); }
|
||||
}
|
||||
|
||||
public int RowCol
|
||||
{
|
||||
get { return _item.RowCol; }
|
||||
set { _item.RowCol = value; NotifyOfPropertyChange(nameof(RowCol)); }
|
||||
}
|
||||
|
||||
public int VerifyRowCol
|
||||
{
|
||||
get { return _item.VerifyRowCol; }
|
||||
set { _item.VerifyRowCol = value; NotifyOfPropertyChange(nameof(VerifyRowCol)); }
|
||||
}
|
||||
|
||||
public double VerifyWaferStep
|
||||
{
|
||||
get { return _item.VerifyWaferStep; }
|
||||
set { _item.VerifyWaferStep = value; NotifyOfPropertyChange(nameof(VerifyWaferStep)); }
|
||||
}
|
||||
|
||||
public double VerifyRotateRange
|
||||
{
|
||||
get { return _item.VerifyRotateRange; }
|
||||
set { _item.VerifyRotateRange = value; NotifyOfPropertyChange(nameof(VerifyRotateRange)); }
|
||||
}
|
||||
|
||||
public double StartX
|
||||
{
|
||||
get { return _item.StartX; }
|
||||
set { _item.StartX = value; NotifyOfPropertyChange(nameof(StartX)); }
|
||||
}
|
||||
|
||||
public double StartY
|
||||
{
|
||||
get { return _item.StartY; }
|
||||
set { _item.StartY = value; NotifyOfPropertyChange(nameof(StartY)); }
|
||||
}
|
||||
|
||||
public double VerifyStartX
|
||||
{
|
||||
get { return _item.VerifyStartX; }
|
||||
set { _item.VerifyStartX = value; NotifyOfPropertyChange(nameof(VerifyStartX)); }
|
||||
}
|
||||
|
||||
public double VerifyStartY
|
||||
{
|
||||
get { return _item.VerifyStartY; }
|
||||
set { _item.VerifyStartY = value; NotifyOfPropertyChange(nameof(VerifyStartY)); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 标定进度
|
||||
|
||||
private string _progressMessage = "";
|
||||
public string ProgressMessage
|
||||
{
|
||||
get { return _progressMessage; }
|
||||
set { SetAndNotify(ref _progressMessage, value); }
|
||||
}
|
||||
|
||||
private int _progressCurrent;
|
||||
public int ProgressCurrent
|
||||
{
|
||||
get { return _progressCurrent; }
|
||||
set { SetAndNotify(ref _progressCurrent, value); }
|
||||
}
|
||||
|
||||
private int _progressTotal;
|
||||
public int ProgressTotal
|
||||
{
|
||||
get { return _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 { return _isProgressVisible; }
|
||||
set { SetAndNotify(ref _isProgressVisible, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
public RotateMatixFormModuleViewModel(
|
||||
RotateMatixFormCalibModuleItem item,
|
||||
HardwareManager hardware,
|
||||
RotateMatixFormCalibMotionService motionService,
|
||||
ApproachAlignmentService approachAlignmentService,
|
||||
Func<Rectangle1> roiRectProvider)
|
||||
{
|
||||
_item = item ?? throw new ArgumentNullException(nameof(item));
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_motionService = motionService ?? throw new ArgumentNullException(nameof(motionService));
|
||||
_approachAlignmentService = approachAlignmentService ?? throw new ArgumentNullException(nameof(approachAlignmentService));
|
||||
_roiRectProvider = roiRectProvider;
|
||||
SubscribeToProgress();
|
||||
}
|
||||
private void SubscribeToProgress()
|
||||
{
|
||||
if (_item.PostProcessor is RotateMatixFormCalibPostProcessor processor)
|
||||
{
|
||||
processor.ProgressChanged += OnProgressChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void UnsubscribeFromProgress()
|
||||
{
|
||||
if (_item.PostProcessor is RotateMatixFormCalibPostProcessor processor)
|
||||
{
|
||||
processor.ProgressChanged -= OnProgressChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProgressChanged(object sender, CalibrationProgressEventArgs e)
|
||||
{
|
||||
// 切换到 UI 线程更新
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
ProgressMessage = e.Message;
|
||||
ProgressCurrent = e.Current;
|
||||
ProgressTotal = e.Total;
|
||||
NotifyOfPropertyChange(nameof(ProgressPercentage));
|
||||
NotifyOfPropertyChange(nameof(ProgressText));
|
||||
});
|
||||
}
|
||||
|
||||
#region 对标 OriginCalibModuleViewModel 的通用方法
|
||||
|
||||
public void ResetModule()
|
||||
{
|
||||
IsCalibrated = false;
|
||||
IsWritten = false;
|
||||
NotifyOfPropertyChange(nameof(CanWriteToController));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 旋转表标定特有操作(原 ViewModel 按钮方法)
|
||||
|
||||
/// <summary>
|
||||
/// 原 btnMoveToPosPosition()
|
||||
/// 移动 X1 到避让位 + 移动 WS 到起始位置
|
||||
/// </summary>
|
||||
public void MoveToPosition()
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_motionService.SafeMove(_hardware.Axis_PHS_X1, X1AvoidancePosition);
|
||||
_motionService.MoveWsAvoidance(StartX, StartY);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MwMessageBox.Show($"移动失败:{ex.Message}", CalibrationDialogCaption,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 原 btnMoveToCenterPoint()
|
||||
/// 中心对齐,读取并设置 StartX, StartY
|
||||
/// </summary>
|
||||
public void MoveToCenterPoint()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
bool success = await FindPointCircleAsync(CancellationToken.None);
|
||||
if (success)
|
||||
{
|
||||
StartX = _hardware.Axis_PHS_X2.State.ActualPos;
|
||||
StartY = _hardware.Axis_PHS_Y1.State.ActualPos;
|
||||
MwMessageBox.Show($"对齐值,X2:{StartX},Y1:{StartY}");
|
||||
}
|
||||
else
|
||||
{
|
||||
MwMessageBox.Show("对齐失败!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MwMessageBox.Show($"异常:{ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 原 btnVerifyApproachCenter()
|
||||
/// 验证对齐
|
||||
/// </summary>
|
||||
public void VerifyApproachCenter()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
bool success = await FindPointCircleAsync(CancellationToken.None);
|
||||
if (success)
|
||||
{
|
||||
VerifyStartX = _hardware.Axis_PHS_X2.State.ActualPos;
|
||||
VerifyStartY = _hardware.Axis_PHS_Y1.State.ActualPos;
|
||||
MwMessageBox.Show($"对齐值,X2:{StartX},Y1:{StartY}");
|
||||
}
|
||||
else
|
||||
{
|
||||
MwMessageBox.Show("对齐失败!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MwMessageBox.Show($"异常:{ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 核心标定流程(对标 StartCalib)
|
||||
|
||||
/// <summary>
|
||||
/// 对标 OriginCalibModuleViewModel.StartCalib()
|
||||
/// 原 btnStart() + RotateFormCalibTask.RotateCalib() 的编排逻辑
|
||||
/// </summary>
|
||||
public async Task StartCalib()
|
||||
{
|
||||
if (IsCalibrating) return;
|
||||
IsCalibrating = true;
|
||||
IsProgressVisible = true; // 显示进度
|
||||
_cts = new CancellationTokenSource();
|
||||
|
||||
try
|
||||
{
|
||||
// 标定流程(原 RotateFormCalibTask.RotateCalib 的编排)
|
||||
if (_item.PostProcessor != null)
|
||||
{
|
||||
await ((RotateMatixFormCalibPostProcessor)_item.PostProcessor)
|
||||
.ExecuteAsync(null, _cts.Token);
|
||||
}
|
||||
IsWritten = false;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
MwMessageBox.Show("标定已取消。", CalibrationDialogCaption,
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MwMessageBox.Show($"标定失败:{ex.Message}", CalibrationDialogCaption,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsCalibrating = false;
|
||||
IsProgressVisible = false; // 隐藏进度
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 原 btnVerifyStart() + RotateFormCalibTask.RotateCalibVerify()
|
||||
/// </summary>
|
||||
public async Task StartVerify()
|
||||
{
|
||||
if (IsCalibrating) return;
|
||||
IsCalibrating = true;
|
||||
IsProgressVisible = true; // 显示进度
|
||||
_cts = new CancellationTokenSource();
|
||||
|
||||
try
|
||||
{
|
||||
if (_item.PostProcessor != null)
|
||||
{
|
||||
await ((RotateMatixFormCalibPostProcessor)_item.PostProcessor)
|
||||
.VerifyAsync(_cts.Token);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
MwMessageBox.Show("验证已取消。", CalibrationDialogCaption,
|
||||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MwMessageBox.Show($"验证失败:{ex.Message}", CalibrationDialogCaption,
|
||||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsCalibrating = false;
|
||||
IsProgressVisible = false; // 隐藏进度
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 原 btnStop() / btnVerifyStop()
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 私有辅助方法
|
||||
|
||||
/// <summary>
|
||||
/// 原 FindPointCircle()
|
||||
/// </summary>
|
||||
private async Task<bool> FindPointCircleAsync(CancellationToken token)
|
||||
{
|
||||
Rectangle1 roiRect = _roiRectProvider?.Invoke();
|
||||
var request = new ApproachAlignmentRequest(
|
||||
axes: new[]
|
||||
{
|
||||
new ApproachAlignmentAxis(GetAxisName(_hardware.Axis_X2), 0.005),
|
||||
new ApproachAlignmentAxis(GetAxisName(_hardware.Axis_Y1), 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;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user