399 lines
15 KiB
C#
399 lines
15 KiB
C#
|
|
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)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|