添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Common
|
||||
{
|
||||
public sealed class AlgorithmCalibExecutionResult
|
||||
{
|
||||
public AlgorithmCalibExecutionResult(IDictionary<string, double> actualPositions)
|
||||
{
|
||||
var positions = actualPositions ?? new Dictionary<string, double>(StringComparer.Ordinal);
|
||||
ActualPositions = new ReadOnlyDictionary<string, double>(
|
||||
new Dictionary<string, double>(positions, StringComparer.Ordinal));
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, double> ActualPositions { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// 进度事件参数
|
||||
/// </summary>
|
||||
public class CalibrationProgressEventArgs : EventArgs
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public int Current { get; set; }
|
||||
public int Total { get; set; }
|
||||
public double Percentage => Total > 0 ? (double)Current / Total * 100 : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// 对标 OriginCalib 的 ICalibrationPostProcessor
|
||||
/// 旋转表标定的后处理器:原 task/rotateformcalibtask 的逻辑搬入实现类
|
||||
/// </summary>
|
||||
public interface IAlgorithmCalibrationPostProcessor
|
||||
{
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 标定后处理(对标原 RotateFormCalibTask.RotateCalib)
|
||||
/// </summary>
|
||||
Task ExecuteAsync(AlgorithmCalibExecutionResult calibrationResult, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// 验证后处理(对标原 RotateFormCalibTask.RotateCalibVerify)
|
||||
/// </summary>
|
||||
Task VerifyAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Model
|
||||
{
|
||||
public class AlgorithmCalibModuleNames
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using MainShell.AlgorithmCalib.Common;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SemiPoint = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Model
|
||||
{
|
||||
public static class FusionCalibModuleNames
|
||||
{
|
||||
public const string DieFusion = "Die融合标定";
|
||||
public const string PadFusion = "Pad融合标定";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 融合标定模块参数
|
||||
/// Die和Pad共用,通过 IsWaferCalib 区分
|
||||
/// </summary>
|
||||
public class FusionCalibModuleItem
|
||||
{
|
||||
// ===== 通用属性 =====
|
||||
public string ModuleName { get; set; }
|
||||
public bool IsIndependent { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IAlgorithmCalibrationPostProcessor PostProcessor { get; set; }
|
||||
|
||||
// ===== 融合标定参数 =====
|
||||
public int Index { get; set; }
|
||||
public string Camera_ID { get; set; }
|
||||
public bool IsWaferCalib { get; set; } // true=Die(WS轴), false=Pad(PHS轴)
|
||||
|
||||
// 位置参数
|
||||
public double MoveAxisPos { get; set; } // 移动轴位置(Die=X1, Pad=Y1)
|
||||
public double ApproachXPos { get; set; } // 逼近X(Die=X2, Pad=X1)
|
||||
public double ApproachYPos { get; set; } // 逼近Y(Die=Y1, Pad=Y2)
|
||||
public double CameraAxisPos { get; set; } // 相机轴起始位置
|
||||
|
||||
// 标定范围参数
|
||||
public double StartX { get; set; } // 起始X
|
||||
public double StartY { get; set; } // 起始Y
|
||||
public double Step { get; set; } // 步进距离
|
||||
public int Count { get; set; } // 组数
|
||||
|
||||
// 网格参数
|
||||
public double CalibStep { get; set; } // 网格步长
|
||||
public int CalibCount { get; set; } // 网格行列数
|
||||
|
||||
// 模板路径
|
||||
public string ModelPath { get; set; } = "";
|
||||
|
||||
// ===== 验证参数 =====
|
||||
public double WaferStartVerifyX { get; set; } // 验证起点X(Die=X2, Pad=X1)
|
||||
public double WaferStartVerifyY { get; set; } // 验证起点Y(Die=Y1, Pad=Y2)
|
||||
public double WaferVerityStep { get; set; } // 验证步进
|
||||
public int WaferVerityCountX { get; set; } // 验证X方向数量
|
||||
public int WaferVerityCountY { get; set; } // 验证Y方向数量
|
||||
|
||||
// ===== 对位验证参数 =====
|
||||
// Die对位:飞拍die坐标
|
||||
public double DieRealX { get; set; } // die实际X(real坐标)
|
||||
public double DieRealY { get; set; } // die实际Y(real坐标)
|
||||
public double DieRulerX { get; set; } // die轴位置X(ruler坐标)
|
||||
public double DieRulerY { get; set; } // die轴位置Y(ruler坐标)
|
||||
|
||||
// Pad对位:飞拍pad坐标
|
||||
public double PadRealX { get; set; } // pad实际X(real坐标)
|
||||
public double PadRealY { get; set; } // pad实际Y(real坐标)
|
||||
public double PadRulerX { get; set; } // pad轴位置X(ruler坐标)
|
||||
public double PadRulerY { get; set; } // pad轴位置Y(ruler坐标)
|
||||
|
||||
// 对位结果
|
||||
public double AlignResultX { get; set; } // 对齐后X1偏移量
|
||||
public double AlignResultY { get; set; } // 对齐后Y1偏移量
|
||||
public double AlignResultX2 { get; set; } // X2补偿量
|
||||
|
||||
// ===== 运行时结果(不序列化) =====
|
||||
[JsonIgnore]
|
||||
public List<SemiPoint> RulerPoints { get; set; } = new List<SemiPoint>();
|
||||
[JsonIgnore]
|
||||
public List<SemiPoint> RealPoints { get; set; } = new List<SemiPoint>();
|
||||
// Die网格飞拍数据
|
||||
[JsonIgnore]
|
||||
public List<Tuple<int, int, SemiPoint>> DieGridPoints { get; set; } = new List<Tuple<int, int, SemiPoint>>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using MainShell.Filewritable;
|
||||
using MXJM.FileWritable;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Model
|
||||
{
|
||||
public class FusionCalibSetting : JsonFileWritableBase
|
||||
{
|
||||
[JsonIgnore]
|
||||
public override string Dir => Paths.CalibSettingPath;
|
||||
|
||||
[JsonIgnore]
|
||||
public override string FileName => "FusionCalibSetting.json";
|
||||
|
||||
// Pad融合的4组模块
|
||||
public List<FusionCalibModuleItem> PadModules { get; set; } = new List<FusionCalibModuleItem>();
|
||||
|
||||
// Die融合的参数(单组)
|
||||
public FusionCalibModuleItem DieModule { get; set; } = new FusionCalibModuleItem();
|
||||
|
||||
public static FusionCalibSetting LoadOrCreate()
|
||||
{
|
||||
var setting = new FusionCalibSetting();
|
||||
string path = Path.Combine(setting.Dir, setting.FileName);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
setting.Read(path);
|
||||
setting.EnsureCollections();
|
||||
return setting;
|
||||
}
|
||||
|
||||
setting.PadModules = CreateDefaultPadModules();
|
||||
setting.DieModule = CreateDefaultDieModule();
|
||||
setting.Write(path);
|
||||
return setting;
|
||||
}
|
||||
|
||||
public void EnsureCollections()
|
||||
{
|
||||
if (PadModules == null)
|
||||
PadModules = new List<FusionCalibModuleItem>();
|
||||
if (DieModule == null)
|
||||
DieModule = CreateDefaultDieModule();
|
||||
}
|
||||
|
||||
private static List<FusionCalibModuleItem> CreateDefaultPadModules()
|
||||
{
|
||||
var modules = new List<FusionCalibModuleItem>();
|
||||
for (int i = 1; i <= 4; i++)
|
||||
{
|
||||
modules.Add(new FusionCalibModuleItem
|
||||
{
|
||||
ModuleName = FusionCalibModuleNames.PadFusion,
|
||||
IsIndependent = true,
|
||||
Index = i,
|
||||
Camera_ID = $"Fusion_Time{i}",
|
||||
IsWaferCalib = false,
|
||||
CalibStep = 0.4,
|
||||
CalibCount = 10,
|
||||
Count = 4,
|
||||
Step = 5.0,
|
||||
});
|
||||
}
|
||||
return modules;
|
||||
}
|
||||
|
||||
private static FusionCalibModuleItem CreateDefaultDieModule()
|
||||
{
|
||||
return new FusionCalibModuleItem
|
||||
{
|
||||
ModuleName = FusionCalibModuleNames.DieFusion,
|
||||
IsIndependent = true,
|
||||
Index = 1,
|
||||
Camera_ID = "DieFusion",
|
||||
IsWaferCalib = true,
|
||||
CalibStep = 0.4,
|
||||
CalibCount = 10,
|
||||
Count = 4,
|
||||
Step = 5.0,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using MaxwellFramework.Core.Common;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.Controls.SystemCalib;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Model
|
||||
{
|
||||
|
||||
|
||||
public class FusionCalibParItem : ViewModelBase
|
||||
{
|
||||
private double _moveAxisPos = 0.0;
|
||||
public double MoveAxisPos
|
||||
{
|
||||
get { return _moveAxisPos; }
|
||||
set { if (_moveAxisPos != value) { _moveAxisPos = value; OnPropertyChanged(nameof(MoveAxisPos)); } }
|
||||
}
|
||||
|
||||
private double _approachXPos = 0.0;
|
||||
public double ApproachXPos
|
||||
{
|
||||
get { return _approachXPos; }
|
||||
set { if (_approachXPos != value) { _approachXPos = value; OnPropertyChanged(nameof(ApproachXPos)); } }
|
||||
}
|
||||
|
||||
private double _approachYPos = 0.0;
|
||||
public double ApproachYPos
|
||||
{
|
||||
get { return _approachYPos; }
|
||||
set { if (_approachYPos != value) { _approachYPos = value; OnPropertyChanged(nameof(ApproachYPos)); } }
|
||||
}
|
||||
|
||||
private double _cameraAxisPos = 0.0;
|
||||
public double CameraAxisPos
|
||||
{
|
||||
get { return _cameraAxisPos; }
|
||||
set { if (_cameraAxisPos != value) { _cameraAxisPos = value; OnPropertyChanged(nameof(CameraAxisPos)); } }
|
||||
}
|
||||
|
||||
private double _startX = 0.0;
|
||||
public double StartX
|
||||
{
|
||||
get { return _startX; }
|
||||
set { if (_startX != value) { _startX = value; OnPropertyChanged(nameof(StartX)); } }
|
||||
}
|
||||
|
||||
private double _startY = 0.0;
|
||||
public double StartY
|
||||
{
|
||||
get { return _startY; }
|
||||
set { if (_startY != value) { _startY = value; OnPropertyChanged(nameof(StartY)); } }
|
||||
}
|
||||
|
||||
private double _step = 0.0;
|
||||
public double Step
|
||||
{
|
||||
get { return _step; }
|
||||
set { if (_step != value) { _step = value; OnPropertyChanged(nameof(Step)); } }
|
||||
}
|
||||
|
||||
private int _count = 0;
|
||||
public int Count
|
||||
{
|
||||
get { return _count; }
|
||||
set { if (_count != value) { _count = value; OnPropertyChanged(nameof(Count)); } }
|
||||
}
|
||||
|
||||
private double _calibStep = 0.0;
|
||||
public double CalibStep
|
||||
{
|
||||
get { return _calibStep; }
|
||||
set { if (_calibStep != value) { _calibStep = value; OnPropertyChanged(nameof(CalibStep)); } }
|
||||
}
|
||||
|
||||
private int _calibCount = 0;
|
||||
public int CalibCount
|
||||
{
|
||||
get { return _calibCount; }
|
||||
set { if (_calibCount != value) { _calibCount = value; OnPropertyChanged(nameof(CalibCount)); } }
|
||||
}
|
||||
|
||||
private bool _isWaferCalib = false;
|
||||
public bool IsWaferCalib
|
||||
{
|
||||
get { return _isWaferCalib; }
|
||||
set { if (_isWaferCalib != value) { _isWaferCalib = value; OnPropertyChanged(nameof(_isWaferCalib)); } }
|
||||
}
|
||||
|
||||
private string _modelPath = "";
|
||||
public string ModelPath
|
||||
{
|
||||
get { return _modelPath; }
|
||||
set { if (_modelPath != value) { _modelPath = value; OnPropertyChanged(nameof(ModelPath)); } }
|
||||
}
|
||||
|
||||
private int _index = 0;
|
||||
public int Index
|
||||
{
|
||||
get { return _index; }
|
||||
set { if (_index != value) { _index = value; OnPropertyChanged(nameof(Index)); } }
|
||||
}
|
||||
|
||||
private string _camera_Id = string.Empty;
|
||||
public string Camera_ID
|
||||
{
|
||||
get { return _camera_Id; }
|
||||
set { if (_camera_Id != value) { _camera_Id = value; OnPropertyChanged(nameof(Camera_ID)); } }
|
||||
}
|
||||
|
||||
|
||||
private List<Point> _rulerPoints;
|
||||
public List<Point> RulerPoints
|
||||
{
|
||||
get { return _rulerPoints; }
|
||||
set { if (_rulerPoints != value) { _rulerPoints = value; OnPropertyChanged(nameof(RulerPoints)); } }
|
||||
}
|
||||
|
||||
private List<Point> _realPoints;
|
||||
public List<Point> RealPoints
|
||||
{
|
||||
get { return _realPoints; }
|
||||
set { if (_realPoints != value) { _realPoints = value; OnPropertyChanged(nameof(RealPoints)); } }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using MaxwellFramework.Core.Common;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Model
|
||||
{
|
||||
public class FusionCalibVerifyParItem: ViewModelBase
|
||||
{
|
||||
private double _moveAxisPos = 0.0;
|
||||
public double MoveAxisPos
|
||||
{
|
||||
get { return _moveAxisPos; }
|
||||
set { if (_moveAxisPos != value) { _moveAxisPos = value; OnPropertyChanged(nameof(MoveAxisPos)); } }
|
||||
}
|
||||
|
||||
private double _approachXPos = 0.0;
|
||||
public double ApproachXPos
|
||||
{
|
||||
get { return _approachXPos; }
|
||||
set { if (_approachXPos != value) { _approachXPos = value; OnPropertyChanged(nameof(ApproachXPos)); } }
|
||||
}
|
||||
|
||||
private double _approachYPos = 0.0;
|
||||
public double ApproachYPos
|
||||
{
|
||||
get { return _approachYPos; }
|
||||
set { if (_approachYPos != value) { _approachYPos = value; OnPropertyChanged(nameof(ApproachYPos)); } }
|
||||
}
|
||||
|
||||
private double _startX = 0.0;
|
||||
public double StartX
|
||||
{
|
||||
get { return _startX; }
|
||||
set { if (_startX != value) { _startX = value; OnPropertyChanged(nameof(StartX)); } }
|
||||
}
|
||||
|
||||
private double _startY = 0.0;
|
||||
public double StartY
|
||||
{
|
||||
get { return _startY; }
|
||||
set { if (_startY != value) { _startY = value; OnPropertyChanged(nameof(StartY)); } }
|
||||
}
|
||||
|
||||
private double _step = 0.0;
|
||||
public double Step
|
||||
{
|
||||
get { return _step; }
|
||||
set { if (_step != value) { _step = value; OnPropertyChanged(nameof(Step)); } }
|
||||
}
|
||||
|
||||
private int _countX = 0;
|
||||
public int CountX
|
||||
{
|
||||
get { return _countX; }
|
||||
set { if (_countX != value) { _countX = value; OnPropertyChanged(nameof(CountX)); } }
|
||||
}
|
||||
|
||||
private int _countY = 0;
|
||||
public int CountY
|
||||
{
|
||||
get { return _countY; }
|
||||
set { if (_countY != value) { _countY = value; OnPropertyChanged(nameof(CountY)); } }
|
||||
}
|
||||
|
||||
private string _modelPath = @"Parameters\SystemSetting\AxisAndWaferCaliModel";
|
||||
|
||||
public string ModelPath
|
||||
{
|
||||
get { return _modelPath; }
|
||||
set { if (_modelPath != value) { _modelPath = value; OnPropertyChanged(nameof(ModelPath)); } }
|
||||
}
|
||||
|
||||
private List<Point> _verifyRealPts = new List<Point>();
|
||||
public List<Point> VerifyRealPts
|
||||
{
|
||||
get { return _verifyRealPts; }
|
||||
set { if (_verifyRealPts != value) { _verifyRealPts = value; OnPropertyChanged(nameof(VerifyRealPts)); } }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using MaxwellFramework.Core.Common;
|
||||
using MwFramework.Controls.SystemCalib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Model
|
||||
{
|
||||
public class RotateCalibParItem: ViewModelBase
|
||||
{
|
||||
private string _modelPath = @"Parameters\SystemSetting\AxisAndWaferCaliModel";
|
||||
public string ModelPath
|
||||
{
|
||||
get { return _modelPath; }
|
||||
set { if (_modelPath != value) { _modelPath = value; OnPropertyChanged(nameof(ModelPath)); } }
|
||||
}
|
||||
private double _x1 = 0.0;
|
||||
public double X1
|
||||
{
|
||||
get { return _x1; }
|
||||
set { if (_x1 != value) { _x1 = value; OnPropertyChanged(nameof(X1)); } }
|
||||
}
|
||||
|
||||
private double _start_X = 0.0;
|
||||
public double Start_X
|
||||
{
|
||||
get { return _start_X; }
|
||||
set { if (_start_X != value) { _start_X = value; OnPropertyChanged(nameof(Start_X)); } }
|
||||
}
|
||||
|
||||
private double _start_Y = 0.0;
|
||||
public double Start_Y
|
||||
{
|
||||
get { return _start_Y; }
|
||||
set { if (_start_Y != value) { _start_Y = value; OnPropertyChanged(nameof(Start_Y)); } }
|
||||
}
|
||||
|
||||
private double _verifyStartX = 0.0;
|
||||
public double VerifyStartX
|
||||
{
|
||||
get { return _verifyStartX; }
|
||||
set { if (_verifyStartX != value) { _verifyStartX = value; OnPropertyChanged(nameof(VerifyStartX)); } }
|
||||
}
|
||||
|
||||
private double _verifyStartY = 0.0;
|
||||
public double VerifyStartY
|
||||
{
|
||||
get { return _verifyStartY; }
|
||||
set { if (_verifyStartY != value) { _verifyStartY = value; OnPropertyChanged(nameof(VerifyStartY)); } }
|
||||
}
|
||||
|
||||
private int _rowCol = 0;
|
||||
public int RowCol
|
||||
{
|
||||
get { return _rowCol; }
|
||||
set { if (_rowCol != value) { _rowCol = value; OnPropertyChanged(nameof(RowCol)); } }
|
||||
}
|
||||
|
||||
private int _verifyRowCol = 0;
|
||||
public int VerifyRowCol
|
||||
{
|
||||
get { return _verifyRowCol; }
|
||||
set { if (_verifyRowCol != value) { _verifyRowCol = value; OnPropertyChanged(nameof(VerifyRowCol)); } }
|
||||
}
|
||||
|
||||
private double _wafer_Step = 0.0;
|
||||
public double Wafer_Step
|
||||
{
|
||||
get { return _wafer_Step; }
|
||||
set { if (_wafer_Step != value) { _wafer_Step = value; OnPropertyChanged(nameof(Wafer_Step)); } }
|
||||
}
|
||||
|
||||
private double _verifyWaferStep = 0.0;
|
||||
public double VerifyWaferStep
|
||||
{
|
||||
get { return _verifyWaferStep; }
|
||||
set { if (_verifyWaferStep != value) { _verifyWaferStep = value; OnPropertyChanged(nameof(VerifyWaferStep)); } }
|
||||
}
|
||||
|
||||
private double _rotate_Step = 0.0;
|
||||
public double Rotate_Step
|
||||
{
|
||||
get { return _rotate_Step; }
|
||||
set { if (_rotate_Step != value) { _rotate_Step = value; OnPropertyChanged(nameof(Rotate_Step)); } }
|
||||
}
|
||||
|
||||
private double _verifyRotateRange = 0.0;
|
||||
public double VerifyRotateRange
|
||||
{
|
||||
get { return _verifyRotateRange; }
|
||||
set { if (_verifyRotateRange != value) { _verifyRotateRange = value; OnPropertyChanged(nameof(VerifyRotateRange)); } }
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using MainShell.AlgorithmCalib.Common;
|
||||
using MainShell.Filewritable;
|
||||
using MainShell.PageCalib.OriginCalib.Service;
|
||||
using MXJM.FileWritable;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Model
|
||||
{
|
||||
public static class RotateMatixFormCalibModuleNames
|
||||
{
|
||||
public const string RotateForm = "旋转表标定模块";
|
||||
}
|
||||
|
||||
public class RotateMatixFormCalibModuleItem
|
||||
{
|
||||
// ===== 对标 OriginCalibModuleItem 通用属性 =====
|
||||
public string ModuleName { get; set; }
|
||||
public bool IsIndependent { get; set; }
|
||||
public string TemplatePath { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public IAlgorithmCalibrationPostProcessor PostProcessor { get; set; }
|
||||
|
||||
// ===== 旋转表特有参数(原 RotateCalibParItem) =====
|
||||
public double X1AvoidancePosition { get; set; }
|
||||
public double RotateStep { get; set; }
|
||||
public double WaferStep { get; set; }
|
||||
public int RowCol { get; set; }
|
||||
|
||||
// ===== 验证参数 =====
|
||||
public int VerifyRowCol { get; set; }
|
||||
public double VerifyWaferStep { get; set; }
|
||||
public double VerifyRotateRange { get; set; }
|
||||
|
||||
// ===== 运行时参数(不序列化) =====
|
||||
[JsonIgnore]
|
||||
public double StartX { get; set; }
|
||||
[JsonIgnore]
|
||||
public double StartY { get; set; }
|
||||
[JsonIgnore]
|
||||
public double VerifyStartX { get; set; }
|
||||
[JsonIgnore]
|
||||
public double VerifyStartY { get; set; }
|
||||
|
||||
//逼近容差
|
||||
public double AlignTolerance { get; set; } = 0.005;
|
||||
}
|
||||
|
||||
public class RotateMatixFormCalibSetting : JsonFileWritableBase
|
||||
{
|
||||
[JsonIgnore]
|
||||
public override string Dir => Paths.CalibSettingPath;
|
||||
|
||||
[JsonIgnore]
|
||||
public override string FileName => "RotateFormCalibSetting.json";
|
||||
|
||||
public List<RotateMatixFormCalibModuleItem> Modules { get; set; } = new List<RotateMatixFormCalibModuleItem>();
|
||||
|
||||
public static RotateMatixFormCalibSetting LoadOrCreate()
|
||||
{
|
||||
// TODO: 对标 OriginCalibSetting.LoadOrCreate()
|
||||
var setting = new RotateMatixFormCalibSetting();
|
||||
string path = Path.Combine(setting.Dir, setting.FileName);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
setting.Read(path);
|
||||
setting.EnsureCollections();
|
||||
return setting;
|
||||
}
|
||||
|
||||
setting.Modules = CreateDefaultModules();
|
||||
setting.Write(path);
|
||||
return setting;
|
||||
}
|
||||
|
||||
public void EnsureCollections()
|
||||
{
|
||||
// TODO: 对标 OriginCalibSetting.EnsureCollections()
|
||||
if (Modules == null)
|
||||
Modules = new List<RotateMatixFormCalibModuleItem>();
|
||||
|
||||
}
|
||||
|
||||
private static List<RotateMatixFormCalibModuleItem> CreateDefaultModules()
|
||||
{
|
||||
// TODO: 原 RotateCalibParItem 的默认值搬到这里
|
||||
return new List<RotateMatixFormCalibModuleItem>
|
||||
{
|
||||
new RotateMatixFormCalibModuleItem
|
||||
{
|
||||
ModuleName = RotateMatixFormCalibModuleNames.RotateForm,
|
||||
IsIndependent = true,
|
||||
TemplatePath = "",
|
||||
RotateStep = 0.05,
|
||||
WaferStep = 0.4,
|
||||
RowCol = 10,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,480 @@
|
||||
<UserControl x:Class="MXJM.SystemSetting.View.CameraFusionCali02AView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mwControls="http://www.maxwell-gp.com/"
|
||||
Loaded="{mwControls:Action viewLoad}"
|
||||
Unloaded="{mwControls:Action viewUnLoad}"
|
||||
xmlns:view="clr-namespace:MXJM.Common.View"
|
||||
xmlns:local="clr-namespace:MXJM.SystemSetting.View"
|
||||
xmlns:testdemo="clr-namespace:MwFramework.Controls.SystemCalib;assembly=MwFramework.Controls.SystemCalib"
|
||||
mwControls:ParameterAttach.DelayAcceptValue ="{Binding ParameterHelper}"
|
||||
xmlns:convert="clr-namespace:MXJM.Common.Converter"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="850" d:DesignWidth="1200">
|
||||
<UserControl.Resources>
|
||||
<convert:CameraTypeToBoolConverter x:Key="CameraTypeToBoolConverter"/>
|
||||
<Style x:Key="CommonLableStyle" TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="120"/>
|
||||
</Style>
|
||||
<Style TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="120"/>
|
||||
</Style>
|
||||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" >
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="110"/>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
<Grid >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<view:CameraAxisView DataContext="{Binding }" IsEnabled="{Binding Motion.IsFinish}"/>
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="60"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TabControl mwControls:TabControlAttach.FontSize="12" mwControls:TabControlAttach.HeaderHeight="30" mwControls:TabControlAttach.HeaderWidth="120" Margin="5,0,0,0" >
|
||||
<TabItem Header="相机晶圆伺服融合">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<GroupBox Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="WS运动系标定位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Grid.Row="0" Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="140"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<!--<ColumnDefinition/>-->
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="WS平台标定X1(mm):" Width="200" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Tag="WS平台标定X1" Value="{Binding CameraWaferFusionCalibrationItem.WSPlatCalibXPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<!--<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WSApproachXPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="2" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WSApproachYPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />-->
|
||||
<Button Grid.Column="3" Tag="WS平台标定X1-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMoveWSCalibPosPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1.6*"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="1.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="X2:" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WSApproachXPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Label Content="Y2:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WSApproachYPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Button Grid.Column="5" Tag="WS平台标定X1-中心对齐" Content="中心对齐" Click="{mwControls:Action btnGotoCalibPos}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="1" Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="相机起始位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Grid.Row="0" Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="CameraX(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Center" />
|
||||
<mwControls:NumberBox Tag="CameraX" Value="{Binding CameraWaferFusionCalibrationItem.CameraX}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Center" Margin="5" Width="120" Height="35" />
|
||||
<!--<Label Content="CameraY(mm):" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.CameraY}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />-->
|
||||
<Button Grid.Column="3" Tag="计算相机起始位置" Content="计算位置" Click="{mwControls:Action BtnCalculateCameraPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="1" Tag="相机起始位置-读取当前位置" Content="读取当前位置" Click="{mwControls:Action btnSetCameraPosition}" HorizontalAlignment="Left" />
|
||||
<Button Grid.Column="3" Tag="相机起始位置-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMoveCameraPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="2" Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="WS起始位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="StartX(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WaferStartX}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="StartY(mm):" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WaferStartY}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0" Tag="WS起始位置-计算当前位置" Content="计算位置" Click="{mwControls:Action BtnCalculateWSPosition}" HorizontalAlignment="Left" Grid.ColumnSpan="2" Margin="3,0,0,0" />
|
||||
<Button Grid.Column="1" Tag="WS起始位置-读取当前位置" Content="读取当前位置" Click="{mwControls:Action btnSetWaferStartPosition}" HorizontalAlignment="Left" Grid.ColumnSpan="2" Margin="3,0,0,0" />
|
||||
<Button Grid.Column="2" Tag="WS起始位置-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMoveWaferStartPosition}" HorizontalAlignment="Left" Margin="2,0,0,0" />
|
||||
<Button Grid.Column="3" Tag="WS起始位置-对齐中心" Content="对齐中心" Click="{mwControls:Action btnMoveToCenter}" HorizontalAlignment="Left" Margin="3,0,0,0" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="4" Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="标定参数" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<Grid >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!--<DataGrid Grid.Row="0" ItemsSource="{Binding CameraWaferFusionCalibrationItem.AxisAndPixelPointItemList}" SelectedItem="CameraWaferFusionCalibrationItem.SelectedAxisAndPixelPointItem" Margin="3" AutoGenerateColumns="false" SelectionMode="Single"
|
||||
CanUserSortColumns="False">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="No" Binding="{Binding Id}" Width="1*" IsReadOnly="true"/>
|
||||
<DataGridTextColumn Header="AxisX1" Binding="{Binding AxisX1}" Width="2*" IsReadOnly="true"/>
|
||||
<DataGridTextColumn Header="AxisY1" Binding="{Binding AxisY1}" Width="2*" IsReadOnly="true"/>
|
||||
<DataGridTextColumn Header="AxisX2" Binding="{Binding AxisX2}" Width="2*" IsReadOnly="true"/>
|
||||
<DataGridTextColumn Header="AxisY2" Binding="{Binding AxisY2}" Width="2*" IsReadOnly="true"/>
|
||||
<DataGridTextColumn Header="RecognizeX" Binding="{Binding PixelX}" Width="2*" IsReadOnly="true"/>
|
||||
<DataGridTextColumn Header="RecognizeY" Binding="{Binding PixelY}" Width="2*" IsReadOnly="true"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>-->
|
||||
<Grid Grid.Row="1" IsEnabled="{Binding Motion.IsFinish}" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="WaferStepXY(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WaferStepXY}" Tag="WaferStepXY(mm)" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="0" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="WaferCountXY:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Value="{Binding CameraWaferFusionCalibrationItem.WaferCountXY}" Tag="WaferCountXY" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="0" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid IsEnabled="{Binding Motion.IsFinish}" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="StepX1(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Tag="StepX(mm)" Value="{Binding CameraWaferFusionCalibrationItem.StepX}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<!--<Label Content="StepY(mm):" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.StepY}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />-->
|
||||
<Label Content="CountX1:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Tag="CountX" Value="{Binding CameraWaferFusionCalibrationItem.CountX}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="1" Maximum="10000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!--<Button Grid.Column="0" Content="移到此位置" Click="{mwControls:Action btnMovePosition}" HorizontalAlignment="Left" />
|
||||
<Button Grid.Column="1" Content="识别" Click="{mwControls:Action btnRecognize}" HorizontalAlignment="Left" />-->
|
||||
|
||||
<!--<Button Content="计算" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnFix}" Grid.Column="0" />-->
|
||||
<!--<Button Content="验证" Click="{mwControls:Action btnVarify}" Grid.Column="1" />-->
|
||||
<CheckBox x:Name="circleCk" Content="圆形标定" IsChecked="{Binding CameraWaferFusionCalibrationItem.UseCircleCalib}" />
|
||||
<Button Content="开始" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnStart}" Grid.Column="2" IsEnabled="{Binding Motion.IsFinish}" />
|
||||
<Button Content="停止" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnStop}" Grid.Column="3" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="3" Visibility="{Binding ElementName=circleCk, Path=IsChecked, Converter={StaticResource boolToVisibleConverter}}" Style="{StaticResource GroupBoxSecondary}" IsEnabled="{Binding Motion.IsFinish}" Margin="3" Header="圆参数示教">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<UniformGrid Columns="4">
|
||||
<!--<Label Margin="2,2" VerticalAlignment="Center" HorizontalAlignment="Center" Content="圆心X:"/>
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.CenterX}" Margin="2,2" HorizontalAlignment="Left" IsReadOnly="True"/>
|
||||
<Label Margin="2,2" VerticalAlignment="Center" HorizontalAlignment="Center" Content="圆心Y:"/>
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.CenterY}" Margin="2,2" HorizontalAlignment="Left" IsReadOnly="True"/>-->
|
||||
<Label Margin="2,2" VerticalAlignment="Center" HorizontalAlignment="Center" Content="半径:"/>
|
||||
<mwControls:NumberBox mwControls:NumericKeypadAttach.IsEnabled="True" Value="{Binding CameraWaferFusionCalibrationItem.Radius}" Margin="2,2" HorizontalAlignment="Left" IsReadOnly="False"/>
|
||||
<Label Margin="2,2" VerticalAlignment="Center" HorizontalAlignment="Center" Content="标定板行间距:"/>
|
||||
<mwControls:NumberBox mwControls:NumericKeypadAttach.IsEnabled="True" Value="{Binding CameraWaferFusionCalibrationItem.RowStep}" Margin="2,2" HorizontalAlignment="Left" IsReadOnly="False"/>
|
||||
<Label Margin="2,2" VerticalAlignment="Center" HorizontalAlignment="Center" Content="标定板列间距:"/>
|
||||
<mwControls:NumberBox mwControls:NumericKeypadAttach.IsEnabled="True" Value="{Binding CameraWaferFusionCalibrationItem.ColStep}" Margin="2,2" HorizontalAlignment="Left" IsReadOnly="False"/>
|
||||
<!--<Button Margin="2,2" Content="示教" Click="{mwControls:Action TeachCircleCenter}"/>
|
||||
<Button Margin="2,2" Content="导入圆坐标" Click="{mwControls:Action ImportCircleFile}"/>-->
|
||||
</UniformGrid>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="验证" >
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="80"/>
|
||||
<RowDefinition Height="80"/>
|
||||
<RowDefinition Height="140"/>
|
||||
<RowDefinition Height="190"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<GroupBox Style="{StaticResource GroupBoxSecondary}" Margin="3" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="第一步:设定Die位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="1">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<!--<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>-->
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0" Visibility="Collapsed" Content="移到相机位置" Click="{mwControls:Action btnMoveCameraPosition}" HorizontalAlignment="Left" />
|
||||
<Button Grid.Column="1" Visibility="Collapsed" Content="移到Wafer位置" Click="{mwControls:Action btnMoveWaferStartPosition}" HorizontalAlignment="Left" />
|
||||
<Button Grid.Column="0" Content="设定Die位置" Click="{mwControls:Action btnSetDiePosition}" HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="1" Style="{StaticResource GroupBoxSecondary}" Margin="3" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="第二步:设定Pad位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="1">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<!--<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>-->
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0" Content="设定Pad位置" Click="{mwControls:Action btnSetPadPosition}" HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="2" Style="{StaticResource GroupBoxSecondary}" Margin="3" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="第三步:计算Wafer移动坐标" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="X,Y(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WaferVerifyX}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<mwControls:NumberBox Value="{Binding WaferVerifyY}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="2" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Button Grid.Column="3" Content="计算" Click="{mwControls:Action btnCalculate}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="3" Content="移动到验证点" Click="{mwControls:Action btnMoveToVerifyPoint}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="3" Style="{StaticResource GroupBoxSecondary}" Margin="3" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="相机畸变测试" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="3" Columns="4">
|
||||
<Label Content="RealX,Y(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding DesPixelX}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" DecimalPlaces="6" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<mwControls:NumberBox Value="{Binding DesPixelY}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" DecimalPlaces="6" Grid.Column="2" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Button Grid.Column="3" Content="识别" Click="{mwControls:Action btnCameraTest}" HorizontalAlignment="Left" />
|
||||
<Label Content="RulerX,Y(mm):" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding DesRulerX}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" DecimalPlaces="6" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<mwControls:NumberBox Value="{Binding DesRulerY}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" DecimalPlaces="6" Grid.Column="2" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label/>
|
||||
<RadioButton Content="定位相机" Margin="10,0,0,0" IsChecked="{Binding CameraTypeVM, Converter={StaticResource CameraTypeToBoolConverter}, ConverterParameter=1}" GroupName="cameraType"/>
|
||||
<RadioButton Content="虚拟定位相机" Margin="10,0,0,0" IsChecked="{Binding CameraTypeVM, Converter={StaticResource CameraTypeToBoolConverter}, ConverterParameter=2}" GroupName="cameraType"/>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="验证1" >
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<GroupBox Style="{StaticResource GroupBoxSecondary}" Margin="3" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="WS运动系标定位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Grid.Row="0" Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<!--<ColumnDefinition/>-->
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="WS平台标定X1,X2,Y2(mm):" Width="200" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WSPlatCalibXPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
<!--<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WSApproachXPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="2" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WSApproachYPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />-->
|
||||
<Button Grid.Column="2" Content="移到此位置" Click="{mwControls:Action btnMoveWSCalibPosPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid Visibility="Collapsed">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="X:" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WSApproachXPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
<Label Content="Y:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WSApproachYPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="80" Height="35" />
|
||||
<Button Grid.Column="5" Content="中心对齐" Click="{mwControls:Action btnGotoCalibPos}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="2" Style="{StaticResource GroupBoxSecondary}" Margin="3" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="WS运动位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="5" Columns="1">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="StartX(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WaferStartVerifyX}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="StartY(mm):" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WaferStartVerifyY}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!--<Button Grid.Column="1" Content="读取当前位置" Click="{mwControls:Action btnSetWaferStartPosition}" HorizontalAlignment="Left" />-->
|
||||
<Button Grid.Column="3" Content="设置起点" Click="{mwControls:Action btnMoveToCenter}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="Step(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.WaferVerityStep}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Button Grid.Column="3" Content="移动到起点" Click="{mwControls:Action btnMoveToStartPoint}" HorizontalAlignment="Left" />
|
||||
<!--<Label Content="StepY(mm):" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding CameraWaferFusionCalibrationItem.StepY}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />-->
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="CountX:" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Value="{Binding CameraWaferFusionCalibrationItem.WaferVerityCountX}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="CountY:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Value="{Binding CameraWaferFusionCalibrationItem.WaferVerityCountY}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button Content="开始飞拍" Click="{mwControls:Action btnMoveWafer}" Grid.Column="0" Margin="10 5" IsEnabled="{Binding Motion.IsFinish}" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button Content="以当前相机位置验证" Click="{mwControls:Action btnVerityWafer}" Margin="10 5" IsEnabled="{Binding Motion.IsFinish}" Width="150"/>
|
||||
<Button Content="停止" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnStopVerityWafer}" HorizontalAlignment="Right"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="轴系精度验证">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<view:AxisPrecisionCheckParamView Grid.Row="0" AxisPrecisionCheck="{Binding AxisCheckItem.PHSPerpendicularityCheck}"/>
|
||||
<GroupBox Grid.Row="1" Header="WS轴精度验证">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Button Content="X1移动到标定位置" Tag="X1移动到标定位置" Click="{mwControls:Action BtnMoveX1ToCalibPos}"></Button>
|
||||
<view:AxisPrecisionCheckParamView Grid.Row="2" AxisPrecisionCheck="{Binding AxisCheckItem.WSPerpendicularityCheck}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<view:AxisPrecisionCheckParamView Grid.Row="2" AxisPrecisionCheck="{Binding AxisCheckItem.X1X2ParallelismCheck}"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
<Grid Grid.Row="1">
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" >
|
||||
<Button Content="保存" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnSave}" Grid.Row="1" Grid.Column="4" Margin="10 5" IsEnabled="{Binding Motion.IsFinish}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,404 @@
|
||||
using JM1.JM1Params;
|
||||
using Maxwell.SemiFramework.DefaultConfig.Vision;
|
||||
using MaxwellControl.Controls;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MaxWellGeneralLog.Extension;
|
||||
using MwFramework.Controls.Components;
|
||||
using MwFramework.Device;
|
||||
using MwFramework.ManagerService;
|
||||
using MwFramework.MXJM.ProcessAnalysis.Model;
|
||||
using MXJM.Common;
|
||||
using MXJM.Common.EventArgsFolder;
|
||||
using MXJM.Logic.Operation;
|
||||
using MXJM.Parameter.SystemSetting;
|
||||
using MXJM.SystemSetting.ViewModel;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using Stylet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
using MessageBox = MaxwellControl.Controls.MessageBox;
|
||||
using Point = System.Windows.Point;
|
||||
|
||||
namespace MXJM.Logic.SystemSetting
|
||||
{
|
||||
public class CameraFusionCalibrationMotion02A : DelegateBase
|
||||
{
|
||||
public override bool Check(object state)
|
||||
{
|
||||
IoC.Get<IProjectManager>().EnablePageAndDisableOther("视觉标定");
|
||||
_device = IoC.Get<GlobalDeviceService>();
|
||||
double speed = 50;
|
||||
SafeAxisMotion.SetAxisSpeed(_device.Axis_X11, speed);
|
||||
SafeAxisMotion.SetAxisSpeed(_device.Axis_Y11, speed);
|
||||
SafeAxisMotion.SetAxisSpeed(_device.Axis_X21, speed);
|
||||
SafeAxisMotion.SetAxisSpeed(_device.Axis_Y21, speed);
|
||||
return true;
|
||||
}
|
||||
|
||||
IParamList _paramList;
|
||||
GlobalDeviceService _device;
|
||||
VisionOperation _visionOperation;
|
||||
CameraWaferFusionCalibrationSetting _parameter;
|
||||
CameraWaferFusionCalibrationItem _cameraWaferFusionCalibrationItem;
|
||||
public Rectangle1 Rectangle { get; set; }
|
||||
bool _isCancle = false;
|
||||
|
||||
private Dictionary<int, SemiconductorVisionAlgorithm.SemiParams.Point[,]> _calibWaferData = new Dictionary<int, SemiconductorVisionAlgorithm.SemiParams.Point[,]>();
|
||||
private List<double> _x11PosList = new List<double>();
|
||||
private SemiconductorVisionAlgorithm.SemiParams.Point[,] _initialwsPos = new SemiconductorVisionAlgorithm.SemiParams.Point[0,0];
|
||||
SafeAxisMotion motion;
|
||||
|
||||
private int _x11Count = 0;
|
||||
private bool _isReDo = false;
|
||||
|
||||
public override void Do(object state)
|
||||
{
|
||||
try
|
||||
{
|
||||
_isCancle = false;
|
||||
if (_isReDo)
|
||||
{
|
||||
_isReDo = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_calibWaferData.Clear();
|
||||
_x11PosList.Clear();
|
||||
}
|
||||
var objects=state as object[];
|
||||
var pointDic = objects[1] as FusionPoint[,];
|
||||
|
||||
bool isRecheck = Convert.ToBoolean(objects[0]);
|
||||
_paramList = IoC.Get<IParameterManager>() as IParamList;
|
||||
_parameter = _paramList.GetParameter<CameraWaferFusionCalibrationSetting>();
|
||||
_cameraWaferFusionCalibrationItem = _parameter.CameraWaferFusionCalibrationItem;
|
||||
|
||||
motion = IoC.Get<SafeAxisMotion>();
|
||||
_device = IoC.Get<GlobalDeviceService>();
|
||||
_visionOperation = IoC.Get<VisionOperation>();
|
||||
double stageY = _device.Axis_Y11.State.ActualPos;
|
||||
double waferStep = _cameraWaferFusionCalibrationItem.WaferStepXY;
|
||||
string modelFileName = _cameraWaferFusionCalibrationItem.ModelPath;
|
||||
string path = System.AppDomain.CurrentDomain.BaseDirectory + modelFileName;
|
||||
|
||||
if (_x11PosList.Count != _cameraWaferFusionCalibrationItem.CountX || _calibWaferData.Count != _cameraWaferFusionCalibrationItem.CountX)
|
||||
{
|
||||
_calibWaferData.Clear();
|
||||
_x11PosList.Clear();
|
||||
_x11Count = 0;
|
||||
for (int i = 0; i < _cameraWaferFusionCalibrationItem.CountX; i++)
|
||||
{
|
||||
_x11PosList.Add(0);
|
||||
_calibWaferData.Add(i, new SemiconductorVisionAlgorithm.SemiParams.Point[0, 0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//相机移到起点 //wafer移到起点
|
||||
//motion.SafeMovePHSAndWS(_cameraWaferFusionCalibrationItem.CameraX, stageY, _cameraWaferFusionCalibrationItem.WaferStartX, _cameraWaferFusionCalibrationItem.WaferStartY, isCalib: true);
|
||||
if(_cameraWaferFusionCalibrationItem.UseCircleCalib)
|
||||
{
|
||||
_initialwsPos = ApprochWSCircleTable(pointDic, _cameraWaferFusionCalibrationItem.WSPlatCalibXPos, stageY, _cameraWaferFusionCalibrationItem.WSApproachXPos,
|
||||
_cameraWaferFusionCalibrationItem.WSApproachYPos, 0, path);
|
||||
}
|
||||
else
|
||||
_initialwsPos = ApprochWSTable(waferStep, _cameraWaferFusionCalibrationItem.WSPlatCalibXPos, stageY, _cameraWaferFusionCalibrationItem.WSApproachXPos,
|
||||
_cameraWaferFusionCalibrationItem.WSApproachYPos, 0, path);
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = _x11Count; i < _cameraWaferFusionCalibrationItem.CountX; i++)
|
||||
{
|
||||
if (_isCancle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
|
||||
double x1 = _cameraWaferFusionCalibrationItem.CameraX + _cameraWaferFusionCalibrationItem.StepX * i;
|
||||
double y1 = _device.Axis_Y11.State.ActualPos;
|
||||
|
||||
double x2 = _cameraWaferFusionCalibrationItem.WaferStartX + _cameraWaferFusionCalibrationItem.StepX * i;
|
||||
double y2 = _cameraWaferFusionCalibrationItem.WaferStartY;
|
||||
|
||||
|
||||
//如果是检查 ,X1=1/2 * StepX Y1是stage的那个黑色平台 Y2是ws
|
||||
if (isRecheck)
|
||||
{
|
||||
x1 = _cameraWaferFusionCalibrationItem.CameraX - 0.5 * _cameraWaferFusionCalibrationItem.StepX + _cameraWaferFusionCalibrationItem.StepX * i;
|
||||
y1 = _device.Axis_Y11.State.ActualPos;
|
||||
x2 = _cameraWaferFusionCalibrationItem.WaferStartX - 0.5 * _cameraWaferFusionCalibrationItem.StepX + _cameraWaferFusionCalibrationItem.StepX * i;
|
||||
y2 = _cameraWaferFusionCalibrationItem.WaferStartY;
|
||||
}
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point[,] points = null;
|
||||
if (_cameraWaferFusionCalibrationItem.UseCircleCalib)
|
||||
{
|
||||
points = ApprochWSCircleTable(pointDic, x1, y1, x2, y2, count, path);
|
||||
}
|
||||
else
|
||||
points = ApprochWSTable(waferStep, x1, y1, x2, y2, count, path);
|
||||
if (_calibWaferData.ContainsKey(i))
|
||||
{
|
||||
_calibWaferData[i] = points;
|
||||
}
|
||||
else
|
||||
{
|
||||
_calibWaferData.Add(i, points);
|
||||
}
|
||||
|
||||
_x11PosList[i] = _device.Axis_X11.State.ActualPos;
|
||||
}
|
||||
|
||||
//当count为1时,认为是老标定
|
||||
if (_cameraWaferFusionCalibrationItem.WaferCountXY == 1)
|
||||
{
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point ini_wsPos = new SemiconductorVisionAlgorithm.SemiParams.Point(_cameraWaferFusionCalibrationItem.WSApproachXPos,
|
||||
_cameraWaferFusionCalibrationItem.WSApproachYPos);
|
||||
List<SemiconductorVisionAlgorithm.SemiParams.Point> wsList = new List<SemiconductorVisionAlgorithm.SemiParams.Point>();
|
||||
_calibWaferData.ForEach(p =>
|
||||
{
|
||||
if (p.Value.Length > 0)
|
||||
{
|
||||
wsList.Add(p.Value[0, 0]);
|
||||
}
|
||||
});
|
||||
//JM1Vision.JM1Manager.Instance.cal_interpolate_affine(_cameraWaferFusionCalibrationItem.WSPlatCalibXPos, ini_wsPos,
|
||||
// _x11PosList, wsList);
|
||||
}
|
||||
else
|
||||
{
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point[,] _circleInitialwsPos = new SemiconductorVisionAlgorithm.SemiParams.Point[0, 0];
|
||||
Dictionary<int, SemiconductorVisionAlgorithm.SemiParams.Point[,]> _circleCalibData = new Dictionary<int, SemiconductorVisionAlgorithm.SemiParams.Point[,]>(_calibWaferData.Count);
|
||||
if (_cameraWaferFusionCalibrationItem.UseCircleCalib)
|
||||
{
|
||||
ConvertToRecheckDiePoint(ref _initialwsPos);
|
||||
|
||||
foreach (var item in _calibWaferData)
|
||||
{
|
||||
var rows=item.Value.GetLength(0);
|
||||
var cols=item.Value.GetLength(1);
|
||||
RecheckDiePoint[,] recheckDiePoint = new RecheckDiePoint[rows, cols];
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
for (int j = 0; j < cols; j++)
|
||||
{
|
||||
var point=item.Value[i, j];
|
||||
bool isexist = !(point.X == 0 && point.Y == 0);
|
||||
var recheckPoint = new RecheckDiePoint
|
||||
{
|
||||
X = point.X,
|
||||
Y = point.Y,
|
||||
State = isexist
|
||||
};
|
||||
recheckDiePoint[i,j]= recheckPoint;
|
||||
}
|
||||
}
|
||||
JM1Vision.JM1Manager.Instance.FillCalibData(recheckDiePoint, _cameraWaferFusionCalibrationItem.WaferStepXY,
|
||||
_cameraWaferFusionCalibrationItem.WaferCountXY,out RecheckDiePoint[,] resutPoint);
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point[,] finalResultPoint = new SemiconductorVisionAlgorithm.SemiParams.Point[rows, cols];
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
for (int j = 0; j < cols; j++)
|
||||
{
|
||||
var point = resutPoint[i, j];
|
||||
|
||||
finalResultPoint[i, j] = new SemiconductorVisionAlgorithm.SemiParams.Point
|
||||
{
|
||||
X = point.X,
|
||||
Y = point.Y,
|
||||
};
|
||||
}
|
||||
}
|
||||
_circleCalibData[item.Key] = finalResultPoint;
|
||||
}
|
||||
_calibWaferData= _circleCalibData;
|
||||
|
||||
}
|
||||
|
||||
JM1Vision.JM1Manager.Instance.cal_wafer_fusion(_calibWaferData, _x11PosList, _initialwsPos, _cameraWaferFusionCalibrationItem.StepX, waferStep, _cameraWaferFusionCalibrationItem.WaferCountXY);
|
||||
}
|
||||
|
||||
|
||||
string filePath = System.AppDomain.CurrentDomain.BaseDirectory + @"CalibData";
|
||||
JM1Vision.JM1Manager.Instance.Save(filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
if (MessageBox.Show("是否继续!", null, "是否继续", MessageBoxButton.OKCancel, MessageBoxImage.Question, MessageBoxResult.Cancel) == MessageBoxResult.OK)
|
||||
{
|
||||
_isReDo = true;
|
||||
this.Do(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
_isReDo = false;
|
||||
}
|
||||
}
|
||||
|
||||
MessageBox.Show("校正完成");
|
||||
}
|
||||
|
||||
private void ConvertToRecheckDiePoint(ref SemiconductorVisionAlgorithm.SemiParams.Point[,] pointArray)
|
||||
{
|
||||
var rows = pointArray.GetLength(0);
|
||||
var cols = pointArray.GetLength(1);
|
||||
RecheckDiePoint[,] recheckDiePoint =new RecheckDiePoint[rows, cols];
|
||||
for (int i = 0; i < recheckDiePoint.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < recheckDiePoint.GetLength(1); j++)
|
||||
{
|
||||
var point = pointArray[i, j];
|
||||
bool isExist = !(point.X == 0 && point.Y == 0);
|
||||
recheckDiePoint[i, j] = new RecheckDiePoint
|
||||
{
|
||||
X = point.X,
|
||||
Y = point.Y,
|
||||
State = isExist
|
||||
};
|
||||
}
|
||||
}
|
||||
JM1Vision.JM1Manager.Instance.FillCalibData(recheckDiePoint, _cameraWaferFusionCalibrationItem.WaferStepXY,
|
||||
_cameraWaferFusionCalibrationItem.WaferCountXY, out RecheckDiePoint[,] resutPoint);
|
||||
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
for (int j = 0; j < cols; j++)
|
||||
{
|
||||
var point = resutPoint[i, j];
|
||||
|
||||
pointArray[i, j] = new SemiconductorVisionAlgorithm.SemiParams.Point
|
||||
{
|
||||
X = point.X,
|
||||
Y = point.Y,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SemiconductorVisionAlgorithm.SemiParams.Point[,] ApprochWSTable (double waferStep, double x1,double y1,double x2,double y2, int count,string path)
|
||||
{
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point[,] pointArray =
|
||||
new SemiconductorVisionAlgorithm.SemiParams.Point[_cameraWaferFusionCalibrationItem.WaferCountXY, _cameraWaferFusionCalibrationItem.WaferCountXY];
|
||||
motion.MovePHSAndWS(x1, y1, x2, y2);
|
||||
for (int y = 0; y < _cameraWaferFusionCalibrationItem.WaferCountXY; y++)
|
||||
{
|
||||
double waferY = y * waferStep + y2;
|
||||
for (int x = 0; x < _cameraWaferFusionCalibrationItem.WaferCountXY; x++)
|
||||
{
|
||||
int index = y % 2 == 0 ? x : _cameraWaferFusionCalibrationItem.WaferCountXY - 1 - x;
|
||||
double waferX = index * waferStep + x2;
|
||||
|
||||
if (_isCancle)
|
||||
{
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
motion.SafeMoveWS(waferX, waferY);
|
||||
|
||||
Point point = new Point();
|
||||
|
||||
//相机拍照
|
||||
if (!_visionOperation.ApproachPointCircle(_device.Camera_ExtendWS, _device.Axis_X21, _device.Axis_Y21,
|
||||
path, Rectangle, out point))
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
|
||||
Thread.Sleep(100);
|
||||
AxisAndPixelPointItem item = new AxisAndPixelPointItem();
|
||||
item.Id = count;
|
||||
item.AxisX1 = _device.Axis_X11.State.ActualPos;
|
||||
item.AxisX2 = _device.Axis_X21.State.ActualPos;
|
||||
item.AxisY1 = _device.Axis_Y11.State.ActualPos;
|
||||
item.AxisY2 = _device.Axis_Y21.State.ActualPos;
|
||||
item.PixelX = point.X;
|
||||
item.PixelY = point.Y;
|
||||
|
||||
pointArray[index, y] = new SemiconductorVisionAlgorithm.SemiParams.Point(item.AxisX2, item.AxisY2);
|
||||
//IoC.Get<IEventAggregator>()?.Publish(new WaferFusionCalibrationResultEventArgs(item));
|
||||
}
|
||||
}
|
||||
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
private SemiconductorVisionAlgorithm.SemiParams.Point[,] ApprochWSCircleTable(FusionPoint[,] tableDic, double x1, double y1, double x2, double y2, int count, string path)
|
||||
{
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point[,] pointArray =
|
||||
new SemiconductorVisionAlgorithm.SemiParams.Point[_cameraWaferFusionCalibrationItem.WaferCountXY, _cameraWaferFusionCalibrationItem.WaferCountXY];
|
||||
motion.MovePHSAndWS(x1, y1, x2, y2);
|
||||
var offsetX = x2 - _cameraWaferFusionCalibrationItem.CenterX;
|
||||
var rowCount = tableDic.GetLength(0);
|
||||
var columnCount = tableDic.GetLength(1);
|
||||
for (int y = 0; y < rowCount; y++)
|
||||
{
|
||||
|
||||
for (int x = 0; x < columnCount; x++)
|
||||
{
|
||||
int index = y % 2 == 0 ? x : columnCount - 1 - x;
|
||||
|
||||
|
||||
if (_isCancle)
|
||||
{
|
||||
return pointArray;
|
||||
}
|
||||
//var movePoint = tableDic[y,x];
|
||||
var movePoint = tableDic[y, index];
|
||||
if (!movePoint.IsExist)
|
||||
{
|
||||
pointArray[index, y] = new SemiconductorVisionAlgorithm.SemiParams.Point(0, 0);
|
||||
continue;
|
||||
}
|
||||
motion.SafeMoveWS(movePoint.X+ offsetX, movePoint.Y);
|
||||
|
||||
Point point = new Point();
|
||||
|
||||
//相机拍照
|
||||
if (!_visionOperation.ApproachPointCircle(_device.Camera_ExtendWS, _device.Axis_X21, _device.Axis_Y21,
|
||||
path, Rectangle, out point))
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
|
||||
Thread.Sleep(100);
|
||||
AxisAndPixelPointItem item = new AxisAndPixelPointItem();
|
||||
item.Id = count;
|
||||
item.AxisX1 = _device.Axis_X11.State.ActualPos;
|
||||
item.AxisX2 = _device.Axis_X21.State.ActualPos;
|
||||
item.AxisY1 = _device.Axis_Y11.State.ActualPos;
|
||||
item.AxisY2 = _device.Axis_Y21.State.ActualPos;
|
||||
item.PixelX = point.X;
|
||||
item.PixelY = point.Y;
|
||||
|
||||
pointArray[index, y] = new SemiconductorVisionAlgorithm.SemiParams.Point(item.AxisX2, item.AxisY2);
|
||||
//IoC.Get<IEventAggregator>()?.Publish(new WaferFusionCalibrationResultEventArgs(item));
|
||||
}
|
||||
}
|
||||
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
public override void Finish()
|
||||
{
|
||||
base.Finish();
|
||||
IoC.Get<IProjectManager>().SwitchState();
|
||||
}
|
||||
|
||||
public override void Cancel()
|
||||
{
|
||||
_isCancle = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
1、die融合标定(ws圆形标定融合)
|
||||
即在X1全行程不同位置,标定建立X2,Y1的die融合表,用于对位晶粒,使得晶粒可以通过X2,Y1的补偿移动到任意X1位置下(此时对位是Y1位置微动变化)。
|
||||
标定方法
|
||||
- 在die运动系下(固定X1),移动X2,Y1扫描获取N×N点阵,作为初始位置。
|
||||
- 选取X2负限位位置附近设置起始位置,将X1,X2平移相同距离移动到起始位置,设定标定范围,标定间隔,扫描一系列N×N点阵,保存为die融合位置表。
|
||||
验证方法
|
||||
在die运动系下飞拍任意坐标,再选取任意X1位置,使用融合位置表计算出任意坐标移动到该X11位置下的X2Y1坐标,同时获取到在该X11位置下实际逼近的X2Y1坐标,输出即为标定误差。可选择若干位置覆盖测试全行程误差
|
||||
2、pad融合标定(stage拼接融合)
|
||||
即在Y1全行程不同位置,建立X1,Y2的pad融合表,用于对位pad,使得产品pad在获取到运动系X1,Y2坐标后,可以移动到任意Y1位置下(此时对位是X1位置微动变化)。
|
||||
标定方法
|
||||
- 在pad运动系下(固定Y1),移动X1,Y2扫描获取N×N点阵,作为初始位置。
|
||||
- 选取Y2负限位位置附近设置起始位置,将Y1,Y2平移相同距离移动到起始位置,设立标定范围,标定间隔,扫描一系列N×N点阵,保存为pad融合位置表。
|
||||
验证方法
|
||||
在pad运动系下飞拍任意坐标,再选取任意Y1位置,使用融合位置表计算出任意坐标移动到该Y11位置下的X1Y2坐标,同时获取到在该Y11位置下实际逼近的X1Y2坐标,输出即为标定误差。可选择若干位置覆盖测试全行程误差。
|
||||
3、整体验证
|
||||
整体对位流程为:飞拍获取对应die的下相机X2,Y2坐标,X1坐标固定(上相机die运动系X2Y1),转换为X1,Y1坐标 。pad定位mark获取X1,Y2坐标,Y1坐标固定(上相机pad运动系X1Y2),即转化为X1,Y1坐标 。
|
||||
此时通过查找die融合表将dieX方向对齐pad(此时Y1会产生少许偏移),再根据此时Y1值,将padY方向对齐die,(X1会产生少许偏移),此时再移动X2跟上X1的移动量(此处直接移动或查表再移动)。
|
||||
@@ -0,0 +1,12 @@
|
||||
旧项目的标定页面为CameraFusionCalibAView.xaml里面的融合标定和验证1是新项目需要的流程
|
||||
CameraFusionCali02AViewModel.xaml是原项目的CameraFusionCali02AViewModel.cs
|
||||
CameraFusionCalibrationMotion02A.xaml是原项目的CameraFusionCalibrationMotion02A.cs
|
||||
|
||||
旧项目的ws轴是x2、Y2,pad轴是X1、Y1
|
||||
|
||||
新项目的ws轴是X2、Y1,pad轴是x1、Y2
|
||||
|
||||
新项目的需求是pad融合标定和die融合标定,并且有分别的验证
|
||||
|
||||
然后总体又有一个整体的验证,及对位流程
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SemiPoint = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Service
|
||||
{
|
||||
public static class CalibFileService
|
||||
{
|
||||
public static void SaveCalibPointsFile(string path, List<SemiPoint> real, List<SemiPoint> ruler)
|
||||
{
|
||||
using (var sw = new StreamWriter(path))
|
||||
{
|
||||
sw.WriteLine("# realX, realY, rulerX, rulerY");
|
||||
int count = Math.Max(real.Count, ruler.Count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var r = i < real.Count ? real[i] : new SemiPoint(0, 0);
|
||||
var u = i < ruler.Count ? ruler[i] : new SemiPoint(0, 0);
|
||||
sw.WriteLine($"{r.X},{r.Y},{u.X},{u.Y}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReadCalibPointsFile(string path, out List<SemiPoint> real, out List<SemiPoint> ruler)
|
||||
{
|
||||
real = new List<SemiPoint>();
|
||||
ruler = new List<SemiPoint>();
|
||||
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
|
||||
foreach (var line in File.ReadLines(path))
|
||||
{
|
||||
var l = line.Trim();
|
||||
if (string.IsNullOrEmpty(l)) continue;
|
||||
if (l.StartsWith("#")) continue;
|
||||
|
||||
var sp = l.Split(',');
|
||||
if (sp.Length < 4) continue;
|
||||
|
||||
real.Add(new SemiPoint(
|
||||
double.Parse(sp[0]),
|
||||
double.Parse(sp[1])
|
||||
));
|
||||
ruler.Add(new SemiPoint(
|
||||
double.Parse(sp[2]),
|
||||
double.Parse(sp[3])
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
using MainShell.AlgorithmCalib.Common;
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.Common;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Log;
|
||||
using MainShell.Motion;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SemiPoint = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 融合对位处理器
|
||||
/// 3步对位流程:
|
||||
/// 1. 抓Pad点(框选ROI识别Pad坐标)
|
||||
/// 2. Die网格飞拍(首点+参数 → 蛇形扫描获取x*y个Die点)
|
||||
/// 3. 对位验证(选择一个Die点 → 与Pad点对位 → 输出结果)
|
||||
/// </summary>
|
||||
public class FusionAlignProcessor
|
||||
{
|
||||
private readonly FusionCalibMotionService _motionService;
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly FusionCalibModuleItem _moduleItem;
|
||||
private readonly ApproachAlignmentService _approachAlignmentService;
|
||||
|
||||
// 飞拍参数
|
||||
private double _flyScanStartX;
|
||||
private double _flyScanStartY;
|
||||
private int _flyScanXCount;
|
||||
private int _flyScanYCount;
|
||||
private double _flyScanStep;
|
||||
|
||||
public event EventHandler<CalibrationProgressEventArgs> ProgressChanged;
|
||||
private readonly Func<Rectangle1> _roiRectProvider; // ROI 提供者委托
|
||||
|
||||
|
||||
public FusionAlignProcessor(
|
||||
FusionCalibMotionService motionService,
|
||||
HardwareManager hardware,
|
||||
FusionCalibModuleItem moduleItem,
|
||||
Func<Rectangle1> roiRectProvider)
|
||||
{
|
||||
_motionService = motionService;
|
||||
_hardware = hardware;
|
||||
_moduleItem = moduleItem;
|
||||
_approachAlignmentService = IoC.Get<ApproachAlignmentService>();
|
||||
_roiRectProvider = roiRectProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置飞拍参数
|
||||
/// </summary>
|
||||
public void SetFlyScanParams(double startX, double startY, int xCount, int yCount, double step)
|
||||
{
|
||||
_flyScanStartX = startX;
|
||||
_flyScanStartY = startY;
|
||||
_flyScanXCount = xCount;
|
||||
_flyScanYCount = yCount;
|
||||
_flyScanStep = step;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 步骤1:抓Pad点
|
||||
/// 框选ROI区域,识别Pad目标点坐标(pad运动系:X1,Y2)
|
||||
/// </summary>
|
||||
public async Task CapturePadPointAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
ReportProgress("抓Pad点...", 1, 3);
|
||||
|
||||
bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
throw new InvalidOperationException($"逼近对齐失败");
|
||||
}
|
||||
|
||||
_moduleItem.PadRealX = _hardware.Axis_X1.State.ActualPos;
|
||||
_moduleItem.PadRealY = _hardware.Axis_Y2.State.ActualPos;
|
||||
|
||||
"抓Pad点完成".LogInfo();
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 步骤2a:抓Die首点
|
||||
/// 框选ROI区域,识别Die首点坐标(die运动系:X2,Y1)
|
||||
/// </summary>
|
||||
public async Task CaptureDieFirstPointAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await Task.Run(async() =>
|
||||
{
|
||||
ReportProgress("抓Die首点...", 1, 3);
|
||||
|
||||
bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
throw new InvalidOperationException($"逼近对齐失败");
|
||||
}
|
||||
|
||||
_moduleItem.DieRealX = _hardware.Axis_X2.State.ActualPos;
|
||||
_moduleItem.DieRealY = _hardware.Axis_Y1.State.ActualPos;
|
||||
|
||||
"抓Die首点完成".LogInfo();
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 步骤2b:Die网格飞拍
|
||||
/// 以首点为起点,按step和count执行蛇形网格飞拍,获取x*y个Die点
|
||||
/// </summary>
|
||||
public async Task ExecuteDieGridFlyScanAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await Task.Run(async() =>
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
int totalPoints = _flyScanXCount * _flyScanYCount;
|
||||
int captured = 0;
|
||||
|
||||
ReportProgress($"开始飞拍,网格{_flyScanXCount}×{_flyScanYCount},共{totalPoints}点...", 0, totalPoints);
|
||||
|
||||
// 清空之前的数据
|
||||
_moduleItem.DieGridPoints = new List<Tuple<int, int, SemiPoint>>();
|
||||
|
||||
for (int row = 0; row < _flyScanYCount; row++)
|
||||
{
|
||||
// 蛇形扫描:偶数行从左到右,奇数行从右到左
|
||||
for (int col = 0; col < _flyScanXCount; col++)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
int actualCol = row % 2 == 0 ? col : (_flyScanXCount - 1 - col);
|
||||
|
||||
// 计算目标位置
|
||||
double targetX2 = _flyScanStartX + actualCol * _flyScanStep;
|
||||
double targetY1 = _flyScanStartY + row * _flyScanStep;
|
||||
|
||||
// 移动轴到目标位置
|
||||
_motionService.MoveWsAvoidance(targetX2, targetY1);
|
||||
|
||||
// 等待运动完成
|
||||
Thread.Sleep(200);
|
||||
|
||||
bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
throw new InvalidOperationException($"逼近对齐失败");
|
||||
}
|
||||
|
||||
// 读取当前位置
|
||||
double currentX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
double currentY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
|
||||
|
||||
SemiPoint point = new SemiPoint(currentX2, currentY1);
|
||||
_moduleItem.DieGridPoints.Add(Tuple.Create(row, actualCol, point));
|
||||
|
||||
captured++;
|
||||
ReportProgress($"飞拍中... ({captured}/{totalPoints})", captured, totalPoints);
|
||||
}
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
$"Die网格飞拍完成,共{captured}点,耗时{sw.ElapsedMilliseconds}ms".LogInfo();
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 步骤3:执行对位
|
||||
/// 用户选择网格中的一个Die点(row, col),与Pad点执行对位
|
||||
/// 对位流程:Die X对齐Pad → Pad Y对齐Die → X2补偿
|
||||
/// </summary>
|
||||
public async Task ExecuteAlignAsync(CancellationToken ct, int selectedRow, int selectedCol)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
ReportProgress("执行对位...", 1, 6);
|
||||
|
||||
// 从网格中找到选中的Die点
|
||||
SemiPoint selectedDie = null;
|
||||
foreach (var pt in _moduleItem.DieGridPoints)
|
||||
{
|
||||
if (pt.Item1 == selectedRow && pt.Item2 == selectedCol)
|
||||
{
|
||||
selectedDie = pt.Item3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedDie == null)
|
||||
{
|
||||
throw new Exception($"未找到Die点[{selectedRow},{selectedCol}]");
|
||||
}
|
||||
|
||||
// 使用选中的Die点作为对位基准
|
||||
_moduleItem.DieRealX = selectedDie.X;
|
||||
_moduleItem.DieRealY = selectedDie.Y;
|
||||
_moduleItem.PadRealX = _moduleItem.PadRulerX;
|
||||
_moduleItem.PadRealY = _moduleItem.PadRulerY;
|
||||
|
||||
ReportProgress("Die X方向对齐Pad...", 2, 6);
|
||||
|
||||
// === 步骤3a:Die X方向对齐Pad ===
|
||||
// 查die融合表,将Die的X方向对齐到Pad的X方向
|
||||
// 移动X2,Y1 → Y1会产生少许偏移
|
||||
//
|
||||
// TODO: 接入JM1融合表查询
|
||||
// SemiPoint dieReal = new SemiPoint(_moduleItem.DieRealX, _moduleItem.DieRealY);
|
||||
// SemiPoint padReal = new SemiPoint(_moduleItem.PadRealX, _moduleItem.PadRealY);
|
||||
// SemiJM1Manager.Instance.get_ws_pos_die(dieReal, padReal, out SemiPoint wsTarget);
|
||||
//
|
||||
// 暂时模拟:使用Die坐标作为目标
|
||||
double wsTargetX = _moduleItem.DieRealX;
|
||||
double wsTargetY = _moduleItem.DieRealY;
|
||||
|
||||
_motionService.MoveWsAvoidance(wsTargetX, wsTargetY);
|
||||
|
||||
// 读取此时Y1位置(已产生偏移)
|
||||
double currentY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
|
||||
ReportProgress("Pad Y方向对齐Die...", 3, 6);
|
||||
|
||||
// === 步骤3b:Pad Y方向对齐Die ===
|
||||
// 根据当前Y1值,查pad融合表,计算X1,Y2目标位置
|
||||
// 移动X1,Y2 → X1会产生少许偏移
|
||||
//
|
||||
// TODO: 接入pad融合表查询
|
||||
// SemiPoint padTarget = FusionTableLookupPad(padReal, currentY1);
|
||||
//
|
||||
// 暂时模拟
|
||||
double padTargetX = _moduleItem.PadRealX;
|
||||
double padTargetY = _moduleItem.PadRealY;
|
||||
|
||||
_motionService.MovePhsAvoidance(padTargetX, padTargetY);
|
||||
|
||||
// 读取此时X1位置(已产生偏移)
|
||||
double currentX1 = _hardware.Axis_X1.State.ActualPos;
|
||||
|
||||
ReportProgress("X2补偿...", 4, 6);
|
||||
|
||||
// === 步骤3c:X2补偿 ===
|
||||
// X2跟上X1的移动量
|
||||
double x1Delta = currentX1 - _moduleItem.PadRulerX;
|
||||
double x2Target = wsTargetX + x1Delta;
|
||||
|
||||
_motionService.SafeMove(_hardware.Axis_X2, x2Target);
|
||||
|
||||
// 记录结果
|
||||
_moduleItem.AlignResultX = currentX1;
|
||||
_moduleItem.AlignResultY = currentY1;
|
||||
_moduleItem.AlignResultX2 = x2Target;
|
||||
|
||||
ReportProgress("对位完成", 5, 6);
|
||||
$"对位完成: Die[{selectedRow},{selectedCol}] → Pad, X1={currentX1:F4}, Y1={currentY1:F4}, X2 ={ x2Target: F4}".LogInfo();
|
||||
}, ct);
|
||||
}
|
||||
|
||||
private void ReportProgress(string message, int current, int total)
|
||||
{
|
||||
ProgressChanged?.Invoke(this, new CalibrationProgressEventArgs
|
||||
{
|
||||
Message = message,
|
||||
Current = current,
|
||||
Total = total
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 逼近对齐
|
||||
/// </summary>
|
||||
private async Task<bool> ApproachAtPointAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
Rectangle1 roiRect = _roiRectProvider?.Invoke();
|
||||
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, cancellationToken).ConfigureAwait(false);
|
||||
return result.Succeeded;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Motion;
|
||||
using MaxwellFramework.Core.Attributes;
|
||||
using MwFramework.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Service
|
||||
{
|
||||
[Singleton]
|
||||
public class FusionCalibMotionService
|
||||
{
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly SafeAxisMotion _safeAxisMotion;
|
||||
|
||||
public FusionCalibMotionService(HardwareManager hardware, SafeAxisMotion safeAxisMotion)
|
||||
{
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_safeAxisMotion = safeAxisMotion ?? throw new ArgumentNullException(nameof(safeAxisMotion));
|
||||
}
|
||||
|
||||
public void SafeMove(IAxis axis, double position)
|
||||
{
|
||||
_safeAxisMotion.SafeMove(
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(axis, nameof(axis)), position));
|
||||
}
|
||||
|
||||
public void MoveWsAvoidance(double xPosition, double yPosition)
|
||||
{
|
||||
_safeAxisMotion.SafeMove(
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_X2, nameof(_hardware.Axis_X2)), xPosition),
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_Y1, nameof(_hardware.Axis_Y1)), yPosition));
|
||||
}
|
||||
|
||||
public void MovePhsAvoidance(double xPosition, double yPosition)
|
||||
{
|
||||
_safeAxisMotion.SafeMove(
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_X1, nameof(_hardware.Axis_X1)), xPosition),
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_Y2, nameof(_hardware.Axis_Y2)), yPosition));
|
||||
}
|
||||
|
||||
public void RotatePos(double rotatePosition)
|
||||
{
|
||||
_safeAxisMotion.SafeMove(
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_WS_R, nameof(_hardware.Axis_WS_R)), rotatePosition));
|
||||
}
|
||||
|
||||
private static MwFramework.Device.IAxis GetRequiredAxis(MwFramework.Device.IAxis axis, string axisPropertyName)
|
||||
{
|
||||
if (axis == null)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Axis '{0}' is not available.", axisPropertyName));
|
||||
}
|
||||
return axis;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
using MainShell.AlgorithmCalib.Common;
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Log;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 融合标定后处理器(Die/Pad共用)
|
||||
/// 通过 IsWaferCalib 内部区分行为
|
||||
/// </summary>
|
||||
public class FusionCalibPostProcessor : IAlgorithmCalibrationPostProcessor
|
||||
{
|
||||
private readonly FusionCalibMotionService _motionService;
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly FusionCalibModuleItem _moduleItem;
|
||||
private readonly Func<Rectangle1> _roiRectProvider;
|
||||
|
||||
public event EventHandler<CalibrationProgressEventArgs> ProgressChanged;
|
||||
|
||||
private Point[,] _initialwsPos;
|
||||
private Dictionary<int, Point[,]> _calibResultPointData = new Dictionary<int, Point[,]>();
|
||||
private List<double> _calibPosList = new List<double>();
|
||||
|
||||
public string Name => "FusionCalib";
|
||||
|
||||
public FusionCalibPostProcessor(
|
||||
FusionCalibMotionService motionService,
|
||||
HardwareManager hardware,
|
||||
FusionCalibModuleItem moduleItem,
|
||||
Func<Rectangle1> roiRectProvider)
|
||||
{
|
||||
_motionService = motionService ?? throw new ArgumentNullException(nameof(motionService));
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_moduleItem = moduleItem ?? throw new ArgumentNullException(nameof(moduleItem));
|
||||
_roiRectProvider = roiRectProvider;
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(AlgorithmCalibExecutionResult calibrationResult, CancellationToken cancellationToken)
|
||||
{
|
||||
$"{(_moduleItem.IsWaferCalib ? "Die" : "Pad")}融合标定开始。".LogInfo();
|
||||
|
||||
try
|
||||
{
|
||||
_calibResultPointData.Clear();
|
||||
_calibPosList.Clear();
|
||||
|
||||
double waferStep = _moduleItem.CalibStep;
|
||||
string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _moduleItem.ModelPath);
|
||||
|
||||
int totalSteps = _moduleItem.Count + 1;
|
||||
ReportProgress("采集初始网格点...", 0, totalSteps);
|
||||
|
||||
// 1. 初始网格
|
||||
_initialwsPos = await Task.Run(() =>
|
||||
ApprochTable(waferStep,
|
||||
_moduleItem.MoveAxisPos,
|
||||
GetCurrentY1(),
|
||||
_moduleItem.ApproachXPos,
|
||||
_moduleItem.ApproachYPos,
|
||||
0, path, cancellationToken),
|
||||
cancellationToken);
|
||||
|
||||
// 2. 循环采集
|
||||
for (int i = 0; i < _moduleItem.Count; i++)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
ReportProgress($"采集第 {i + 1}/{_moduleItem.Count} 组...", i + 1, totalSteps);
|
||||
|
||||
double x1, y1, x2, y2;
|
||||
CalculatePositions(i, out x1, out y1, out x2, out y2);
|
||||
|
||||
Point[,] points = await Task.Run(() =>
|
||||
ApprochTable(waferStep, x1, y1, x2, y2, i + 1, path, cancellationToken),
|
||||
cancellationToken);
|
||||
|
||||
_calibResultPointData[i] = points;
|
||||
_calibPosList.Add(GetCurrentMoveAxisPos());
|
||||
}
|
||||
|
||||
// 3. 调用平台算法
|
||||
ReportProgress("计算融合矩阵...", totalSteps, totalSteps);
|
||||
await Task.Run(() =>
|
||||
{
|
||||
string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CalibData");
|
||||
|
||||
if (_moduleItem.IsWaferCalib)
|
||||
{
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.cal_wafer_fusion_die(
|
||||
_calibResultPointData, _calibPosList, _initialwsPos,
|
||||
_moduleItem.CalibStep, waferStep, _moduleItem.CalibCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.cal_wafer_fusion_pad(
|
||||
_moduleItem.Index, _calibResultPointData, _calibPosList, _initialwsPos,
|
||||
_moduleItem.CalibStep, waferStep, _moduleItem.CalibCount);
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.set_center(new Point(0, 0));
|
||||
}
|
||||
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.Save(filePath);
|
||||
}, cancellationToken);
|
||||
|
||||
$"{(_moduleItem.IsWaferCalib ? "Die" : "Pad")}融合标定完成。".LogInfo();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
"融合标定已取消。".LogInfo();
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
$"融合标定失败:{ex.Message}".LogSysError();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task VerifyAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: 验证流程
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
#region 位置计算(Die/Pad分支)
|
||||
|
||||
private void CalculatePositions(int stepIndex, out double x1, out double y1, out double x2, out double y2)
|
||||
{
|
||||
if (_moduleItem.IsWaferCalib)
|
||||
{
|
||||
// Die: 移动X1,逼近X2+Y1
|
||||
x1 = _moduleItem.CameraAxisPos + _moduleItem.Step * stepIndex;
|
||||
y1 = _moduleItem.StartY;
|
||||
x2 = _moduleItem.StartX + _moduleItem.Step * stepIndex;
|
||||
y2 = _hardware.Axis_Y2.State.ActualPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pad: 移动Y1,逼近X1+Y2
|
||||
x1 = _moduleItem.StartX;
|
||||
y1 = _moduleItem.CameraAxisPos + _moduleItem.Step * stepIndex;
|
||||
x2 = _hardware.Axis_X2.State.ActualPos;
|
||||
y2 = _moduleItem.StartY + _moduleItem.Step * stepIndex;
|
||||
}
|
||||
}
|
||||
|
||||
private double GetCurrentY1()
|
||||
{
|
||||
return _hardware.Axis_Y1.State.ActualPos;
|
||||
}
|
||||
|
||||
private double GetCurrentMoveAxisPos()
|
||||
{
|
||||
return _moduleItem.IsWaferCalib
|
||||
? _hardware.Axis_X1.State.ActualPos
|
||||
: _hardware.Axis_Y1.State.ActualPos;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 网格采集
|
||||
|
||||
private Point[,] ApprochTable(double calibStep, double x1, double y1, double x2, double y2,
|
||||
int count, string path, CancellationToken ct)
|
||||
{
|
||||
int calibCount = _moduleItem.CalibCount;
|
||||
Point[,] pointArray = new Point[calibCount, calibCount];
|
||||
|
||||
// 先移到起始位置
|
||||
if (_moduleItem.IsWaferCalib)
|
||||
_motionService.MoveWsAvoidance(x2, y1);
|
||||
else
|
||||
_motionService.MovePhsAvoidance(x1, y2);
|
||||
|
||||
for (int y = 0; y < calibCount; y++)
|
||||
{
|
||||
double Y1 = y * calibStep + y1;
|
||||
double Y2 = y * calibStep + y2;
|
||||
|
||||
for (int x = 0; x < calibCount; x++)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
int index = y % 2 == 0 ? x : calibCount - 1 - x;
|
||||
double X2 = index * calibStep + x2;
|
||||
double X1 = index * calibStep + x1;
|
||||
|
||||
if (_moduleItem.IsWaferCalib)
|
||||
{
|
||||
_motionService.MoveWsAvoidance(X2, Y1);
|
||||
// TODO: 调用逼近识别
|
||||
pointArray[index, y] = new Point(
|
||||
_hardware.Axis_X2.State.ActualPos,
|
||||
_hardware.Axis_Y1.State.ActualPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
_motionService.MovePhsAvoidance(X1, Y2);
|
||||
// TODO: 调用逼近识别
|
||||
pointArray[index, y] = new Point(
|
||||
_hardware.Axis_X1.State.ActualPos,
|
||||
_hardware.Axis_Y2.State.ActualPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void ReportProgress(string message, int current, int total)
|
||||
{
|
||||
ProgressChanged?.Invoke(this, new CalibrationProgressEventArgs
|
||||
{
|
||||
Message = message,
|
||||
Current = current,
|
||||
Total = total
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Service
|
||||
{
|
||||
public static class MotionCalibFileService
|
||||
{
|
||||
public static void SaveCalibPointsFile(string path, List<Point> real, List<Point> ruler)
|
||||
{
|
||||
using (var sw = new StreamWriter(path))
|
||||
{
|
||||
sw.WriteLine("# realX, realY, rulerX, rulerY");
|
||||
int count = Math.Max(real.Count, ruler.Count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var r = i < real.Count ? real[i] : new Point(0, 0);
|
||||
var u = i < ruler.Count ? ruler[i] : new Point(0, 0);
|
||||
sw.WriteLine($"{r.X},{r.Y},{u.X},{u.Y}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReadCalibPointsFile(string path, out List<Point> real, out List<Point> ruler)
|
||||
{
|
||||
real = new List<Point>();
|
||||
ruler = new List<Point>();
|
||||
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
|
||||
foreach (var line in File.ReadLines(path))
|
||||
{
|
||||
var l = line.Trim();
|
||||
if (string.IsNullOrEmpty(l)) continue;
|
||||
if (l.StartsWith("#")) continue;
|
||||
|
||||
var sp = l.Split(',');
|
||||
if (sp.Length < 4) continue;
|
||||
|
||||
real.Add(new Point(
|
||||
double.Parse(sp[0]),
|
||||
double.Parse(sp[1])
|
||||
));
|
||||
ruler.Add(new Point(
|
||||
double.Parse(sp[2]),
|
||||
double.Parse(sp[3])
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 旋转表标定文件服务
|
||||
/// </summary>
|
||||
public static class RotateMatixFormCalibFileService
|
||||
{
|
||||
/// <summary>
|
||||
/// 保存验证点数据
|
||||
/// </summary>
|
||||
public static void SaveVerifyPointsFile(string path, List<Point> cal, List<Point> real)
|
||||
{
|
||||
using (var sw = new StreamWriter(path))
|
||||
{
|
||||
int count = cal.Count;
|
||||
sw.WriteLine("Cal_X,Cal_Y,Real_X,Real_Y");
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
sw.WriteLine($"{cal[i].X},{cal[i].Y},{real[i].X},{real[i].Y}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存标定网格数据(用于调试)
|
||||
/// </summary>
|
||||
public static void SaveCalibrationGridData(string path, List<Point[,]> calibData,List<double> rotatePosList)
|
||||
{
|
||||
using (var sw = new StreamWriter(path))
|
||||
{
|
||||
sw.WriteLine("RotatePos,GridY,GridX,PointX,PointY");
|
||||
for (int step = 0; step < calibData.Count; step++)
|
||||
{
|
||||
var grid = calibData[step];
|
||||
int n = grid.GetLength(0);
|
||||
for (int y = 0; y < n; y++)
|
||||
{
|
||||
for (int x = 0; x < n; x++)
|
||||
{
|
||||
sw.WriteLine($"{rotatePosList[step]:F4},{y},{x},{grid[y,x].X:F6},{grid[y, x].Y:F6}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Log;
|
||||
using MainShell.Motion;
|
||||
using MaxwellFramework.Core.Attributes;
|
||||
using MwFramework.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 旋转表标定运动服务
|
||||
/// 对标 OriginCalibrationMotionService
|
||||
/// </summary>
|
||||
[Singleton]
|
||||
public class RotateMatixFormCalibMotionService
|
||||
{
|
||||
private const int PositionSettleDelayMilliseconds = 200;
|
||||
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly SafeAxisMotion _safeAxisMotion;
|
||||
|
||||
public RotateMatixFormCalibMotionService(HardwareManager hardware, SafeAxisMotion safeAxisMotion)
|
||||
{
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_safeAxisMotion = safeAxisMotion ?? throw new ArgumentNullException(nameof(safeAxisMotion));
|
||||
}
|
||||
|
||||
#region 低级运动方法
|
||||
|
||||
public void SafeMove(IAxis axis, double position)
|
||||
{
|
||||
_safeAxisMotion.SafeMove(
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(axis, nameof(axis)), position));
|
||||
}
|
||||
|
||||
public async Task SafeMoveAsync(IAxis axis, double position, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await _safeAxisMotion.SafeMoveAsync(
|
||||
cancellationToken,
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(axis, nameof(axis)),position)).ConfigureAwait(false);
|
||||
result.EnsureSuccess();
|
||||
}
|
||||
|
||||
public void MoveWsAvoidance(double xPosition, double yPosition)
|
||||
{
|
||||
_safeAxisMotion.SafeMove(
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_X2,nameof(_hardware.Axis_X2)), xPosition),
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_Y1,nameof(_hardware.Axis_Y1)), yPosition));
|
||||
}
|
||||
|
||||
public async Task MoveWsAvoidanceAsync(double xPosition, double yPosition,CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await _safeAxisMotion.SafeMoveAsync(
|
||||
cancellationToken,
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_X2,nameof(_hardware.Axis_X2)), xPosition),
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_Y1,nameof(_hardware.Axis_Y1)), yPosition)).ConfigureAwait(false);
|
||||
result.EnsureSuccess();
|
||||
}
|
||||
|
||||
public void RotatePos(double rotatePosition)
|
||||
{
|
||||
_safeAxisMotion.SafeMove(
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_WS_R,nameof(_hardware.Axis_WS_R)), rotatePosition));
|
||||
}
|
||||
|
||||
public async Task RotatePosAsync(double rotatePosition, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await _safeAxisMotion.SafeMoveAsync(
|
||||
cancellationToken,
|
||||
MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_WS_R,nameof(_hardware.Axis_WS_R)), rotatePosition)).ConfigureAwait(false);
|
||||
result.EnsureSuccess();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 批量运动方法(对标 OriginCalibrationMotionService)
|
||||
|
||||
/// <summary>
|
||||
/// 批量移动避让轴
|
||||
/// </summary>
|
||||
public async Task MoveAvoidanceAxesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
// 移动 X1 到避让位
|
||||
if (_hardware.Axis_PHS_X1 != null)
|
||||
{
|
||||
string.Format("旋转表标定移动避让轴 X1 到位置。").LogInfo();
|
||||
await SafeMoveAsync(_hardware.Axis_PHS_X1, 0,cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待轴稳定后采集实际位置
|
||||
/// </summary>
|
||||
public async Task<Dictionary<string, double>> CollectActualPositionsAsync(
|
||||
IEnumerable<string> axisNames,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
string.Format("旋转表标定等待 {0} ms 以稳定轴反馈。",PositionSettleDelayMilliseconds).LogInfo();
|
||||
await Task.Delay(PositionSettleDelayMilliseconds,cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var positions = new Dictionary<string, double>(StringComparer.Ordinal);
|
||||
foreach (var axisName in axisNames)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(axisName)) continue;
|
||||
|
||||
var axis = _hardware.GetAxisByName(axisName);
|
||||
if (axis == null) continue;
|
||||
|
||||
positions[axisName] = GetActualPosition(axis);
|
||||
string.Format("旋转表标定已采集轴'{0}'的实际位置:{1:F3}。", axisName,positions[axisName]).LogInfo();
|
||||
}
|
||||
|
||||
return positions;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static double GetActualPosition(IAxis axis)
|
||||
{
|
||||
return axis.State != null ? axis.State.ActualPos : axis.GetPositionImmediate();
|
||||
}
|
||||
|
||||
private static IAxis GetRequiredAxis(IAxis axis, string axisPropertyName)
|
||||
{
|
||||
if (axis == null)
|
||||
throw new InvalidOperationException(string.Format("Axis '{0}' is not available.",axisPropertyName));
|
||||
return axis;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,598 @@
|
||||
using JM1Vision;
|
||||
using MainShell.AlgorithmCalib.Common;
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.Common;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Log;
|
||||
using MainShell.Motion;
|
||||
using MainShell.PageCalib.OriginCalib.Service;
|
||||
using SemiconductorVisionAlgorithm.SemiCalib;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using SemiJM1Vision;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Point = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// 旋转表标定后处理器
|
||||
/// 对标原 RotateFormCalibTask 的逻辑
|
||||
/// </summary>
|
||||
public class RotateMatixFormCalibPostProcessor : IAlgorithmCalibrationPostProcessor
|
||||
{
|
||||
private readonly RotateMatixFormCalibMotionService _motionService;
|
||||
private readonly HardwareManager _hardware;
|
||||
private readonly RotateMatixFormCalibModuleItem _moduleItem;
|
||||
private readonly ApproachAlignmentService _approachAlignmentService;
|
||||
private readonly Func<Rectangle1> _roiRectProvider; // ROI 提供者委托
|
||||
|
||||
public event EventHandler<CalibrationProgressEventArgs> ProgressChanged;
|
||||
|
||||
// 运行时数据
|
||||
private Point[,] _initialwsPos;
|
||||
private List<Point[,]> _calibWaferData = new List<Point[,]>();
|
||||
private List<double> _rotatePosList = new List<double>();
|
||||
private double _initialwsRotate;
|
||||
|
||||
public string Name => "RotateFormCalib";
|
||||
|
||||
public RotateMatixFormCalibPostProcessor(
|
||||
RotateMatixFormCalibMotionService motionService,
|
||||
HardwareManager hardware,
|
||||
RotateMatixFormCalibModuleItem moduleItem,
|
||||
ApproachAlignmentService approachAlignmentService,
|
||||
Func<Rectangle1> roiRectProvider)
|
||||
{
|
||||
_motionService = motionService ?? throw new ArgumentNullException(nameof(motionService));
|
||||
_hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
|
||||
_moduleItem = moduleItem ?? throw new ArgumentNullException(nameof(moduleItem));
|
||||
_approachAlignmentService = approachAlignmentService ?? throw new ArgumentNullException(nameof(approachAlignmentService));
|
||||
_roiRectProvider = roiRectProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标定主流程
|
||||
/// 对标原 RotateFormCalibTask.RotateCalib()
|
||||
/// </summary>
|
||||
public async Task ExecuteAsync(AlgorithmCalibExecutionResult calibrationResult, CancellationToken cancellationToken)
|
||||
{
|
||||
"旋转表标定开始。".LogInfo();
|
||||
|
||||
try
|
||||
{
|
||||
// 清空历史数据
|
||||
_calibWaferData.Clear();
|
||||
_rotatePosList.Clear();
|
||||
|
||||
double waferStep = _moduleItem.WaferStep;
|
||||
int rowCol = _moduleItem.RowCol;
|
||||
|
||||
// 1. 移动到起始位置,采集初始网格点
|
||||
ReportProgress("采集初始网格点...", 0, 1);
|
||||
_initialwsPos = await GetInitPointsAsync(
|
||||
waferStep,
|
||||
_moduleItem.X1AvoidancePosition,
|
||||
_moduleItem.StartY,
|
||||
_moduleItem.StartX,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_initialwsRotate = _hardware.Axis_WS_R.State.ActualPos;
|
||||
string.Format("旋转表标定:初始旋转位置 = {0:F4}。", _initialwsRotate).LogInfo();
|
||||
|
||||
// 2. 计算总旋转步数
|
||||
double rotateStep = _moduleItem.RotateStep;
|
||||
|
||||
double negLimit = 0;
|
||||
double posLimit = 0;
|
||||
|
||||
_hardware.Axis_WS_R.GetSoftMel(ref negLimit);
|
||||
_hardware.Axis_WS_R.GetSoftPel(ref posLimit);
|
||||
|
||||
// 如果限位为0,使用默认范围
|
||||
if (negLimit == 0 && posLimit == 0)
|
||||
{
|
||||
negLimit = -180;
|
||||
posLimit = 180;
|
||||
"旋转表标定:限位为0,使用默认范围 [-180, 180]。".LogInfo();
|
||||
}
|
||||
|
||||
double startAngle = negLimit;
|
||||
double range = posLimit - startAngle;
|
||||
int totalCount = (int)(range / rotateStep) + 1;
|
||||
|
||||
string.Format("旋转表标定:旋转步数 = {0},范围 = [{1:F4}, {2:F4}]。", totalCount, negLimit, posLimit).LogInfo();
|
||||
|
||||
// 初始化数据容器
|
||||
for (int i = 0; i < totalCount; i++)
|
||||
{
|
||||
_rotatePosList.Add(0);
|
||||
_calibWaferData.Add(new Point[rowCol, rowCol]);
|
||||
}
|
||||
|
||||
// 3. 旋转轴先转到负限位
|
||||
ReportProgress("旋转轴移动到负限位...", 0, totalCount);
|
||||
await _motionService.RotatePosAsync(negLimit, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// 4. 从负限位开始,逐步旋转到正限位,每步采集网格
|
||||
for (int stepIndex = 0; stepIndex < totalCount; stepIndex++)
|
||||
{
|
||||
double targetRotate = startAngle + rotateStep * stepIndex;
|
||||
|
||||
if (targetRotate > posLimit)
|
||||
break;
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
ReportProgress($"旋转到 {targetRotate:F2}°", stepIndex, totalCount);
|
||||
// 旋转到目标角度
|
||||
await _motionService.RotatePosAsync(targetRotate, cancellationToken).ConfigureAwait(false);
|
||||
_rotatePosList[stepIndex] = _hardware.Axis_WS_R.State.ActualPos;
|
||||
|
||||
|
||||
// 计算旋转后的拍照位置
|
||||
var rotateOffset = targetRotate - _initialwsRotate;
|
||||
var resultPts = new Point[rowCol, rowCol];
|
||||
SemiJM1Manager.Instance.RotatePts("", _initialwsPos, rotateOffset, out resultPts);
|
||||
ReportProgress($"采集网格点 ({stepIndex + 1}/{totalCount})", stepIndex + 1, totalCount);
|
||||
|
||||
var resultPoints = await GetApproachCenterPointsAsync(resultPts, stepIndex, cancellationToken).ConfigureAwait(false);
|
||||
_calibWaferData[stepIndex] = resultPoints;
|
||||
}
|
||||
|
||||
// 5. 融合计算
|
||||
ReportProgress("融合计算...", totalCount, totalCount);
|
||||
SemiJM1Manager.Instance.MakeRotateTable(
|
||||
_calibWaferData, _rotatePosList, _moduleItem.RotateStep);
|
||||
|
||||
// 6. 保存标定数据
|
||||
ReportProgress("保存标定数据...", totalCount, totalCount);
|
||||
string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CalibData");
|
||||
Directory.CreateDirectory(filePath);
|
||||
JM1Manager.Instance.Save(filePath);
|
||||
string.Format("旋转表标定:标定数据已保存到 {0}。", filePath).LogInfo();
|
||||
|
||||
// 7. 保存调试数据
|
||||
string debugPath = Path.Combine(filePath, "RotateFormCalibDebug.csv");
|
||||
RotateMatixFormCalibFileService.SaveCalibrationGridData(debugPath, _calibWaferData, _rotatePosList);
|
||||
ReportProgress("标定完成", totalCount, totalCount);
|
||||
"旋转表标定完成。".LogInfo();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
"旋转表标定已取消。".LogInfo();
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("旋转表标定失败:{0}", ex.Message).LogSysError();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证流程
|
||||
/// 对标原 RotateFormCalibTask.RotateCalibVerify()
|
||||
/// </summary>
|
||||
public async Task VerifyAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
"旋转表验证开始。".LogInfo();
|
||||
|
||||
try
|
||||
{
|
||||
double verifyWaferStep = _moduleItem.VerifyWaferStep;
|
||||
double initWsRotate = _hardware.Axis_WS_R.State.ActualPos;
|
||||
double rotateOffset = _moduleItem.VerifyRotateRange;
|
||||
int totalSteps = _moduleItem.VerifyRowCol * _moduleItem.VerifyRowCol + 2;
|
||||
|
||||
// 1. 获取验证初始点
|
||||
ReportProgress("获取验证初始点...", 0, totalSteps);
|
||||
var initVerifyPts = await GetInitListPointsAsync(
|
||||
verifyWaferStep,
|
||||
_moduleItem.VerifyStartX,
|
||||
_moduleItem.VerifyStartY,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// 2. 旋转轴转到目标位置
|
||||
double targetRotate = initWsRotate + rotateOffset;
|
||||
ReportProgress("旋转到目标角度...", 1, totalSteps);
|
||||
await _motionService.RotatePosAsync(targetRotate, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// 3. 调用算法接口计算预期位置
|
||||
ReportProgress("计算预期位置...", 2, totalSteps);
|
||||
var calPts = new List<Point>();
|
||||
SemiJM1Manager.Instance.GetRotateDstPos(initVerifyPts, initWsRotate, rotateOffset, out calPts);
|
||||
|
||||
// 4. 逐个移动并采集实际位置
|
||||
ReportProgress("逐个采集实际位置...", 2, totalSteps);
|
||||
var approachPts = await MoveAndGetPtsAsync(calPts, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// 5. 保存验证数据
|
||||
ReportProgress("保存验证数据...", totalSteps, totalSteps);
|
||||
string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "RotateFormVerify.csv");
|
||||
RotateMatixFormCalibFileService.SaveVerifyPointsFile(filePath, calPts, approachPts);
|
||||
ReportProgress("验证完成", totalSteps, totalSteps);
|
||||
|
||||
"旋转表验证完成。".LogInfo();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
"旋转表验证已取消。".LogInfo();
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string.Format("旋转表验证失败:{0}", ex.Message).LogSysError();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#region 辅助方法
|
||||
|
||||
///// <summary>
|
||||
///// 蛇形扫描网格,返回 Point[RowCol, RowCol]
|
||||
///// 对标原 RotateFormCalibTask.GetInitPoints()
|
||||
///// </summary>
|
||||
//private async Task<Point[,]> GetInitPointsAsync(
|
||||
// double waferStep, double x1, double y1, double x2,
|
||||
// CancellationToken cancellationToken)
|
||||
//{
|
||||
// int n = _moduleItem.RowCol;
|
||||
// var pointArray = new Point[n, n];
|
||||
|
||||
// // 移动 X1 到避让位
|
||||
// await _motionService.SafeMoveAsync(_hardware.Axis_PHS_X1, x1, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// for (int y = 0; y < n; y++)
|
||||
// {
|
||||
// for (int x = 0; x < n; x++)
|
||||
// {
|
||||
// int index = y % 2 == 0 ? x : n - 1 - x;
|
||||
// double waferX = index * waferStep + x2;
|
||||
// double waferY = y * waferStep + y1;
|
||||
|
||||
// cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// // 粗移到目标位置
|
||||
// await _motionService.MoveWsAvoidanceAsync(waferX, waferY, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// // 逼近对齐
|
||||
// bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
|
||||
// if (!success)
|
||||
// {
|
||||
// throw new InvalidOperationException(string.Format("逼近对齐失败 at ({0:F4}, {0:F4})。", waferX, waferY));
|
||||
// }
|
||||
|
||||
// // 采集光栅尺位置
|
||||
// var rulerX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
// var rulerY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
// pointArray[y, index] = new Point(rulerX2, rulerY1);
|
||||
|
||||
// string.Format("初始网格点 [{0},{1}] = ({2:F4}, {3:F4})。", y, index, rulerX2,
|
||||
// rulerY1).LogInfo();
|
||||
// }
|
||||
// }
|
||||
|
||||
// return pointArray;
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 根据旋转后的拍照位置,蛇形逐个对齐
|
||||
///// 对标原 RotateFormCalibTask.GetApproachCenterPoints()
|
||||
///// </summary>
|
||||
//private async Task<Point[,]> GetApproachCenterPointsAsync(
|
||||
// Point[,] cameraPoints, int stepIndex,
|
||||
// CancellationToken cancellationToken)
|
||||
//{
|
||||
// int n = _moduleItem.RowCol;
|
||||
// var resultArray = new Point[n, n];
|
||||
|
||||
// for (int y = 0; y < n; y++)
|
||||
// {
|
||||
// for (int x = 0; x < n; x++)
|
||||
// {
|
||||
// int index = y % 2 == 0 ? x : n - 1 - x;
|
||||
// cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// double px = cameraPoints[y, index].X;
|
||||
// double py = cameraPoints[y, index].Y;
|
||||
|
||||
// // 粗移到目标位置
|
||||
// await _motionService.MoveWsAvoidanceAsync(px, py, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// // 逼近对齐
|
||||
// bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
|
||||
// if (!success)
|
||||
// {
|
||||
// throw new InvalidOperationException(string.Format("逼近对齐失败 at ({0:F4}, {1:F4})。", px, py));
|
||||
// }
|
||||
|
||||
// // 采集光栅尺位置
|
||||
// var rulerX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
// var rulerY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
// resultArray[y, index] = new Point(rulerX2, rulerY1);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return resultArray;
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 蛇形扫描网格,返回 List<Point>
|
||||
///// 对标原 RotateFormCalibTask.GetInitListPoints()
|
||||
///// </summary>
|
||||
//private async Task<List<Point>> GetInitListPointsAsync(
|
||||
// double waferStep, double x2, double y1,
|
||||
// CancellationToken cancellationToken)
|
||||
//{
|
||||
// int n = _moduleItem.VerifyRowCol;
|
||||
|
||||
// // 移动 X1 到避让位
|
||||
// await _motionService.SafeMoveAsync(_hardware.Axis_PHS_X1, _moduleItem.X1AvoidancePosition, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// var pointArray = new List<Point>();
|
||||
|
||||
// for (int y = 0; y < n; y++)
|
||||
// {
|
||||
// for (int x = 0; x < n; x++)
|
||||
// {
|
||||
// int index = y % 2 == 0 ? x : n - 1 - x;
|
||||
// double waferX = index * waferStep + x2;
|
||||
// double waferY = y * waferStep + y1;
|
||||
|
||||
// cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// // 粗移到目标位置
|
||||
// await _motionService.MoveWsAvoidanceAsync(waferX, waferY, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// // 逼近对齐
|
||||
// bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
|
||||
// if (!success)
|
||||
// {
|
||||
// throw new InvalidOperationException(string.Format("逼近对齐失败 at ({0:F4},{1:F4})。", waferX, waferY));
|
||||
// }
|
||||
|
||||
// // 采集光栅尺位置
|
||||
// var rulerX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
// var rulerY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
// pointArray.Add(new Point(rulerX2, rulerY1));
|
||||
// }
|
||||
// }
|
||||
|
||||
// return pointArray;
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 逐个移动到目标点并采集实际位置
|
||||
///// 对标原 RotateFormCalibTask.MoveAndGetPts()
|
||||
///// </summary>
|
||||
//private async Task<List<Point>> MoveAndGetPtsAsync(
|
||||
// List<Point> targetPts,
|
||||
// CancellationToken cancellationToken)
|
||||
//{
|
||||
// var pointArray = new List<Point>();
|
||||
|
||||
// foreach (var pt in targetPts)
|
||||
// {
|
||||
// cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// // 粗移到目标位置
|
||||
// await _motionService.MoveWsAvoidanceAsync(pt.X, pt.Y,
|
||||
//cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// // 逼近对齐
|
||||
// bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
|
||||
// if (!success)
|
||||
// {
|
||||
// throw new InvalidOperationException(string.Format("逼近对齐失败 at ({0:F4},{1:F4})。", pt.X, pt.Y));
|
||||
// }
|
||||
|
||||
// // 采集光栅尺位置
|
||||
// var rulerX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
// var rulerY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
// pointArray.Add(new Point(rulerX2, rulerY1));
|
||||
// }
|
||||
|
||||
// return pointArray;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 移动逼近公共方法
|
||||
/// </summary>
|
||||
/// <param name="targetX"></param>
|
||||
/// <param name="targetY"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
private async Task<Point> MoveApproachAndCollectAsync(
|
||||
double targetX, double targetY, CancellationToken cancellationToken)
|
||||
{
|
||||
await _motionService.MoveWsAvoidanceAsync(targetX, targetY,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
bool success = await ApproachAtPointAsync(cancellationToken).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
throw new InvalidOperationException($"逼近对齐失败 at ({targetX:F4}, {targetY:F4})。");
|
||||
}
|
||||
|
||||
var rulerX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
var rulerY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
return new Point(rulerX2, rulerY1);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取标定初始点组
|
||||
/// </summary>
|
||||
/// <param name="waferStep"></param>
|
||||
/// <param name="x1"></param>
|
||||
/// <param name="y1"></param>
|
||||
/// <param name="x2"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<Point[,]> GetInitPointsAsync(
|
||||
double waferStep, double x1, double y1, double x2,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
int n = _moduleItem.RowCol;
|
||||
var pointArray = new Point[n, n];
|
||||
|
||||
await _motionService.SafeMoveAsync(_hardware.Axis_PHS_X1, x1,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
for (int y = 0; y < n; y++)
|
||||
{
|
||||
for (int x = 0; x < n; x++)
|
||||
{
|
||||
int index = y % 2 == 0 ? x : n - 1 - x;
|
||||
double waferX = index * waferStep + x2;
|
||||
double waferY = y * waferStep + y1;
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
pointArray[y, index] = await MoveApproachAndCollectAsync(
|
||||
waferX, waferY, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
string.Format("初始网格点 [{0},{1}] = ({2:F4}, {3:F4})。",
|
||||
y, index, pointArray[y, index].X, pointArray[y, index].Y).LogInfo();
|
||||
}
|
||||
}
|
||||
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标定流程内获取点
|
||||
/// </summary>
|
||||
/// <param name="cameraPoints"></param>
|
||||
/// <param name="stepIndex"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<Point[,]> GetApproachCenterPointsAsync(
|
||||
Point[,] cameraPoints, int stepIndex,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
int n = _moduleItem.RowCol;
|
||||
var resultArray = new Point[n, n];
|
||||
|
||||
for (int y = 0; y < n; y++)
|
||||
{
|
||||
for (int x = 0; x < n; x++)
|
||||
{
|
||||
int index = y % 2 == 0 ? x : n - 1 - x;
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
resultArray[y, index] = await MoveApproachAndCollectAsync(
|
||||
cameraPoints[y, index].X, cameraPoints[y, index].Y,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证流程获取初始点
|
||||
/// </summary>
|
||||
/// <param name="waferStep"></param>
|
||||
/// <param name="x2"></param>
|
||||
/// <param name="y1"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<List<Point>> GetInitListPointsAsync(
|
||||
double waferStep, double x2, double y1,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
int n = _moduleItem.VerifyRowCol;
|
||||
await _motionService.SafeMoveAsync(_hardware.Axis_PHS_X1, _moduleItem.X1AvoidancePosition,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var pointArray = new List<Point>();
|
||||
|
||||
for (int y = 0; y < n; y++)
|
||||
{
|
||||
for (int x = 0; x < n; x++)
|
||||
{
|
||||
int index = y % 2 == 0 ? x : n - 1 - x;
|
||||
double waferX = index * waferStep + x2;
|
||||
double waferY = y * waferStep + y1;
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
pointArray.Add(await MoveApproachAndCollectAsync(
|
||||
waferX, waferY, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
}
|
||||
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证流程获取旋转后验证点
|
||||
/// </summary>
|
||||
/// <param name="targetPts"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<List<Point>> MoveAndGetPtsAsync(
|
||||
List<Point> targetPts,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var pointArray = new List<Point>();
|
||||
|
||||
foreach (var pt in targetPts)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
pointArray.Add(await MoveApproachAndCollectAsync(
|
||||
pt.X, pt.Y, cancellationToken).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 逼近对齐
|
||||
/// </summary>
|
||||
private async Task<bool> ApproachAtPointAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
Rectangle1 roiRect = _roiRectProvider?.Invoke();
|
||||
var request = new ApproachAlignmentRequest(
|
||||
axes: new[]
|
||||
{
|
||||
new ApproachAlignmentAxis("X2轴", _moduleItem.AlignTolerance),
|
||||
new ApproachAlignmentAxis("Y1轴", _moduleItem.AlignTolerance)
|
||||
},
|
||||
camera: CameraType.TopPositionCamera)
|
||||
{
|
||||
MaxIterations = 3,
|
||||
RecognitionTimeoutMilliseconds = 5000,
|
||||
RecognitionParameters = new CenterRecognitionParameters()
|
||||
{
|
||||
Type = CenterRecognitionType.EdgeCircle,
|
||||
rectangle = roiRect
|
||||
}
|
||||
};
|
||||
|
||||
var result = await _approachAlignmentService.ApproachAlignmentAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
return result.Succeeded;
|
||||
}
|
||||
|
||||
|
||||
private void ReportProgress(string message, int current, int total)
|
||||
{
|
||||
ProgressChanged?.Invoke(this, new CalibrationProgressEventArgs
|
||||
{
|
||||
Message = message,
|
||||
Current = current,
|
||||
Total = total
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
using JM1.JM1Params;
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.AlgorithmCalib.Service;
|
||||
using MainShell.Common;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Motion;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.ManagerService;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace MainShell.AlgorithmCalib
|
||||
{
|
||||
public class FusionCalibTask : DelegateBase
|
||||
{
|
||||
public Rectangle1 Rectangle { get; set; }
|
||||
|
||||
private HardwareManager _hardware;
|
||||
private FusionCalibParItem _fusionCalibParItem;
|
||||
private List<double> _calibPosList = new List<double>();
|
||||
private SemiconductorVisionAlgorithm.SemiParams.Point[,] _initialwsPos;
|
||||
private Dictionary<int, SemiconductorVisionAlgorithm.SemiParams.Point[,]> _calibResultPointData = new Dictionary<int, SemiconductorVisionAlgorithm.SemiParams.Point[,]>();
|
||||
private FusionCalibMotionService _motion;
|
||||
//private VisionOperation _visionOperation;
|
||||
bool _isCancle = false;
|
||||
private int _calibCount = 0;
|
||||
private bool _isReDo = false;
|
||||
private bool _isWaferCalib = false;
|
||||
private double _initialwsRotate;
|
||||
|
||||
public override bool Check(object state)
|
||||
{
|
||||
_isWaferCalib = _fusionCalibParItem.IsWaferCalib;
|
||||
IoC.Get<IProjectManager>().EnablePageAndDisableOther("视觉标定");
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Do(object state)
|
||||
{
|
||||
try
|
||||
{
|
||||
_isCancle = false;
|
||||
if (_isReDo)
|
||||
{
|
||||
_isReDo = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_calibResultPointData.Clear();
|
||||
_calibPosList.Clear();
|
||||
}
|
||||
var objects = state as object[];
|
||||
_fusionCalibParItem = objects[0] as FusionCalibParItem;
|
||||
|
||||
|
||||
//_visionOperation = IoC.Get<VisionOperation>();
|
||||
|
||||
double waferStep = _fusionCalibParItem.CalibStep;
|
||||
string modelFileName = _fusionCalibParItem.ModelPath;
|
||||
string path = System.AppDomain.CurrentDomain.BaseDirectory + modelFileName;
|
||||
|
||||
if (_calibPosList.Count != _fusionCalibParItem.Count || _calibResultPointData.Count != _fusionCalibParItem.Count)
|
||||
{
|
||||
_calibResultPointData.Clear();
|
||||
_calibPosList.Clear();
|
||||
_calibCount = 0;
|
||||
for (int i = 0; i < _fusionCalibParItem.Count; i++)
|
||||
{
|
||||
_calibPosList.Add(0);
|
||||
_calibResultPointData.Add(i, new SemiconductorVisionAlgorithm.SemiParams.Point[0, 0]);
|
||||
}
|
||||
}
|
||||
|
||||
_initialwsPos = ApprochTable(waferStep, _fusionCalibParItem.MoveAxisPos, _hardware.Axis_Y1.State.ActualPos, _fusionCalibParItem.ApproachXPos, _fusionCalibParItem.ApproachYPos, 0, path);
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = _calibCount; i < _fusionCalibParItem.Count; i++)
|
||||
{
|
||||
if (_isCancle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
double x1, y1, x2, y2 = 0;
|
||||
count++;
|
||||
if (_fusionCalibParItem.IsWaferCalib)
|
||||
{
|
||||
x1 = _fusionCalibParItem.CameraAxisPos + _fusionCalibParItem.Step * i;
|
||||
y1 = _fusionCalibParItem.StartY;
|
||||
|
||||
x2 = _fusionCalibParItem.StartX + _fusionCalibParItem.Step * i;
|
||||
y2 = _hardware.Axis_Y2.State.ActualPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
x1 = _fusionCalibParItem.StartX;
|
||||
y1 = _fusionCalibParItem.CameraAxisPos + _fusionCalibParItem.Step * i;
|
||||
|
||||
x2 = _hardware.Axis_X2.State.ActualPos;
|
||||
y2 = _fusionCalibParItem.StartY + _fusionCalibParItem.Step * i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point[,] points = null;
|
||||
points = ApprochTable(waferStep, x1, y1, x2, y2, count, path);
|
||||
if (_calibResultPointData.ContainsKey(i))
|
||||
{
|
||||
_calibResultPointData[i] = points;
|
||||
}
|
||||
else
|
||||
{
|
||||
_calibResultPointData.Add(i, points);
|
||||
}
|
||||
if (_fusionCalibParItem.IsWaferCalib)
|
||||
{
|
||||
_calibPosList[i] = _hardware.Axis_X1.State.ActualPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
_calibPosList[i] = _hardware.Axis_X1.State.ActualPos;
|
||||
}
|
||||
}
|
||||
if (_fusionCalibParItem.IsWaferCalib)
|
||||
{
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.cal_wafer_fusion_die(_calibResultPointData, _calibPosList, _initialwsPos, _fusionCalibParItem.CalibStep, waferStep, _fusionCalibParItem.CalibCount);
|
||||
string filePath = System.AppDomain.CurrentDomain.BaseDirectory + @"CalibData";
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.Save(filePath);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.cal_wafer_fusion_pad(_fusionCalibParItem.Index,_calibResultPointData, _calibPosList, _initialwsPos, _fusionCalibParItem.CalibStep, waferStep, _fusionCalibParItem.CalibCount);
|
||||
string filePath = System.AppDomain.CurrentDomain.BaseDirectory + @"CalibData";
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.set_center(new SemiconductorVisionAlgorithm.SemiParams.Point(0, 0));
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.Save(filePath);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
var result = MwMessageBox.Show("是否继续?", "继续", MessageBoxButton.YesNo, MessageBoxImage.Information);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
_isReDo = true;
|
||||
this.Do(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
_isReDo = false;
|
||||
}
|
||||
}
|
||||
|
||||
MessageBox.Show("校正完成");
|
||||
}
|
||||
|
||||
|
||||
private SemiconductorVisionAlgorithm.SemiParams.Point[,] ApprochTable(double calibStep, double x1, double y1, double x2, double y2, int count, string path)
|
||||
{
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point[,] pointArray =
|
||||
new SemiconductorVisionAlgorithm.SemiParams.Point[_fusionCalibParItem.CalibCount, _fusionCalibParItem.CalibCount];
|
||||
_motion.MoveWsAvoidance(x2, y1);
|
||||
_motion.MovePhsAvoidance(x1, y2);
|
||||
for (int y = 0; y < _fusionCalibParItem.CalibCount; y++)
|
||||
{
|
||||
double X1, X2, Y1, Y2 = 0;
|
||||
Y1 = y * calibStep + y1;
|
||||
Y2 = y * calibStep + y2;
|
||||
for (int x = 0; x < _fusionCalibParItem.CalibCount; x++)
|
||||
{
|
||||
int index = y % 2 == 0 ? x : _fusionCalibParItem.CalibCount - 1 - x;
|
||||
X2 = index * calibStep + x2;
|
||||
X1 = index * calibStep + x1;
|
||||
if (_isCancle)
|
||||
{
|
||||
return pointArray;
|
||||
}
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point point = new SemiconductorVisionAlgorithm.SemiParams.Point();
|
||||
|
||||
if (_fusionCalibParItem.IsWaferCalib)
|
||||
{
|
||||
_motion.MoveWsAvoidance(X2, Y1);
|
||||
//if (!_visionOperation.ApproachPointCircle(_hardware.TopCameraExtend, _hardware.Axis_X2, _hardware.Axis_Y1, path, Rectangle, out point))
|
||||
//{
|
||||
// Cancel();
|
||||
//}
|
||||
pointArray[index, y] = new SemiconductorVisionAlgorithm.SemiParams.Point(_hardware.Axis_X2.State.ActualPos, _hardware.Axis_Y1.State.ActualPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
_motion.MovePhsAvoidance(X1, Y2);
|
||||
//if (!_visionOperation.ApproachPointCircle(_hardware.TopCameraExtend, _hardware.Axis_X1, _hardware.Axis_Y2, path, Rectangle, out point))
|
||||
//{
|
||||
// Cancel();
|
||||
//}
|
||||
pointArray[index, y] = new SemiconductorVisionAlgorithm.SemiParams.Point(_hardware.Axis_X1.State.ActualPos, _hardware.Axis_Y2.State.ActualPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override void Finish()
|
||||
{
|
||||
base.Finish();
|
||||
IoC.Get<IProjectManager>().SwitchState();
|
||||
}
|
||||
|
||||
public override void Cancel()
|
||||
{
|
||||
_isCancle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
using JM1.JM1Params;
|
||||
using MainShell.AlgorithmCalib.Model;
|
||||
using MainShell.AlgorithmCalib.Service;
|
||||
using MainShell.AlgorithmCalib.ViewModel;
|
||||
using MainShell.Common;
|
||||
using MainShell.Hardware;
|
||||
using MainShell.Motion;
|
||||
using MaxwellFramework.Controls;
|
||||
using MaxwellFramework.Core.Interfaces;
|
||||
using MwFramework.ManagerService;
|
||||
using SemiconductorVisionAlgorithm.SemiCalib;
|
||||
using SemiconductorVisionAlgorithm.SemiParams;
|
||||
using SemiJM1Vision;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Media3D;
|
||||
using Point = SemiconductorVisionAlgorithm.SemiParams.Point;
|
||||
|
||||
namespace MainShell.AlgorithmCalib
|
||||
{
|
||||
public class RotateFormCalibTask : DelegateBase
|
||||
{
|
||||
public Rectangle1 Rectangle { get; set; }
|
||||
|
||||
private HardwareManager _hardware;
|
||||
private RotateCalibParItem _rotateCalibParItem;
|
||||
private SemiconductorVisionAlgorithm.SemiParams.Point[,] _initialwsPos;
|
||||
private List<SemiconductorVisionAlgorithm.SemiParams.Point[,]> _calibWaferData = new List<SemiconductorVisionAlgorithm.SemiParams.Point[,]>();
|
||||
private List<double> _rotatePosList = new List<double>();
|
||||
private RotateMatixFormCalibMotionService _motion;
|
||||
//private VisionOperation _visionOperation;
|
||||
bool _isCancle = false;
|
||||
private bool _isReDo = false;
|
||||
private bool _isVerify = false;
|
||||
private double _initialwsRotate;
|
||||
public override bool Check(object state)
|
||||
{
|
||||
IoC.Get<IProjectManager>().EnablePageAndDisableOther("视觉标定");
|
||||
_hardware = IoC.Get<HardwareManager>();
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Do(object state)
|
||||
{
|
||||
try
|
||||
{
|
||||
// =========== 0. 解析参数 ===========
|
||||
var objects = state as object[];
|
||||
_rotateCalibParItem = objects[0] as RotateCalibParItem;
|
||||
_motion = objects[1] as RotateMatixFormCalibMotionService;
|
||||
_isVerify = Convert.ToBoolean(objects[2]);
|
||||
|
||||
double waferStep = _rotateCalibParItem.Wafer_Step;
|
||||
double verifyWaferStep = _rotateCalibParItem.VerifyWaferStep;
|
||||
_isCancle = false;
|
||||
|
||||
// =========== 1. 初始化视觉 ===========
|
||||
//_visionOperation = IoC.Get<VisionOperation>();
|
||||
|
||||
string modelFileName = _rotateCalibParItem.ModelPath;
|
||||
string path = AppDomain.CurrentDomain.BaseDirectory + modelFileName;
|
||||
|
||||
if (_isReDo)
|
||||
{
|
||||
_isReDo = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_calibWaferData.Clear();
|
||||
_rotatePosList.Clear();
|
||||
}
|
||||
if (!_isVerify)
|
||||
{
|
||||
RotateCalib(waferStep, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
RotateCalibVerify(verifyWaferStep, path);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MwMessageBox.Show(ex.Message);
|
||||
var result = MwMessageBox.Show("是否继续?", "确认",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
_isReDo = true;
|
||||
this.Do(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
_isReDo = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MwMessageBox.Show("校正完成");
|
||||
}
|
||||
|
||||
public void RotateCalib(double waferStep, string path)
|
||||
{
|
||||
// =========== 2. 移动到起始位置,采集初始网格点 ===========
|
||||
_initialwsPos = GetInitPoints(waferStep,
|
||||
_rotateCalibParItem.X1,
|
||||
_rotateCalibParItem.Start_X,
|
||||
_rotateCalibParItem.Start_Y,
|
||||
path);
|
||||
|
||||
_initialwsRotate = _hardware.Axis_WS_R.State.ActualPos;
|
||||
|
||||
// =========== 3. 计算总旋转步数 ===========
|
||||
double rotateStep = _rotateCalibParItem.Rotate_Step;
|
||||
//double negLimit = _hardware.Axis_WS_R.State.负限位;
|
||||
//double posLimit = _hardware.Axis_WS_R.State.正限位;
|
||||
|
||||
double negLimit = 0;
|
||||
double posLimit = 0;
|
||||
|
||||
// 从负限位开始,到正限位结束
|
||||
double startAngle = negLimit;
|
||||
double range = posLimit - startAngle;
|
||||
int totalCount = (int)(range / rotateStep) + 1;
|
||||
if (_rotatePosList.Count != totalCount || _calibWaferData.Count != totalCount)
|
||||
{
|
||||
_calibWaferData.Clear();
|
||||
_rotatePosList.Clear();
|
||||
int n = _rotateCalibParItem.RowCol;
|
||||
for (int i = 0; i < totalCount; i++)
|
||||
{
|
||||
_rotatePosList.Add(0);
|
||||
_calibWaferData.Add(new SemiconductorVisionAlgorithm.SemiParams.Point[n, n]);
|
||||
}
|
||||
}
|
||||
|
||||
// =========== 4. 旋转轴先转到负限位 ===========
|
||||
_motion.SafeMove(_hardware.Axis_WS_R, negLimit);
|
||||
|
||||
// =========== 5. 从负限位开始,逐步旋转到正限位,每步采集网格 ===========
|
||||
for (int stepIndex = 0; stepIndex < totalCount; stepIndex++)
|
||||
{
|
||||
double targetRotate = startAngle + rotateStep * stepIndex;
|
||||
|
||||
if (targetRotate > posLimit)
|
||||
break;
|
||||
|
||||
if (_isCancle) return;
|
||||
|
||||
// 旋转到目标角度
|
||||
_motion.SafeMove(_hardware.Axis_WS_R, targetRotate);
|
||||
_rotatePosList[stepIndex] = _hardware.Axis_WS_R.State.ActualPos;
|
||||
|
||||
int n = _rotateCalibParItem.RowCol;
|
||||
var rotateOffset = targetRotate - _initialwsRotate;
|
||||
var rotateCenterFilePath = "";
|
||||
var resultPts = new SemiconductorVisionAlgorithm.SemiParams.Point[n, n];
|
||||
SemiJM1Manager.Instance.RotatePts(rotateCenterFilePath, _initialwsPos, rotateOffset, out resultPts);
|
||||
// 采集当前角度下的网格点
|
||||
var result_points = GetApproachCenterPoints(resultPts, stepIndex);
|
||||
|
||||
_calibWaferData[stepIndex] = result_points;
|
||||
|
||||
}
|
||||
|
||||
// =========== 6. 融合计算 ===========
|
||||
SemiJM1Vision.SemiJM1Manager.Instance.MakeRotateTable(
|
||||
_calibWaferData, _rotatePosList, _rotateCalibParItem.Rotate_Step);
|
||||
|
||||
// =========== 7. 保存标定数据 ===========
|
||||
string filePath = AppDomain.CurrentDomain.BaseDirectory + @"CalibData";
|
||||
|
||||
|
||||
|
||||
JM1Vision.JM1Manager.Instance.Save(filePath);
|
||||
MwMessageBox.Show("校正完成");
|
||||
}
|
||||
|
||||
public void RotateCalibVerify(double step, string path)
|
||||
{
|
||||
List<Point> initVerifyPts=new List<Point>();
|
||||
double initWsRotate = _hardware.Axis_WS_R.State.ActualPos;
|
||||
double rotateOffset = _rotateCalibParItem.VerifyRotateRange;
|
||||
|
||||
// =========== 2. 获取验证初始点 ===========
|
||||
initVerifyPts = GetInitListPoints(step,
|
||||
_rotateCalibParItem.VerifyStartX,
|
||||
_rotateCalibParItem.VerifyStartY,
|
||||
path);
|
||||
|
||||
// =========== 3. 旋转轴转到目标位置 ===========
|
||||
double targetRotate = initWsRotate + rotateOffset;
|
||||
_motion.SafeMove(_hardware.Axis_WS_R, targetRotate);
|
||||
|
||||
// =========== 4. 调用算法接口进行验证 ===========
|
||||
|
||||
var calPts = new List<Point>();
|
||||
var approachPts= new List<Point>();
|
||||
|
||||
SemiJM1Manager.Instance.GetRotateDstPos(initVerifyPts, initWsRotate, rotateOffset, out calPts);
|
||||
|
||||
approachPts = MoveAndGetPts(calPts);
|
||||
|
||||
// =========== 5. 保存验证数据 ===========
|
||||
string filePath = AppDomain.CurrentDomain.BaseDirectory + "RotateFormVerify.csv";
|
||||
|
||||
RotateMatixFormCalibFileService.SaveVerifyPointsFile(filePath, calPts, approachPts);
|
||||
MwMessageBox.Show("验证完成");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 蛇形扫描网格,返回 Point[RowCol, RowCol]
|
||||
/// [y, 0]~[y, RowCol-1] = 第 y 行的位置点
|
||||
/// </summary>
|
||||
private SemiconductorVisionAlgorithm.SemiParams.Point[,] GetInitPoints(
|
||||
double waferStep, double x1, double y1, double x2, string path)
|
||||
{
|
||||
int n = _rotateCalibParItem.RowCol;
|
||||
var pointArray = new SemiconductorVisionAlgorithm.SemiParams.Point[n, n];
|
||||
|
||||
_motion.SafeMove(_hardware.Axis_X1, x1);
|
||||
_motion.MoveWsAvoidance(x2, y1);
|
||||
|
||||
for (int y = 0; y < n; y++)
|
||||
{
|
||||
for (int x = 0; x < n; x++)
|
||||
{
|
||||
int index = y % 2 == 0 ? x : n - 1 - x;
|
||||
double waferX = index * waferStep + x2;
|
||||
|
||||
if (_isCancle) return pointArray;
|
||||
|
||||
_motion.MoveWsAvoidance(waferX, y * waferStep + y1);
|
||||
|
||||
System.Windows.Point point;
|
||||
//if (!_visionOperation.ApproachPointCircle(
|
||||
// _hardware.TopCameraExtend, _hardware.Axis_PHS_X2, _hardware.Axis_PHS_Y1,
|
||||
// path, Rectangle, out point))
|
||||
//{
|
||||
// Cancel();
|
||||
//}
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
var rulerX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
var rulerY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
|
||||
//var realPoint = GetRealByRuler(rulerX2, rulerY1);
|
||||
|
||||
//pointArray[y, x] = realPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据旋转后的拍照位置,蛇形逐个对齐,返回 Point[RowCol, RowCol]
|
||||
/// </summary>
|
||||
private SemiconductorVisionAlgorithm.SemiParams.Point[,] GetApproachCenterPoints(
|
||||
SemiconductorVisionAlgorithm.SemiParams.Point[,] cameraPoints, int stepIndex)
|
||||
{
|
||||
int n = _rotateCalibParItem.RowCol;
|
||||
var resultArray = new SemiconductorVisionAlgorithm.SemiParams.Point[n, n];
|
||||
|
||||
for (int y = 0; y < n; y++)
|
||||
{
|
||||
for (int x = 0; x < n; x++)
|
||||
{
|
||||
// 蛇形索引,与 ApprochWSTable 保持一致
|
||||
int index = y % 2 == 0 ? x : n - 1 - x;
|
||||
|
||||
if (_isCancle) return resultArray;
|
||||
|
||||
double px = cameraPoints[y, index].X;
|
||||
double py = cameraPoints[y, index].Y;
|
||||
|
||||
//var rulerPoint = GetRulerByReal(new Point(px, py));
|
||||
|
||||
//_motion.MoveWsAvoidance(rulerPoint.X, rulerPoint.Y);
|
||||
|
||||
System.Windows.Point point;
|
||||
//if (!_visionOperation.ApproachPointCircle(
|
||||
// _hardware.TopCameraExtend, _hardware.Axis_PHS_X2, _hardware.Axis_PHS_Y1,
|
||||
// path, Rectangle, out point))
|
||||
//{
|
||||
// Cancel();
|
||||
//}
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
var rulerX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
var rulerY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
|
||||
//var realPoint= GetRealByRuler(rulerX2, rulerY1);
|
||||
|
||||
//// 写入时保持蛇形顺序,与读取顺序一致
|
||||
//resultArray[y, index] = realPoint;
|
||||
}
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 蛇形扫描网格,返回List<Point>
|
||||
/// </summary>
|
||||
private List<SemiconductorVisionAlgorithm.SemiParams.Point> GetInitListPoints(
|
||||
double waferStep, double x2, double y1, string path)
|
||||
{
|
||||
int n = _rotateCalibParItem.VerifyRowCol;
|
||||
_motion.SafeMove(_hardware.Axis_X1, _rotateCalibParItem.X1);
|
||||
_motion.MoveWsAvoidance(x2, y1);
|
||||
|
||||
List<Point> pointArray = new List<Point>();
|
||||
|
||||
for (int y = 0; y < n; y++)
|
||||
{
|
||||
for (int x = 0; x < n; x++)
|
||||
{
|
||||
int index = y % 2 == 0 ? x : n - 1 - x;
|
||||
double waferX = index * waferStep + x2;
|
||||
|
||||
if (_isCancle) return pointArray;
|
||||
|
||||
_motion.MoveWsAvoidance(waferX, y * waferStep + y1);
|
||||
|
||||
System.Windows.Point point;
|
||||
//if (!_visionOperation.ApproachPointCircle(
|
||||
// _hardware.TopCameraExtend, _hardware.Axis_PHS_X2, _hardware.Axis_PHS_Y1,
|
||||
// path, Rectangle, out point))
|
||||
//{
|
||||
// Cancel();
|
||||
//}
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
var rulerX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
var rulerY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
|
||||
//var realPoint= GetRealByRuler(rulerX2,rulerY1);
|
||||
|
||||
//pointArray.Add(realPoint);
|
||||
}
|
||||
}
|
||||
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
private List<Point> MoveAndGetPts(List<Point> targetPts)
|
||||
{
|
||||
var pointArray= new List<Point>();
|
||||
foreach(Point pt in targetPts)
|
||||
{
|
||||
//var rulerPoint = GetRulerByReal(pt);
|
||||
|
||||
//_motion.MoveWsAvoidance(rulerPoint.X, rulerPoint.Y);
|
||||
System.Windows.Point point;
|
||||
//if (!_visionOperation.ApproachPointCircle(
|
||||
// _hardware.TopCameraExtend, _hardware.Axis_PHS_X2, _hardware.Axis_PHS_Y1,
|
||||
// path, Rectangle, out point))
|
||||
//{
|
||||
// Cancel();
|
||||
//}
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
var rulerX2 = _hardware.Axis_X2.State.ActualPos;
|
||||
var rulerY1 = _hardware.Axis_Y1.State.ActualPos;
|
||||
|
||||
//var realPoint = GetRealByRuler(rulerX2, rulerY1);
|
||||
|
||||
//pointArray.Add(realPoint);
|
||||
}
|
||||
return pointArray;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.CameraFusionCalibVerifyView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mwControls="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
xmlns:view="clr-namespace:MainShell.Common.Display.View"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ContentControl Grid.Column="0" Content="{Binding CameraAxisViewModelSevice}"/>
|
||||
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<GroupBox Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="WS运动系标定位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Grid.Row="0" Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="140"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="WS平台标定X1(mm):" Width="200" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Tag="WS平台标定X1" Value="{Binding WsFusionCalibParItem.MoveAxisPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Button Grid.Column="3" Tag="WS平台标定X1-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMoveWSCalibPosPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1.6*"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="1.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="X2:" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.ApproachXPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Label Content="Y1:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.ApproachYPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<!--<Button Grid.Column="5" Tag="WS平台标定X1-中心对齐" Content="中心对齐" Click="{mwControls:Action btnApproachWSCalibPosition}" HorizontalAlignment="Left" />-->
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="2" Style="{StaticResource GroupBoxSecondary}" Margin="3" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="WS运动位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="5" Columns="1">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="StartX(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.StartX}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="StartY(mm):" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.StartY}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="3" Content="设置起点" Click="{mwControls:Action btnMoveToCenter}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="Step(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.Step}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Button Grid.Column="3" Content="移动到起点" Click="{mwControls:Action btnMoveToStartPoint}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="CountX:" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Value="{Binding WsFusionCalibParItem.CountX}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="CountY:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Value="{Binding WsFusionCalibParItem.CountY}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button Content="开始飞拍" Click="{mwControls:Action btnMoveWafer}" Grid.Column="0" Margin="10 5" IsEnabled="{Binding Motion.IsFinish}" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button Content="以当前相机位置验证" Click="{mwControls:Action btnVerifyWafer}" Margin="10 5" IsEnabled="{Binding Motion.IsFinish}" Width="150"/>
|
||||
<Button Content="停止" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnStopVerifyWafer}" HorizontalAlignment="Right"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// CameraFusionCalibVerifyView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CameraFusionCalibVerifyView : UserControl
|
||||
{
|
||||
public CameraFusionCalibVerifyView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
public void CalibVerify()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.CameraFusionCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mwControls="http://www.maxwell-gp.com/"
|
||||
Loaded="{mwControls:Action viewLoad}"
|
||||
Unloaded="{mwControls:Action viewUnLoad}"
|
||||
xmlns:view="clr-namespace:MainShell.Common.Display.View"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="600" d:DesignWidth="800">
|
||||
<!--<UserControl.Resources>
|
||||
--><!--<convert:CameraTypeToBoolConverter x:Key="CameraTypeToBoolConverter"/>--><!--
|
||||
<Style x:Key="CommonLableStyle" TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="120"/>
|
||||
</Style>
|
||||
<Style TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="120"/>
|
||||
</Style>
|
||||
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" >
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="3"/>
|
||||
<Setter Property="Height" Value="35"/>
|
||||
<Setter Property="Width" Value="110"/>
|
||||
</Style>
|
||||
</UserControl.Resources>-->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ContentControl Grid.Column="0" Content="{Binding CameraAxisViewModelSevice}"/>
|
||||
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<GroupBox Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="WS运动系标定位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Grid.Row="0" Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="140"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="WS平台标定X1(mm):" Width="200" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Tag="WS平台标定X1" Value="{Binding WsFusionCalibParItem.MoveAxisPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Button Grid.Column="3" Tag="WS平台标定X1-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMoveWSCalibPosPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1.6*"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="1.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="X2:" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.ApproachXPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Label Content="Y1:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.ApproachYPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Button Grid.Column="5" Tag="WS平台标定X1-中心对齐" Content="中心对齐" Click="{mwControls:Action btnApproachWSCalibPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="1" Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="相机起始位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Grid.Row="0" Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="CameraX(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Center" />
|
||||
<mwControls:NumberBox Tag="CameraX" Value="{Binding WsFusionCalibParItem.CameraAxisPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Center" Margin="5" Width="120" Height="35" />
|
||||
<Button Grid.Column="3" Tag="计算相机起始位置" Content="计算位置" Click="{mwControls:Action btnCalculateCameraPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="1" Tag="相机起始位置-读取当前位置" Content="读取当前位置" Click="{mwControls:Action btnSetCameraPosition}" HorizontalAlignment="Left" />
|
||||
<Button Grid.Column="3" Tag="相机起始位置-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMoveCameraPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="2" Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="WS起始位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="StartX(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.StartX}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="StartY(mm):" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.StartY}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0" Tag="WS起始位置-计算当前位置" Content="计算位置" Click="{mwControls:Action btnCalculateWSPosition}" HorizontalAlignment="Left" Grid.ColumnSpan="2" Margin="3,0,0,0" />
|
||||
<Button Grid.Column="1" Tag="WS起始位置-读取当前位置" Content="读取当前位置" Click="{mwControls:Action btnSetWaferStartPosition}" HorizontalAlignment="Left" Grid.ColumnSpan="2" Margin="3,0,0,0" />
|
||||
<Button Grid.Column="2" Tag="WS起始位置-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMoveWaferStartPosition}" HorizontalAlignment="Left" Margin="2,0,0,0" />
|
||||
<Button Grid.Column="3" Tag="WS起始位置-对齐中心" Content="对齐中心" Click="{mwControls:Action btnMoveToCenter}" HorizontalAlignment="Left" Margin="3,0,0,0" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="3" Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="标定参数" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<Grid >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="1" IsEnabled="{Binding Motion.IsFinish}" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="WaferStepXY(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding WsFusionCalibParItem.CalibStep}" Tag="WaferStepXY(mm)" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="0" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="WaferCountXY:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Value="{Binding WsFusionCalibParItem.CalibCount}" Tag="WaferCountXY" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="0" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid IsEnabled="{Binding Motion.IsFinish}" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="StepX1(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Tag="StepX(mm)" Value="{Binding WsFusionCalibParItem.Step}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="CountX1:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Tag="CountX" Value="{Binding WsFusionCalibParItem.Count}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="1" Maximum="10000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Content="开始" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnStart}" Grid.Column="2" IsEnabled="{Binding Motion.IsFinish}" />
|
||||
<Button Content="停止" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnStop}" Grid.Column="3" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// CameraFusionCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CameraFusionCalibView : UserControl
|
||||
{
|
||||
public CameraFusionCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.CameraFusionPadCalibVerifyView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mwControls="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
xmlns:view="clr-namespace:MainShell.Common.Display.View"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ContentControl Grid.Column="0" Content="{Binding CameraAxisViewModelSevice}"/>
|
||||
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<GroupBox Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="PAD运动系标定位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Grid.Row="0" Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="140"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="PAD平台标定Y1(mm):" Width="200" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Tag="WS平台标定Y1" Value="{Binding PadfusionCalibVerifyParItem.MoveAxisPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Button Grid.Column="3" Tag="WS平台标定X1-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMovePadCalibPosPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1.6*"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="1.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="X1:" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding PadfusionCalibVerifyParItem.ApproachXPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Label Content="Y2:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding PadfusionCalibVerifyParItem.ApproachYPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<!--<Button Grid.Column="5" Tag="WS平台标定X1-中心对齐" Content="中心对齐" Click="{mwControls:Action btnApproachWSCalibPosition}" HorizontalAlignment="Left" />-->
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="2" Style="{StaticResource GroupBoxSecondary}" Margin="3" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="PAD运动位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="5" Columns="1">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="StartX(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding PadfusionCalibVerifyParItem.StartX}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="StartY(mm):" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding PadfusionCalibVerifyParItem.StartY}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="3" Content="设置起点" Click="{mwControls:Action btnMoveToCenter}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="Step(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding PadfusionCalibVerifyParItem.Step}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Button Grid.Column="3" Content="移动到起点" Click="{mwControls:Action btnMoveToStartPoint}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="CountX:" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Value="{Binding PadfusionCalibVerifyParItem.CountX}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="CountY:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Value="{Binding PadfusionCalibVerifyParItem.CountY}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button Content="开始飞拍" Click="{mwControls:Action btnMovePad}" Grid.Column="0" Margin="10 5" IsEnabled="{Binding Motion.IsFinish}" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<Button Content="以当前相机位置验证" Click="{mwControls:Action btnVerifyPad}" Margin="10 5" IsEnabled="{Binding Motion.IsFinish}" Width="150"/>
|
||||
<Button Content="停止" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnStopVerifyPad}" HorizontalAlignment="Right"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// CameraFusionPadCalibVerifyView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CameraFusionPadCalibVerifyView : UserControl
|
||||
{
|
||||
public CameraFusionPadCalibVerifyView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.CameraFusionPadCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
mc:Ignorable="d"
|
||||
xmlns:mwControls="http://www.maxwell-gp.com/"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ContentControl Grid.Column="0" Content="{Binding CameraAxisViewModelSevice}"/>
|
||||
|
||||
<Grid Grid.Column="1">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<GroupBox Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="PHS运动系标定位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Grid.Row="0" Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="140"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="PHS平台标定Y1(mm):" Width="200" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Tag="PHS平台标定Y1" Value="{Binding FusionCalibParItem.MoveAxisPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Button Grid.Column="3" Tag="PHS平台标定Y1-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMovePhsCalibPosPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1.6*"/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition Width="1.5*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="X1:" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding FusionCalibParItem.ApproachXPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Label Content="Y2:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding FusionCalibParItem.ApproachYPos}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="75" Height="35" />
|
||||
<Button Grid.Column="5" Tag="WS平台标定X1-中心对齐" Content="中心对齐" Click="{mwControls:Action btnApproachPhsCalibPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="1" Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="相机起始位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Grid.Row="0" Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="CameraX(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Center" />
|
||||
<mwControls:NumberBox Tag="CameraX" Value="{Binding FusionCalibParItem.CameraAxisPos}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Center" Margin="5" Width="120" Height="35" />
|
||||
<Button Grid.Column="3" Tag="计算相机起始位置" Content="计算位置" Click="{mwControls:Action btnCalculateCameraPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="1" Tag="相机起始位置-读取当前位置" Content="读取当前位置" Click="{mwControls:Action btnSetCameraPosition}" HorizontalAlignment="Left" />
|
||||
<Button Grid.Column="3" Tag="相机起始位置-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMoveCameraPosition}" HorizontalAlignment="Left" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="2" Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" IsEnabled="{Binding Motion.IsFinish}" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="PHS起始位置" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<UniformGrid Rows="2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="StartX(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding FusionCalibParItem.StartX}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="StartY(mm):" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding FusionCalibParItem.StartY}" IsReadOnly="True" Background="LightGray" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0" Tag="WS起始位置-计算当前位置" Content="计算位置" Click="{mwControls:Action btnCalculatePhsPosition}" HorizontalAlignment="Left" Grid.ColumnSpan="2" Margin="3,0,0,0" />
|
||||
<Button Grid.Column="1" Tag="WS起始位置-读取当前位置" Content="读取当前位置" Click="{mwControls:Action btnSetStageStartPosition}" HorizontalAlignment="Left" Grid.ColumnSpan="2" Margin="3,0,0,0" />
|
||||
<Button Grid.Column="2" Tag="WS起始位置-移到此位置" Content="移到此位置" Click="{mwControls:Action btnMoveStageStartPosition}" HorizontalAlignment="Left" Margin="2,0,0,0" />
|
||||
<Button Grid.Column="3" Tag="WS起始位置-对齐中心" Content="对齐中心" Click="{mwControls:Action btnMoveToCenter}" HorizontalAlignment="Left" Margin="3,0,0,0" />
|
||||
</Grid>
|
||||
</UniformGrid>
|
||||
</GroupBox>
|
||||
<GroupBox Grid.Row="3" Style="{StaticResource GroupBoxSecondary}" Margin="3,3,3,3" Grid.ColumnSpan="2">
|
||||
<GroupBox.Header>
|
||||
<TextBlock Text="标定参数" VerticalAlignment="Center" FontWeight="Bold" />
|
||||
</GroupBox.Header>
|
||||
<Grid >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="1" IsEnabled="{Binding Motion.IsFinish}" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="WaferStepXY(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Value="{Binding FusionCalibParItem.CalibStep}" Tag="WaferStepXY(mm)" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="0" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="WaferCountXY:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Value="{Binding FusionCalibParItem.CalibCount}" Tag="WaferCountXY" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="0" Maximum="1000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid IsEnabled="{Binding Motion.IsFinish}" >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Content="StepX1(mm):" Grid.Column="0" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:NumberBox Tag="StepX(mm)" Value="{Binding FusionCalibParItem.Step}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="-1000" Maximum="1000" Grid.Column="1" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
<Label Content="CountX1:" Grid.Column="2" Style="{StaticResource CommonLableStyle}" HorizontalAlignment="Right" />
|
||||
<mwControls:IntNumberBox Tag="CountX" Value="{Binding FusionCalibParItem.Count}" mwControls:NumericKeypadAttach.IsEnabled="True" Minimum="1" Maximum="10000" Grid.Column="3" HorizontalAlignment="Left" Margin="5" Width="120" Height="35" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Content="开始" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnStart}" Grid.Column="2" IsEnabled="{Binding Motion.IsFinish}" />
|
||||
<Button Content="停止" Tag="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Content}" Click="{mwControls:Action btnStop}" Grid.Column="3" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// CameraFusionPadCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class CameraFusionPadCalibView : UserControl
|
||||
{
|
||||
public CameraFusionPadCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.DistortionCorrectionCalibContentsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="50"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- 顶部导航栏 -->
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA" BorderThickness="0,0,0,1" Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="当前标定:" VerticalAlignment="Center" FontSize="13" Foreground="#7A8FA6"/>
|
||||
<TextBlock Text="{Binding CurrentCalibName}" VerticalAlignment="Center"
|
||||
FontSize="13" FontWeight="SemiBold" Foreground="#2D3748" Margin="0,0,16,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding ProgressText}" VerticalAlignment="Center"
|
||||
FontSize="12" Foreground="#A0AEC0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- 内容区 -->
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<ContentControl mw:View.Model="{Binding ShowScreenVM}"/>
|
||||
</ScrollViewer>
|
||||
<!-- 底部导航按钮 -->
|
||||
<Border Grid.Row="2" Background="White" BorderBrush="#E0E4EA" BorderThickness="0,1,0,0" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="上一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding PrevCommand}" IsEnabled="{Binding IsEnablePrev}"/>
|
||||
<Button Content="下一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding NextCommand}" IsEnabled="{Binding IsEnableNext}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// DistortionCorrectionCalibContentsView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class DistortionCorrectionCalibContentsView : UserControl
|
||||
{
|
||||
public DistortionCorrectionCalibContentsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.DistortionCorrectionCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mwFramework="clr-namespace:MwFramework.Controls.SystemCalib;assembly=MwFramework.Controls.SystemCalib"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<mwFramework:DistortionCorrectionCalibControl DataContext="{Binding Service}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// DistortionCorrectionCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class DistortionCorrectionCalibView : UserControl
|
||||
{
|
||||
public DistortionCorrectionCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,713 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.DieFusionCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="800" d:DesignWidth="1200">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
|
||||
<Style x:Key="VerifyButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#2B6CB0"/>
|
||||
<Setter Property="BorderBrush" Value="#2B6CB0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2C5282"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#1A365D"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ModuleCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<DropShadowEffect Color="#000000" Opacity="0.06" BlurRadius="8" ShadowDepth="2"
|
||||
Direction="270"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SectionHeaderTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ParamLabelStyle" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#4A5568"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ParamNumberBoxStyle" TargetType="mw:NumberBox">
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="6,2"/>
|
||||
<Setter Property="Minimum" Value="-99999"/>
|
||||
<Setter Property="Maximum" Value="99999"/>
|
||||
<Setter Property="DecimalPlaces" Value="3"/>
|
||||
<Setter Property="Foreground" Value="#1568D5"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ReadOnlyNumberBoxStyle" TargetType="mw:NumberBox" BasedOn="{StaticResource
|
||||
ParamNumberBoxStyle}">
|
||||
<Setter Property="IsReadOnly" Value="True"/>
|
||||
<Setter Property="Background" Value="#F0F4F8"/>
|
||||
<Setter Property="Foreground" Value="#4A5568"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IntParamNumberBoxStyle" TargetType="mw:IntNumberBox">
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="6,2"/>
|
||||
<Setter Property="mw:NumericKeypadAttach.IsEnabled" Value="True"/>
|
||||
<Setter Property="Minimum" Value="0"/>
|
||||
<Setter Property="Maximum" Value="1000"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SmallActionButtonStyle" TargetType="Button">
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Padding" Value="10,0"/>
|
||||
<Setter Property="Margin" Value="4,2"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bd" Background="#EDF2F7" BorderBrush="#CBD5E0"
|
||||
BorderThickness="1" CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#CBD5E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="bd" Property="Background" Value="#F7FAFC"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StartButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#1A202C"/>
|
||||
<Setter Property="BorderBrush" Value="#1A202C"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2D3748"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#0F141B"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StopButtonStyle" TargetType="Button" BasedOn="{StaticResource
|
||||
BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#E53E3E"/>
|
||||
<Setter Property="BorderBrush" Value="#E53E3E"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#C53030"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#9B2C2C"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ==================== 左侧:相机预览 ==================== -->
|
||||
<Border Grid.Column="0" Margin="0,0,4,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0" Padding="10,0">
|
||||
<Grid>
|
||||
<TextBlock Text="相机预览"
|
||||
Foreground="#7A8FA6"
|
||||
FontSize="11"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center">
|
||||
<Ellipse Width="7" Height="7" Fill="#28A745" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="LIVE" Foreground="#28A745" FontSize="10" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ContentControl Grid.Row="1" Content="{Binding CameraAxisViewModelSevice}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ==================== 右侧:Tab切换 ==================== -->
|
||||
<Grid Grid.Column="1">
|
||||
<TabControl>
|
||||
<!-- ====== Tab 1:标定 ====== -->
|
||||
<TabItem Header="标定">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
CanContentScroll="False"
|
||||
PanningMode="VerticalOnly"
|
||||
Padding="8,8,8,0">
|
||||
<StackPanel>
|
||||
|
||||
<!-- ====== 卡片 1:WS运动系标定位置 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#E8821A" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="WS运动系标定位置"
|
||||
Foreground="#E8821A"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="WS平台标定X1(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.MoveAxisPos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="80"/>
|
||||
<Button Grid.Column="2"
|
||||
Content="移到此位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveWSCalibPosPosition}"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="40"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="X2:"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.ApproachXPos}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="80"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="Y1:"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding WsFusionCalibParItem.ApproachYPos}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="80"/>
|
||||
<Button Grid.Column="4"
|
||||
Content="中心对齐"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnApproachWSCalibPosition}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 2:相机起始位置 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="相机起始位置"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="CameraX(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.CameraAxisPos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
<Button Grid.Column="2"
|
||||
Content="计算位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnCalculateCameraPosition}"/>
|
||||
<Button Grid.Column="3"
|
||||
Content="读取当前位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnSetCameraPosition}"/>
|
||||
<Button Grid.Column="4"
|
||||
Content="移到此位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveCameraPosition}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 3:WS起始位置 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="WS起始位置"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="StartX(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.StartX}"
|
||||
Style="{StaticResource ReadOnlyNumberBoxStyle}"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="StartY(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding WsFusionCalibParItem.StartY}"
|
||||
Style="{StaticResource ReadOnlyNumberBoxStyle}"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
|
||||
<Button Content="计算位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnCalculateWSPosition}"/>
|
||||
<Button Content="读取当前位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnSetWaferStartPosition}"/>
|
||||
<Button Content="移到此位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveWaferStartPosition}"/>
|
||||
<Button Content="对齐中心"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveToCenter}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 4:标定参数 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="标定参数"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="WaferStepXY(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.CalibStep, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="WaferCountXY:"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:IntNumberBox Grid.Column="3"
|
||||
Value="{Binding WsFusionCalibParItem.CalibCount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="StepX1(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.Step, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="CountX1:"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:IntNumberBox Grid.Column="3"
|
||||
Value="{Binding WsFusionCalibParItem.Count, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Minimum="1"
|
||||
Maximum="10000"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
|
||||
Margin="0,8,0,0">
|
||||
<Button Content="开始"
|
||||
Click="{mw:Action btnStart}"
|
||||
Style="{StaticResource StartButtonStyle}"
|
||||
IsEnabled="{Binding Motion.IsFinish}"/>
|
||||
<Button Content="停止"
|
||||
Click="{mw:Action btnStop}"
|
||||
Style="{StaticResource StopButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<!-- ====== Tab 2:验证 ====== -->
|
||||
<TabItem Header="验证">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
CanContentScroll="False"
|
||||
PanningMode="VerticalOnly"
|
||||
Padding="8,8,8,0">
|
||||
<StackPanel>
|
||||
|
||||
<!-- ====== 卡片 1:WS运动系标定位置 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#E8821A" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="WS运动系验证位置"
|
||||
Foreground="#E8821A"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="WS平台标定X1(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.MoveAxisPos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="80"/>
|
||||
<Button Grid.Column="2"
|
||||
Content="移到此位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveWSCalibPosPosition}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 2:WS运动位置(验证) ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="WS运动位置"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<!-- 起点坐标 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="StartX(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.WaferStartVerifyX}"
|
||||
Style="{StaticResource ReadOnlyNumberBoxStyle}"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="StartY(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding WsFusionCalibParItem.WaferStartVerifyY}"
|
||||
Style="{StaticResource ReadOnlyNumberBoxStyle}"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 设置起点 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Grid.Column="1" Content="设置起点"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveToCenter}"/>
|
||||
<Button Grid.Column="3"
|
||||
Content="移动到起点"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveToStartPoint}"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<!-- Step + 移动到起点 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="Step(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.WaferVerityStep}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- Count X / Y -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="CountX:"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:IntNumberBox Grid.Column="1"
|
||||
Value="{Binding WsFusionCalibParItem.WaferVerityCountX}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="CountY:"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:IntNumberBox Grid.Column="3"
|
||||
Value="{Binding WsFusionCalibParItem.WaferVerityCountY}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 飞拍 + 验证按钮 -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
|
||||
Margin="0,8,0,0">
|
||||
<Button Content="开始飞拍"
|
||||
Click="{mw:Action btnMoveWafer}"
|
||||
Style="{StaticResource StartButtonStyle}"
|
||||
IsEnabled="{Binding Motion.IsFinish}"/>
|
||||
<Button Content="以当前相机位置验证"
|
||||
Click="{mw:Action btnVerityWafer}"
|
||||
Style="{StaticResource VerifyButtonStyle}"
|
||||
Width="150"
|
||||
IsEnabled="{Binding Motion.IsFinish}"/>
|
||||
<Button Content="停止"
|
||||
Click="{mw:Action btnStopVerityWafer}"
|
||||
Style="{StaticResource StopButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Grid>
|
||||
|
||||
<customControl:LoadingWaitView Grid.ColumnSpan="2" Panel.ZIndex="1000"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// DieFusionCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class DieFusionCalibView : UserControl
|
||||
{
|
||||
public DieFusionCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
<UserControl x:Class="MainShell.PageCalib.AlgorithmCalib.View.FusionCalib.FusionAlignVerifyView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.PageCalib.AlgorithmCalib.View.FusionCalib"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="800" d:DesignWidth="1200">
|
||||
<UserControl.Resources>
|
||||
<!-- 复用标定页面的样式 -->
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
<Style x:Key="StartButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#1A202C"/>
|
||||
<Setter Property="BorderBrush" Value="#1A202C"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2D3748"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#0F141B"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="VerifyButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#2B6CB0"/>
|
||||
<Setter Property="BorderBrush" Value="#2B6CB0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2C5282"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#1A365D"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StopButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#E53E3E"/>
|
||||
<Setter Property="BorderBrush" Value="#E53E3E"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#C53030"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#9B2C2C"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ModuleCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<DropShadowEffect Color="#000000" Opacity="0.06" BlurRadius="8" ShadowDepth="2" Direction="270"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SectionHeaderTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ParamLabelStyle" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#4A5568"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ReadOnlyNumberBoxStyle" TargetType="mw:NumberBox">
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="6,2"/>
|
||||
<Setter Property="IsReadOnly" Value="True"/>
|
||||
<Setter Property="Background" Value="#F0F4F8"/>
|
||||
<Setter Property="Foreground" Value="#4A5568"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SmallActionButtonStyle" TargetType="Button">
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Padding" Value="10,0"/>
|
||||
<Setter Property="Margin" Value="4,2"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bd" Background="#EDF2F7" BorderBrush="#CBD5E0"
|
||||
BorderThickness="1" CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#CBD5E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="bd" Property="Background" Value="#F7FAFC"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StepButtonStyle" TargetType="Button">
|
||||
<Setter Property="Width" Value="120"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,8,0"/>
|
||||
<Setter Property="Background" Value="#2B6CB0"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#2B6CB0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2C5282"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#1A365D"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="#A0AEC0"/>
|
||||
<Setter Property="BorderBrush" Value="#A0AEC0"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ==================== 左侧:相机预览 ==================== -->
|
||||
<Border Grid.Column="0" Margin="0,0,4,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Row="0" Padding="10,0">
|
||||
<Grid>
|
||||
<TextBlock Text="相机预览" Foreground="#7A8FA6" FontSize="11"
|
||||
FontWeight="SemiBold" VerticalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Ellipse Width="7" Height="7" Fill="#28A745" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="LIVE" Foreground="#28A745" FontSize="10" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ContentControl Grid.Row="1" Content="{Binding CameraAxisViewModelSevice}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ==================== 右侧:对位流程(3步) ==================== -->
|
||||
<Grid Grid.Column="1">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled"
|
||||
CanContentScroll="False" PanningMode="VerticalOnly" Padding="8,8,8,0">
|
||||
<StackPanel>
|
||||
|
||||
<!-- ====== 步骤1:抓Pad点 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Row="0" Background="#F7F9FC" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" CornerRadius="6,6,0,0" Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2B6CB0" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="第一步:抓Pad点(目标Pad)" Foreground="#2B6CB0" Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="框选ROI区域,识别Pad目标点坐标" Foreground="#718096" FontSize="11" Margin="6,0,0,8"/>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="Pad X1(mm):" Style="{StaticResource ParamLabelStyle}" Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1" Value="{Binding PadCapturedX}" Style="{StaticResource ReadOnlyNumberBoxStyle}"/>
|
||||
<TextBlock Grid.Column="2" Text="Pad Y2(mm):" Style="{StaticResource ParamLabelStyle}" Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="3" Value="{Binding PadCapturedY}" Style="{StaticResource ReadOnlyNumberBoxStyle}"/>
|
||||
<Button Grid.Column="4" Content="抓Pad点" Style="{StaticResource VerifyButtonStyle}" Click="{mw:Action btnCapturePad}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 步骤2:Die网格飞拍 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Row="0" Background="#F7F9FC" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" CornerRadius="6,6,0,0" Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2B6CB0" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="第二步:Die网格飞拍" Foreground="#2B6CB0" Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="框选ROI抓Die首点,设置飞拍参数后执行网格扫描" Foreground="#718096" FontSize="11" Margin="6,0,0,8"/>
|
||||
<!-- 首点坐标 + 抓Die首点按钮 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="首点 X2(mm):" Style="{StaticResource ParamLabelStyle}" Margin="6,0"/>
|
||||
<mw:NumberBox Width="80" Grid.Column="1" Value="{Binding DieFirstX}" Style="{StaticResource ReadOnlyNumberBoxStyle}"/>
|
||||
<TextBlock Grid.Column="2" Text="首点 Y1(mm):" Style="{StaticResource ParamLabelStyle}" Margin="6,0"/>
|
||||
<mw:NumberBox Width="80" Grid.Column="3" Value="{Binding DieFirstY}" Style="{StaticResource ReadOnlyNumberBoxStyle}"/>
|
||||
<Button Grid.Column="4" Content="抓Die首点" Style="{StaticResource VerifyButtonStyle}" Click="{mw:Action btnCaptureDieFirst}"/>
|
||||
</Grid>
|
||||
<!-- 飞拍参数 -->
|
||||
<Grid Margin="0,6,0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="X Count:" Style="{StaticResource ParamLabelStyle}" Margin="6,0"/>
|
||||
<mw:IntNumberBox Grid.Row="0" Grid.Column="1" Value="{Binding FlyScanXCount}" Width="80" Height="28" Margin="6,2"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="2" Text="Y Count:" Style="{StaticResource ParamLabelStyle}" Margin="6,0"/>
|
||||
<mw:IntNumberBox Grid.Row="0" Grid.Column="3" Value="{Binding FlyScanYCount}" Width="80" Height="28" Margin="6,2"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Step(mm):" Style="{StaticResource ParamLabelStyle}" Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Row="1" Grid.Column="1" Value="{Binding FlyScanStep}" Width="80" Height="28" Margin="6,2"/>
|
||||
</Grid>
|
||||
<!-- 飞拍按钮 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,6,0,0">
|
||||
<Button Content="开始飞拍" Style="{StaticResource VerifyButtonStyle}" Click="{mw:Action btnStartFlyScan}"/>
|
||||
<Button Content="停止" Style="{StaticResource StopButtonStyle}" Click="{mw:Action btnStopAlign}" Width="80"/>
|
||||
</StackPanel>
|
||||
<!-- 飞拍结果 -->
|
||||
<TextBlock Text="{Binding FlyScanResultText}" Foreground="#2D3748" FontSize="12" Margin="6,8,0,4"/>
|
||||
<DataGrid ItemsSource="{Binding DisplayDieGridPoints}"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
CanUserAddRows="False"
|
||||
CanUserDeleteRows="False"
|
||||
Height="120"
|
||||
Margin="0,2"
|
||||
FontSize="11"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="行" Binding="{Binding Row}" Width="50"/>
|
||||
<DataGridTextColumn Header="列" Binding="{Binding Col}" Width="50"/>
|
||||
<DataGridTextColumn Header="X2(mm)" Binding="{Binding X, StringFormat=F4}" Width="100"/>
|
||||
<DataGridTextColumn Header="Y1(mm)" Binding="{Binding Y, StringFormat=F4}" Width="100"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 步骤3:对位验证 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Row="0" Background="#F7F9FC" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" CornerRadius="6,6,0,0" Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#38A169" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="第三步:对位验证" Foreground="#38A169" Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="选择Die网格中的一点,与Pad点执行对位" Foreground="#718096" FontSize="11" Margin="6,0,0,8"/>
|
||||
<!-- 行列选择 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="选择行(Row):" Style="{StaticResource ParamLabelStyle}" Margin="6,0"/>
|
||||
<mw:IntNumberBox Grid.Column="1" Value="{Binding SelectedRow}" Width="80" Height="28" Margin="6,2"/>
|
||||
<TextBlock Grid.Column="2" Text="选择列(Col):" Style="{StaticResource ParamLabelStyle}" Margin="6,0"/>
|
||||
<mw:IntNumberBox Grid.Column="3" Value="{Binding SelectedCol}" Width="80" Height="28" Margin="6,2"/>
|
||||
<Button Grid.Column="4" Content="执行对位" Style="{StaticResource VerifyButtonStyle}" Click="{mw:Action btnExecuteAlign}"/>
|
||||
</Grid>
|
||||
<!-- 对位结果 -->
|
||||
<Border Background="#F7FAFC" BorderBrush="#E2E8F0" BorderThickness="1" CornerRadius="4" Margin="0,8,0,4" Padding="8,6">
|
||||
<StackPanel>
|
||||
<TextBlock Text="对位结果" Foreground="#4A5568" FontSize="11" FontWeight="SemiBold" Margin="0,0,0,4"/>
|
||||
<TextBlock Text="{Binding AlignResultText}" Foreground="#2D3748" FontSize="12" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 进度 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" Visibility="{Binding IsRunning, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel Margin="10,8">
|
||||
<TextBlock Text="{Binding ProgressMessage}" Foreground="#4A5568" FontSize="12"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<customControl:LoadingWaitView Grid.ColumnSpan="2" Panel.ZIndex="1000"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.PageCalib.AlgorithmCalib.View.FusionCalib
|
||||
{
|
||||
/// <summary>
|
||||
/// FusionAlignVerifyView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class FusionAlignVerifyView : UserControl
|
||||
{
|
||||
public FusionAlignVerifyView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.FusionCalibContentsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="50"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="当前标定:" VerticalAlignment="Center" FontSize="13" Foreground="#7A8FA6"/>
|
||||
<TextBlock Text="{Binding CurrentCalibName}" VerticalAlignment="Center"
|
||||
FontSize="13" FontWeight="SemiBold" Foreground="#2D3748" Margin="0,0,16,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding ProgressText}" VerticalAlignment="Center"
|
||||
FontSize="12" Foreground="#A0AEC0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<ContentControl mw:View.Model="{Binding ShowScreenVM}"/>
|
||||
</ScrollViewer>
|
||||
<Border Grid.Row="2" Background="White" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,1,0,0" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="上一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding PrevCommand}" IsEnabled="{Binding IsEnablePrev}"/>
|
||||
<Button Content="下一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding NextCommand}" IsEnabled="{Binding IsEnableNext}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// FusionCalibContentsView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class FusionCalibContentsView : UserControl
|
||||
{
|
||||
public FusionCalibContentsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.FusionMultipleCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="800" d:DesignWidth="1200">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
|
||||
<Style x:Key="ModuleCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<DropShadowEffect Color="#000000" Opacity="0.06" BlurRadius="8" ShadowDepth="2" Direction="270"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SectionHeaderTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="BadgeStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="3"/>
|
||||
<Setter Property="Padding" Value="5,1"/>
|
||||
<Setter Property="Margin" Value="3,0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SmallActionButtonStyle" TargetType="Button">
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Padding" Value="10,0"/>
|
||||
<Setter Property="Margin" Value="4,2"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bd" Background="#EDF2F7" BorderBrush="#CBD5E0"
|
||||
BorderThickness="1" CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#CBD5E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="bd" Property="Background" Value="#F7FAFC"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StartCalibButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="120"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,10,0"/>
|
||||
<Setter Property="Background" Value="#1A202C"/>
|
||||
<Setter Property="BorderBrush" Value="#1A202C"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2D3748"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#0F141B"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ModuleWriteButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="4,0"/>
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrange}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrange}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrangeHover}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrangeHover}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrangePressed}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrangePressed}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 左侧:相机预览 -->
|
||||
<Border Grid.Column="0" Margin="0,0,4,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Row="0" Padding="10,0">
|
||||
<Grid>
|
||||
<TextBlock Text="相机预览" Foreground="#7A8FA6" FontSize="11"
|
||||
FontWeight="SemiBold" VerticalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Ellipse Width="7" Height="7" Fill="#28A745" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="LIVE" Foreground="#28A745" FontSize="10" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ContentControl Grid.Row="1" Content="{Binding CameraAxisViewModelService}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- 右侧:工具栏 + 标定卡片 -->
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 顶部工具栏 -->
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="读取标定数据" Command="{mw:Action btnReadCalibData}"
|
||||
Style="{StaticResource SmallActionButtonStyle}" Width="110" Height="34" Margin="5,0"/>
|
||||
<Button Content="保存标定数据" Command="{mw:Action btnSaveCalibData}"
|
||||
Style="{StaticResource SmallActionButtonStyle}" Width="110" Height="34" Margin="5,0"/>
|
||||
<Button Content="应用标定数据" Command="{mw:Action btnApplyCalibData}"
|
||||
Style="{StaticResource ModuleWriteButtonStyle}" Width="110" Height="34" Margin="5,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 标定卡片 -->
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled" CanContentScroll="False"
|
||||
PanningMode="VerticalOnly" Padding="8,8,8,0">
|
||||
<Border Style="{StaticResource ModuleCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<Border Grid.Row="0" Background="#F7F9FC" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" CornerRadius="6,6,0,0" Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="[] " Foreground="#8892A0" FontSize="14" VerticalAlignment="Center"/>
|
||||
<TextBlock FontWeight="SemiBold" FontSize="13" Foreground="#2D3748" VerticalAlignment="Center">
|
||||
<Run Text="融合标定数据"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Border Style="{StaticResource BadgeStyle}" Background="#EDF2F7">
|
||||
<TextBlock Text="4区域融合" FontSize="10" Foreground="#718096"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Section 1: 标定参数表格 -->
|
||||
<Border Grid.Row="1" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="标定区域参数" Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<DataGrid ItemsSource="{Binding FusionCalibParItem}"
|
||||
SelectedItem="{Binding SelectedCalibPar}"
|
||||
Margin="0,4" Height="200"
|
||||
AutoGenerateColumns="false" SelectionMode="Single"
|
||||
CanUserSortColumns="False" HeadersVisibility="Column"
|
||||
GridLinesVisibility="Horizontal"
|
||||
HorizontalGridLinesBrush="#F0F4F8"
|
||||
BorderBrush="#E0E4EA" BorderThickness="1"
|
||||
RowBackground="White" AlternatingRowBackground="#FAFBFC"
|
||||
RowHeight="28">
|
||||
<DataGrid.ColumnHeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="#F7F9FC"/>
|
||||
<Setter Property="Foreground" Value="#8892A0"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Padding" Value="8,4"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,0,1"/>
|
||||
</Style>
|
||||
</DataGrid.ColumnHeaderStyle>
|
||||
<DataGrid.CellStyle>
|
||||
<Style TargetType="DataGridCell">
|
||||
<Setter Property="Padding" Value="8,2"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#EBF5FF"/>
|
||||
<Setter Property="Foreground" Value="#1568D5"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.CellStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="序号" IsReadOnly="True" Binding="{Binding Index}" Width="50"/>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="Y1(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding MoveAxisPos, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="X1(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding ApproachXPos, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="Y2(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding ApproachYPos, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="StartX(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding StartX, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="StartY(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding StartY, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="步长(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding Step, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="行列数"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding Count}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Section 2: 操作按钮 -->
|
||||
<Border Grid.Row="2" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2B6CB0" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="标定操作" Foreground="#2B6CB0" Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="打开标定窗口" Command="{mw:Action btnOpenCalibWindow}"
|
||||
Style="{StaticResource StartCalibButtonStyle}" Width="120"/>
|
||||
<TextBlock Text="选择一行数据后打开对应标定窗口"
|
||||
Foreground="#A0AEC0" FontSize="11" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Footer -->
|
||||
<Border Grid.Row="3" BorderBrush="#E0E4EA" BorderThickness="0,1,0,0"
|
||||
Background="#FAFBFC" CornerRadius="0,0,6,6" Padding="10,0">
|
||||
<TextBlock Text="共 4 个标定区域" Foreground="#A0AEC0" FontSize="11"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<customControl:LoadingWaitView Grid.ColumnSpan="2" Panel.ZIndex="1000"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// FusionMultipleCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class FusionMultipleCalibView : UserControl
|
||||
{
|
||||
public FusionMultipleCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,711 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.PadFusionCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="800" d:DesignWidth="1200"
|
||||
Loaded="{mw:Action viewLoad}"
|
||||
Unloaded="{mw:Action viewUnLoad}">
|
||||
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
|
||||
<Style x:Key="VerifyButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#2B6CB0"/>
|
||||
<Setter Property="BorderBrush" Value="#2B6CB0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2C5282"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#1A365D"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ModuleCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<DropShadowEffect Color="#000000" Opacity="0.06" BlurRadius="8" ShadowDepth="2"
|
||||
Direction="270"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SectionHeaderTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ParamLabelStyle" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#4A5568"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ParamNumberBoxStyle" TargetType="mw:NumberBox">
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="6,2"/>
|
||||
<Setter Property="mw:NumericKeypadAttach.IsEnabled" Value="True"/>
|
||||
<Setter Property="Minimum" Value="-99999"/>
|
||||
<Setter Property="Maximum" Value="99999"/>
|
||||
<Setter Property="DecimalPlaces" Value="3"/>
|
||||
<Setter Property="Foreground" Value="#1568D5"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ReadOnlyNumberBoxStyle" TargetType="mw:NumberBox">
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="6,2"/>
|
||||
<Setter Property="mw:NumericKeypadAttach.IsEnabled" Value="True"/>
|
||||
<Setter Property="Minimum" Value="-99999"/>
|
||||
<Setter Property="Maximum" Value="99999"/>
|
||||
<Setter Property="DecimalPlaces" Value="3"/>
|
||||
<Setter Property="IsReadOnly" Value="True"/>
|
||||
<Setter Property="Background" Value="#F0F4F8"/>
|
||||
<Setter Property="Foreground" Value="#4A5568"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IntParamNumberBoxStyle" TargetType="mw:IntNumberBox">
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="6,2"/>
|
||||
<Setter Property="mw:NumericKeypadAttach.IsEnabled" Value="True"/>
|
||||
<Setter Property="Minimum" Value="0"/>
|
||||
<Setter Property="Maximum" Value="1000"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SmallActionButtonStyle" TargetType="Button">
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Padding" Value="10,0"/>
|
||||
<Setter Property="Margin" Value="4,2"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bd" Background="#EDF2F7" BorderBrush="#CBD5E0"
|
||||
BorderThickness="1" CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#CBD5E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="bd" Property="Background" Value="#F7FAFC"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StartButtonStyle" TargetType="Button" BasedOn="{StaticResource
|
||||
BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#1A202C"/>
|
||||
<Setter Property="BorderBrush" Value="#1A202C"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2D3748"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#0F141B"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StopButtonStyle" TargetType="Button" BasedOn="{StaticResource
|
||||
BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#E53E3E"/>
|
||||
<Setter Property="BorderBrush" Value="#E53E3E"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#C53030"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#9B2C2C"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ==================== 左侧:相机预览 ==================== -->
|
||||
<Border Grid.Column="0" Margin="0,0,4,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0" Padding="10,0">
|
||||
<Grid>
|
||||
<TextBlock Text="相机预览"
|
||||
Foreground="#7A8FA6"
|
||||
FontSize="11"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center">
|
||||
<Ellipse Width="7" Height="7" Fill="#28A745" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="LIVE" Foreground="#28A745" FontSize="10" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ContentControl Grid.Row="1" Content="{Binding CameraAxisViewModelSevice}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ==================== 右侧:Tab切换 ==================== -->
|
||||
<Grid Grid.Column="1">
|
||||
<TabControl>
|
||||
<!-- ====== Tab 1:标定 ====== -->
|
||||
<TabItem Header="标定">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
CanContentScroll="False"
|
||||
PanningMode="VerticalOnly"
|
||||
Padding="8,8,8,0">
|
||||
<StackPanel>
|
||||
|
||||
<!-- ====== 卡片 1:PHS运动系标定位置 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#E8821A" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="PHS运动系标定位置"
|
||||
Foreground="#E8821A"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="PHS平台标定Y1(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.MoveAxisPos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="80"/>
|
||||
<Button Grid.Column="2"
|
||||
Content="移到此位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMovePhsCalibPosPosition}"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="40"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="X1:"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.ApproachXPos}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="80"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="Y2:"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding FusionCalibParItem.ApproachYPos}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="80"/>
|
||||
<Button Grid.Column="4"
|
||||
Content="中心对齐"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnApproachPhsCalibPosition}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 2:相机起始位置 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="相机起始位置"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="CameraX(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.CameraAxisPos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
<Button Grid.Column="2"
|
||||
Content="计算位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnCalculateCameraPosition}"/>
|
||||
<Button Grid.Column="3"
|
||||
Content="读取当前位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnSetCameraPosition}"/>
|
||||
<Button Grid.Column="4"
|
||||
Content="移到此位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveCameraPosition}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 3:PHS起始位置 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="PHS起始位置"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="StartX(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.StartX}"
|
||||
Style="{StaticResource ReadOnlyNumberBoxStyle}"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="StartY(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding FusionCalibParItem.StartY}"
|
||||
Style="{StaticResource ReadOnlyNumberBoxStyle}"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
|
||||
<Button Content="计算位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnCalculatePhsPosition}"/>
|
||||
<Button Content="读取当前位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnSetStageStartPosition}"/>
|
||||
<Button Content="移到此位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveStageStartPosition}"/>
|
||||
<Button Content="对齐中心"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveToCenter}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 4:标定参数 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="标定参数"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="WaferStepXY(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.CalibStep, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="WaferCountXY:"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:IntNumberBox Grid.Column="3"
|
||||
Value="{Binding FusionCalibParItem.CalibCount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="StepX1(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.Step, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="CountX1:"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:IntNumberBox Grid.Column="3"
|
||||
Value="{Binding FusionCalibParItem.Count, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Minimum="1"
|
||||
Maximum="10000"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
|
||||
Margin="0,8,0,0">
|
||||
<Button Content="开始"
|
||||
Click="{mw:Action btnStart}"
|
||||
Style="{StaticResource StartButtonStyle}"
|
||||
IsEnabled="{Binding Motion.IsFinish}"/>
|
||||
<Button Content="停止"
|
||||
Click="{mw:Action btnStop}"
|
||||
Style="{StaticResource StopButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
|
||||
<!-- ====== Tab 2:验证 ====== -->
|
||||
<TabItem Header="验证">
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
CanContentScroll="False"
|
||||
PanningMode="VerticalOnly"
|
||||
Padding="8,8,8,0">
|
||||
<StackPanel>
|
||||
|
||||
<!-- ====== 卡片 1:PHS运动系标定位置 ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#E8821A" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="PHS运动系标定位置"
|
||||
Foreground="#E8821A"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="PHS平台标定Y1(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.MoveAxisPos, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="80"/>
|
||||
<Button Grid.Column="2"
|
||||
Content="移到此位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMovePhsCalibPosPosition}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 2:PHS运动位置(验证) ====== -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="PHS运动位置"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<!-- 起点坐标 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="StartX(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.WaferStartVerifyX}"
|
||||
Style="{StaticResource ReadOnlyNumberBoxStyle}"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="StartY(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding FusionCalibParItem.WaferStartVerifyY}"
|
||||
Style="{StaticResource ReadOnlyNumberBoxStyle}"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 设置起点 -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
|
||||
<Button Content="设置起点"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveToCenter}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Step + 移动到起点 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="Step(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.WaferVerityStep}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
<Button Grid.Column="2"
|
||||
Content="移动到起点"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action btnMoveToStartPoint}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Count X / Y -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="150"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="CountX:"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:IntNumberBox Grid.Column="1"
|
||||
Value="{Binding FusionCalibParItem.WaferVerityCountX}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="CountY:"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:IntNumberBox Grid.Column="3"
|
||||
Value="{Binding FusionCalibParItem.WaferVerityCountY}"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"
|
||||
Width="100"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 飞拍 + 验证按钮 -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
|
||||
Margin="0,8,0,0">
|
||||
<Button Content="开始飞拍"
|
||||
Click="{mw:Action btnMoveWafer}"
|
||||
Style="{StaticResource StartButtonStyle}"
|
||||
IsEnabled="{Binding Motion.IsFinish}"/>
|
||||
<Button Content="以当前相机位置验证"
|
||||
Click="{mw:Action btnVerityWafer}"
|
||||
Style="{StaticResource VerifyButtonStyle}"
|
||||
Width="150"
|
||||
IsEnabled="{Binding Motion.IsFinish}"/>
|
||||
<Button Content="停止"
|
||||
Click="{mw:Action btnStopVerityWafer}"
|
||||
Style="{StaticResource StopButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Grid>
|
||||
|
||||
<customControl:LoadingWaitView Grid.ColumnSpan="2" Panel.ZIndex="1000"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// PadFusionCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class PadFusionCalibView : UserControl
|
||||
{
|
||||
public PadFusionCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.FusionCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
Unloaded="{mw:Action viewUnLoad}"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="60"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Row="0" Background="#F5F5F5" BorderBrush="#DDD" BorderThickness="0,0,0,1">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock Text="当前标定:" VerticalAlignment="Center" FontSize="14"/>
|
||||
<TextBlock Text="{Binding CurrentCameraName}" VerticalAlignment="Center"
|
||||
FontSize="14" FontWeight="Bold" Margin="0,0,16,0"/>
|
||||
<TextBlock Text="{Binding ProgressText}" VerticalAlignment="Center"
|
||||
FontSize="13" Foreground="#888"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<ContentControl mw:View.Model="{Binding ShowScreenVM}"/>
|
||||
</ScrollViewer>
|
||||
<Border Grid.Row="2">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="上一个" Margin="5,2" Command="{Binding PrevCommand}" IsEnabled="{Binding IsEnablePrev}"/>
|
||||
<Button Content="下一个" Margin="5,2" Command="{Binding NextCommand}" IsEnabled="{Binding IsEnableNext}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// FusionCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class FusionCalibView : UserControl
|
||||
{
|
||||
public FusionCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.FusionMenuCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
d:DesignHeight="800" d:DesignWidth="1200">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
|
||||
<Style x:Key="ModuleCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<DropShadowEffect Color="#000000" Opacity="0.06" BlurRadius="8" ShadowDepth="2" Direction="270"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SectionHeaderTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="BadgeStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="3"/>
|
||||
<Setter Property="Padding" Value="5,1"/>
|
||||
<Setter Property="Margin" Value="3,0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SmallActionButtonStyle" TargetType="Button">
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Padding" Value="10,0"/>
|
||||
<Setter Property="Margin" Value="4,2"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bd" Background="#EDF2F7" BorderBrush="#CBD5E0"
|
||||
BorderThickness="1" CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#CBD5E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="bd" Property="Background" Value="#F7FAFC"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StartCalibButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="120"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,10,0"/>
|
||||
<Setter Property="Background" Value="#1A202C"/>
|
||||
<Setter Property="BorderBrush" Value="#1A202C"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2D3748"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#0F141B"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ModuleWriteButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="4,0"/>
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrange}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrange}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrangeHover}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrangeHover}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrangePressed}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrangePressed}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 左侧:相机预览 -->
|
||||
<Border Grid.Column="0" Margin="0,0,4,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Row="0" Padding="10,0">
|
||||
<Grid>
|
||||
<TextBlock Text="相机预览" Foreground="#7A8FA6" FontSize="11"
|
||||
FontWeight="SemiBold" VerticalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Ellipse Width="7" Height="7" Fill="#28A745" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="LIVE" Foreground="#28A745" FontSize="10" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ContentControl Grid.Row="1" Content="{Binding CameraAxisViewModelService}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- 右侧:工具栏 + 标定卡片 -->
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 顶部工具栏 -->
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="读取标定数据" Command="{mw:Action btnReadCalibData}"
|
||||
Style="{StaticResource SmallActionButtonStyle}" Width="110" Height="34" Margin="5,0"/>
|
||||
<Button Content="保存标定数据" Command="{mw:Action btnSaveCalibData}"
|
||||
Style="{StaticResource SmallActionButtonStyle}" Width="110" Height="34" Margin="5,0"/>
|
||||
<Button Content="应用标定数据" Command="{mw:Action btnApplyCalibData}"
|
||||
Style="{StaticResource ModuleWriteButtonStyle}" Width="110" Height="34" Margin="5,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 标定卡片 -->
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled" CanContentScroll="False"
|
||||
PanningMode="VerticalOnly" Padding="8,8,8,0">
|
||||
<Border Style="{StaticResource ModuleCardStyle}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<Border Grid.Row="0" Background="#F7F9FC" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" CornerRadius="6,6,0,0" Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="[] " Foreground="#8892A0" FontSize="14" VerticalAlignment="Center"/>
|
||||
<TextBlock FontWeight="SemiBold" FontSize="13" Foreground="#2D3748" VerticalAlignment="Center">
|
||||
<Run Text="融合标定数据"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Border Style="{StaticResource BadgeStyle}" Background="#EDF2F7">
|
||||
<TextBlock Text="4区域融合" FontSize="10" Foreground="#718096"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Section 1: 标定参数表格 -->
|
||||
<Border Grid.Row="1" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="标定区域参数" Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<DataGrid ItemsSource="{Binding FusionCalibParItem}"
|
||||
SelectedItem="{Binding SelectedCalibPar}"
|
||||
Margin="0,4" Height="200"
|
||||
AutoGenerateColumns="false" SelectionMode="Single"
|
||||
CanUserSortColumns="False" HeadersVisibility="Column"
|
||||
GridLinesVisibility="Horizontal"
|
||||
HorizontalGridLinesBrush="#F0F4F8"
|
||||
BorderBrush="#E0E4EA" BorderThickness="1"
|
||||
RowBackground="White" AlternatingRowBackground="#FAFBFC"
|
||||
RowHeight="28">
|
||||
<DataGrid.ColumnHeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="#F7F9FC"/>
|
||||
<Setter Property="Foreground" Value="#8892A0"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Padding" Value="8,4"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,0,1"/>
|
||||
</Style>
|
||||
</DataGrid.ColumnHeaderStyle>
|
||||
<DataGrid.CellStyle>
|
||||
<Style TargetType="DataGridCell">
|
||||
<Setter Property="Padding" Value="8,2"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#EBF5FF"/>
|
||||
<Setter Property="Foreground" Value="#1568D5"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.CellStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="序号" IsReadOnly="True" Binding="{Binding Index}" Width="50"/>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="Y1(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding MoveAxisPos, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="X1(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding ApproachXPos, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="Y2(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding ApproachYPos, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="StartX(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding StartX, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="StartY(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding StartY, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="步长(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding Step, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="行列数"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock VerticalAlignment="Center" Foreground="{StaticResource PrimaryTextBrush}"
|
||||
Text="{Binding Count}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Section 2: 操作按钮 -->
|
||||
<Border Grid.Row="2" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2B6CB0" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="标定操作" Foreground="#2B6CB0" Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="打开标定窗口" Command="{mw:Action btnOpenCalibWindow}"
|
||||
Style="{StaticResource StartCalibButtonStyle}" Width="120"/>
|
||||
<TextBlock Text="选择一行数据后打开对应标定窗口"
|
||||
Foreground="#A0AEC0" FontSize="11" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Footer -->
|
||||
<Border Grid.Row="3" BorderBrush="#E0E4EA" BorderThickness="0,1,0,0"
|
||||
Background="#FAFBFC" CornerRadius="0,0,6,6" Padding="10,0">
|
||||
<TextBlock Text="共 4 个标定区域" Foreground="#A0AEC0" FontSize="11"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<customControl:LoadingWaitView Grid.ColumnSpan="2" Panel.ZIndex="1000"/>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// FusionMenuCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class FusionMenuCalibView : UserControl
|
||||
{
|
||||
public FusionMenuCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.MotionCalibContentsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="50"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- 顶部导航栏 -->
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA" BorderThickness="0,0,0,1" Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="当前标定:" VerticalAlignment="Center" FontSize="13" Foreground="#7A8FA6"/>
|
||||
<TextBlock Text="{Binding CurrentCalibName}" VerticalAlignment="Center"
|
||||
FontSize="13" FontWeight="SemiBold" Foreground="#2D3748" Margin="0,0,16,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding ProgressText}" VerticalAlignment="Center"
|
||||
FontSize="12" Foreground="#A0AEC0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- 内容区 -->
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<ContentControl mw:View.Model="{Binding ShowScreenVM}"/>
|
||||
</ScrollViewer>
|
||||
<!-- 底部导航按钮 -->
|
||||
<Border Grid.Row="2" Background="White" BorderBrush="#E0E4EA" BorderThickness="0,1,0,0" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="上一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding PrevCommand}" IsEnabled="{Binding IsEnablePrev}"/>
|
||||
<Button Content="下一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding NextCommand}" IsEnabled="{Binding IsEnableNext}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// MotionCalibContentsView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MotionCalibContentsView : UserControl
|
||||
{
|
||||
public MotionCalibContentsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.MotionCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mwFramework="clr-namespace:MwFramework.Controls.SystemCalib;assembly=MwFramework.Controls.SystemCalib"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<mwFramework:MotionSysCalibControlA DataContext="{Binding Service}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// MotionCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MotionCalibView : UserControl
|
||||
{
|
||||
public MotionCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.MotionMultipleCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="800" d:DesignWidth="1200">
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
|
||||
<!-- 卡片样式 -->
|
||||
<Style x:Key="ModuleCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<DropShadowEffect Color="#000000" Opacity="0.06" BlurRadius="8" ShadowDepth="2" Direction="270"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SectionHeaderTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="BadgeStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="3"/>
|
||||
<Setter Property="Padding" Value="5,1"/>
|
||||
<Setter Property="Margin" Value="3,0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<!-- 表头样式 -->
|
||||
<Style x:Key="TableHeaderStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Foreground" Value="#8892A0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</Style>
|
||||
|
||||
<!-- 按钮样式 -->
|
||||
<Style x:Key="SmallActionButtonStyle" TargetType="Button">
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Padding" Value="10,0"/>
|
||||
<Setter Property="Margin" Value="4,2"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bd" Background="#EDF2F7" BorderBrush="#CBD5E0"
|
||||
BorderThickness="1" CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#CBD5E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="bd" Property="Background" Value="#F7FAFC"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StartCalibButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#1A202C"/>
|
||||
<Setter Property="BorderBrush" Value="#1A202C"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2D3748"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#0F141B"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ModuleWriteButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="4,0"/>
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrange}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrange}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrangeHover}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrangeHover}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrangePressed}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrangePressed}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ==================== 左侧:相机预览 ==================== -->
|
||||
<Border Grid.Column="0" Margin="0,0,4,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0" Padding="10,0">
|
||||
<Grid>
|
||||
<TextBlock Text="相机预览"
|
||||
Foreground="#7A8FA6"
|
||||
FontSize="11"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Ellipse Width="7" Height="7" Fill="#28A745" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="LIVE" Foreground="#28A745" FontSize="10" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ContentControl Grid.Row="1" Content="{Binding CameraAxisViewModelService}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ==================== 右侧:工具栏 + 标定卡片 ==================== -->
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 顶部工具栏 -->
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="读取标定数据"
|
||||
Command="{mw:Action btnReadCalibData}"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Width="110" Height="34" Margin="5,0"/>
|
||||
<Button Content="保存标定数据"
|
||||
Command="{mw:Action btnSaveCalibData}"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Width="110" Height="34" Margin="5,0"/>
|
||||
<Button Content="应用标定数据"
|
||||
Command="{mw:Action btnApplyCalibData}"
|
||||
Style="{StaticResource ModuleWriteButtonStyle}"
|
||||
Width="110" Height="34" Margin="5,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 标定卡片 -->
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
CanContentScroll="False"
|
||||
PanningMode="VerticalOnly"
|
||||
Padding="8,8,8,0">
|
||||
|
||||
<Border Style="{StaticResource ModuleCardStyle}" IsEnabled="{Binding Motion.IsFinish}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<!-- Header -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 标定参数表格 -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 操作按钮 -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- Footer -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- ====== 卡片 Header ====== -->
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="[] " Foreground="#8892A0" FontSize="14" VerticalAlignment="Center"/>
|
||||
<TextBlock FontWeight="SemiBold" FontSize="13" Foreground="#2D3748" VerticalAlignment="Center">
|
||||
<Run Text="运动系标定数据"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Border Style="{StaticResource BadgeStyle}" Background="#EDF2F7">
|
||||
<TextBlock Text="5区域融合" FontSize="10" Foreground="#718096"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== Section 1:标定参数表格 ====== -->
|
||||
<Border Grid.Row="1"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="10,8">
|
||||
<StackPanel>
|
||||
<!-- 区域标题 -->
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="标定区域参数" Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- DataGrid -->
|
||||
<DataGrid Name="dataGridMark"
|
||||
ItemsSource="{Binding MotionCalibParItem}"
|
||||
SelectedItem="{Binding SelectedCalibPar}"
|
||||
Margin="0,4"
|
||||
Height="220"
|
||||
RowHeight="35"
|
||||
AutoGenerateColumns="false"
|
||||
SelectionMode="Single"
|
||||
CanUserSortColumns="False"
|
||||
HeadersVisibility="Column"
|
||||
GridLinesVisibility="Horizontal"
|
||||
HorizontalGridLinesBrush="#F0F4F8"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="1"
|
||||
RowBackground="White"
|
||||
AlternatingRowBackground="#FAFBFC">
|
||||
<DataGrid.ColumnHeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<!--<Setter Property="Background" Value="#F7F9FC"/>-->
|
||||
<Setter Property="Foreground" Value="#8892A0"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Padding" Value="8,4"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,0,1"/>
|
||||
</Style>
|
||||
</DataGrid.ColumnHeaderStyle>
|
||||
<DataGrid.CellStyle>
|
||||
<Style TargetType="DataGridCell">
|
||||
<Setter Property="Padding" Value="8,2"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#EBF5FF"/>
|
||||
<Setter Property="Foreground" Value="#1568D5"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.CellStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="序号" IsReadOnly="True" Binding="{Binding Id}" Width="50"/>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="起点X(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Foreground="{StaticResource PrimaryTextBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding StartAxisX, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="起点Y(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Foreground="{StaticResource PrimaryTextBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding StartAxisY, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="0.5*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="行数"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Foreground="{StaticResource PrimaryTextBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Rows, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="行步长(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Foreground="{StaticResource PrimaryTextBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding RowStep, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="0.5*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="列数"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Foreground="{StaticResource PrimaryTextBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Columns, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="列步长(mm)"/>
|
||||
</DataGridTemplateColumn.Header>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Foreground="{StaticResource PrimaryTextBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding ColumnStep, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, StringFormat=F4}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ====== Section 2:操作按钮 ====== -->
|
||||
<Border Grid.Row="2"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="10,8">
|
||||
<StackPanel>
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2B6CB0" VerticalAlignment="Center"
|
||||
Margin="0,0,5,0"/>
|
||||
<TextBlock Text="标定操作"
|
||||
Foreground="#2B6CB0"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,4">
|
||||
<Button Content="打开标定窗口"
|
||||
Command="{mw:Action btnOpenCalibWindow}"
|
||||
Style="{StaticResource StartCalibButtonStyle}"
|
||||
Width="120"
|
||||
Margin="0,0,10,0"/>
|
||||
<TextBlock Text="选择一行数据后打开对应标定窗口"
|
||||
Foreground="#A0AEC0"
|
||||
FontSize="11"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 Footer ====== -->
|
||||
<Border Grid.Row="3"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,1,0,0"
|
||||
Background="#FAFBFC"
|
||||
CornerRadius="0,0,6,6"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="共 5 个标定区域"
|
||||
Foreground="#A0AEC0"
|
||||
FontSize="11"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<!-- 全局 Loading 遮罩 -->
|
||||
<customControl:LoadingWaitView Grid.ColumnSpan="2" Panel.ZIndex="1000"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// MotionMultipleCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MotionMultipleCalibView : UserControl
|
||||
{
|
||||
public MotionMultipleCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.PixRatioCalibContentsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="50"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- 顶部导航栏 -->
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA" BorderThickness="0,0,0,1" Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="当前标定:" VerticalAlignment="Center" FontSize="13" Foreground="#7A8FA6"/>
|
||||
<TextBlock Text="{Binding CurrentCalibName}" VerticalAlignment="Center"
|
||||
FontSize="13" FontWeight="SemiBold" Foreground="#2D3748" Margin="0,0,16,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding ProgressText}" VerticalAlignment="Center"
|
||||
FontSize="12" Foreground="#A0AEC0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- 内容区 -->
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<ContentControl mw:View.Model="{Binding ShowScreenVM}"/>
|
||||
</ScrollViewer>
|
||||
<!-- 底部导航按钮 -->
|
||||
<Border Grid.Row="2" Background="White" BorderBrush="#E0E4EA" BorderThickness="0,1,0,0" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="上一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding PrevCommand}" IsEnabled="{Binding IsEnablePrev}"/>
|
||||
<Button Content="下一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding NextCommand}" IsEnabled="{Binding IsEnableNext}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// PixRatioCalibContentsView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class PixRatioCalibContentsView : UserControl
|
||||
{
|
||||
public PixRatioCalibContentsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.PixRatioCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mwFramework="clr-namespace:MwFramework.Controls.SystemCalib;assembly=MwFramework.Controls.SystemCalib"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<mwFramework:CameraParaCalibControlA DataContext="{Binding Service}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// PixRatioCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class PixRatioCalibView : UserControl
|
||||
{
|
||||
public PixRatioCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.RotateCenterCalibContentsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="50"/>
|
||||
</Grid.RowDefinitions>
|
||||
<!-- 顶部导航栏 -->
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA" BorderThickness="0,0,0,1" Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="当前标定:" VerticalAlignment="Center" FontSize="13" Foreground="#7A8FA6"/>
|
||||
<TextBlock Text="{Binding CurrentCalibName}" VerticalAlignment="Center"
|
||||
FontSize="13" FontWeight="SemiBold" Foreground="#2D3748" Margin="0,0,16,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding ProgressText}" VerticalAlignment="Center"
|
||||
FontSize="12" Foreground="#A0AEC0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<!-- 内容区 -->
|
||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<ContentControl mw:View.Model="{Binding ShowScreenVM}"/>
|
||||
</ScrollViewer>
|
||||
<!-- 底部导航按钮 -->
|
||||
<Border Grid.Row="2" Background="White" BorderBrush="#E0E4EA" BorderThickness="0,1,0,0" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="上一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding PrevCommand}" IsEnabled="{Binding IsEnablePrev}"/>
|
||||
<Button Content="下一个" Margin="5,0" Padding="16,0" Height="32"
|
||||
Command="{Binding NextCommand}" IsEnabled="{Binding IsEnableNext}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// RotateCenterCalibContentsView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class RotateCenterCalibContentsView : UserControl
|
||||
{
|
||||
public RotateCenterCalibContentsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.RotateCenterCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:MainShell.AlgorithmCalib.View"
|
||||
xmlns:mwFramework="clr-namespace:MwFramework.Controls.SystemCalib;assembly=MwFramework.Controls.SystemCalib"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<mwFramework:RotateCenterCalibControlA DataContext="{Binding Service}"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// RotateCenterCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class RotateCenterCalibView : UserControl
|
||||
{
|
||||
public RotateCenterCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,701 @@
|
||||
<UserControl x:Class="MainShell.AlgorithmCalib.View.RotateMatixFormCalibView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mw="http://www.maxwell-gp.com/"
|
||||
xmlns:customControl="clr-namespace:MainShell.Resources.CustomControl"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="800"
|
||||
d:DesignWidth="1200">
|
||||
|
||||
<UserControl.Resources>
|
||||
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
|
||||
|
||||
<Style x:Key="ModuleCardStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="White"/>
|
||||
<Setter Property="BorderBrush" Value="#E0E4EA"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="CornerRadius" Value="6"/>
|
||||
<Setter Property="Margin" Value="0,0,0,12"/>
|
||||
<Setter Property="Effect">
|
||||
<Setter.Value>
|
||||
<DropShadowEffect Color="#000000" Opacity="0.06" BlurRadius="8" ShadowDepth="2" Direction="270"/>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="AvoidanceAxisNameStyle" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#E8821A"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="TableHeaderStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Foreground" Value="#8892A0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CalibAxisNameStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Foreground" Value="#2D3748"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="TargetValueStyle" TargetType="mw:NumberBox">
|
||||
<Setter Property="Width" Value="85"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="0,1"/>
|
||||
<Setter Property="mw:NumericKeypadAttach.IsEnabled" Value="True"/>
|
||||
<Setter Property="Minimum" Value="-99999"/>
|
||||
<Setter Property="Maximum" Value="99999"/>
|
||||
<Setter Property="DecimalPlaces" Value="3"/>
|
||||
<Setter Property="Foreground" Value="#1568D5"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SmallIconButtonStyle" TargetType="Button">
|
||||
<Setter Property="Width" Value="28"/>
|
||||
<Setter Property="Height" Value="24"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
<Setter Property="Margin" Value="1,0"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bd"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#F0F4F8"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="#CBD5E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="AddAxisButtonStyle" TargetType="Button" BasedOn="{StaticResource SmallIconButtonStyle}">
|
||||
<Setter Property="Width" Value="24"/>
|
||||
<Setter Property="Height" Value="24"/>
|
||||
<Setter Property="Foreground" Value="#28A745"/>
|
||||
<Setter Property="FontSize" Value="15"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ModuleActionButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="4,0"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="CalibStartButtonStyle" TargetType="Button" BasedOn="{StaticResource ModuleActionButtonStyle}">
|
||||
<Setter Property="Background" Value="#1A202C"/>
|
||||
<Setter Property="BorderBrush" Value="#1A202C"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2D3748"/>
|
||||
<Setter Property="BorderBrush" Value="#2D3748"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#0F141B"/>
|
||||
<Setter Property="BorderBrush" Value="#0F141B"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
<Setter Property="Cursor" Value="Arrow"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ModuleWriteButtonStyle" TargetType="Button" BasedOn="{StaticResource ModuleActionButtonStyle}">
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrange}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrange}"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrangeHover}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrangeHover}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource TeachOrangePressed}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource TeachOrangePressed}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
<Setter Property="Cursor" Value="Arrow"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="BadgeStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="3"/>
|
||||
<Setter Property="Padding" Value="5,1"/>
|
||||
<Setter Property="Margin" Value="3,0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
<Style x:Key="SectionHeaderTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ParamLabelStyle" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#4A5568"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ParamNumberBoxStyle" TargetType="mw:NumberBox">
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="6,2"/>
|
||||
<Setter Property="mw:NumericKeypadAttach.IsEnabled" Value="True"/>
|
||||
<Setter Property="Minimum" Value="-99999"/>
|
||||
<Setter Property="Maximum" Value="99999"/>
|
||||
<Setter Property="DecimalPlaces" Value="3"/>
|
||||
<Setter Property="Foreground" Value="#1568D5"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ReadOnlyNumberBoxStyle" TargetType="mw:NumberBox" BasedOn="{StaticResource ParamNumberBoxStyle}">
|
||||
<Setter Property="IsReadOnly" Value="True"/>
|
||||
<Setter Property="Background" Value="#F0F4F8"/>
|
||||
<Setter Property="Foreground" Value="#4A5568"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="IntParamNumberBoxStyle" TargetType="mw:IntNumberBox">
|
||||
<Setter Property="Width" Value="100"/>
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Margin" Value="6,2"/>
|
||||
<Setter Property="mw:NumericKeypadAttach.IsEnabled" Value="True"/>
|
||||
<Setter Property="Minimum" Value="0"/>
|
||||
<Setter Property="Maximum" Value="1000"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SmallActionButtonStyle" TargetType="Button">
|
||||
<Setter Property="Height" Value="28"/>
|
||||
<Setter Property="Padding" Value="10,0"/>
|
||||
<Setter Property="Margin" Value="4,2"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bd" Background="#EDF2F7" BorderBrush="#CBD5E0"
|
||||
BorderThickness="1" CornerRadius="4"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="bd" Property="Background" Value="#CBD5E0"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="bd" Property="Background" Value="#F7FAFC"/>
|
||||
<Setter TargetName="bd" Property="BorderBrush" Value="#E2E8F0"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StartCalibButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#1A202C"/>
|
||||
<Setter Property="BorderBrush" Value="#1A202C"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2D3748"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#0F141B"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="VerifyButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#2B6CB0"/>
|
||||
<Setter Property="BorderBrush" Value="#2B6CB0"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#2C5282"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#1A365D"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Background" Value="{StaticResource DisabledBackground}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForeground}"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="StopButtonStyle" TargetType="Button" BasedOn="{StaticResource BaseRoundedButtonStyle}">
|
||||
<Setter Property="Width" Value="110"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Margin" Value="0,0,6,0"/>
|
||||
<Setter Property="Background" Value="#E53E3E"/>
|
||||
<Setter Property="BorderBrush" Value="#E53E3E"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#C53030"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Background" Value="#9B2C2C"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ==================== 左侧:相机预览(对标原点标定) ==================== -->
|
||||
<Border Grid.Column="0" Margin="0,0,4,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0" Padding="10,0">
|
||||
<Grid>
|
||||
<TextBlock Text="相机预览"
|
||||
Foreground="#7A8FA6"
|
||||
FontSize="11"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Ellipse Width="7" Height="7" Fill="#28A745" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="LIVE" Foreground="#28A745" FontSize="10" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ContentControl Grid.Row="1" Content="{Binding CameraAxisViewModel}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ==================== 右侧:工具栏 + 模块卡片 ==================== -->
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="50"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 顶部工具栏(对标原点标定) -->
|
||||
<Border Grid.Row="0" Background="White" BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1" Padding="8,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button Content="保存配置"
|
||||
Click="{mw:Action SaveConfig}"
|
||||
Style="{StaticResource SaveButtonStyle}"
|
||||
Width="130"
|
||||
Height="34"
|
||||
Margin="5,0"/>
|
||||
<Button Content="全部复位"
|
||||
Click="{mw:Action ResetAll}"
|
||||
Style="{StaticResource ResetButtonStyle}"
|
||||
Width="130"
|
||||
Height="34"
|
||||
Margin="5,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 单模块卡片(对标原点标定的卡片,但不用 ItemsControl) -->
|
||||
<ScrollViewer Grid.Row="1"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
CanContentScroll="False"
|
||||
PanningMode="VerticalOnly"
|
||||
Padding="8,8,8,0">
|
||||
|
||||
<!-- 直接绑定单个 Module,不再用 ItemsControl -->
|
||||
<Border Style="{StaticResource ModuleCardStyle}" DataContext="{Binding Module}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="36"/>
|
||||
<!-- Header -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 避让/位置 -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 标定参数 -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 验证参数 -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 进度条 -->
|
||||
<RowDefinition Height="46"/>
|
||||
<!-- Footer -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- ====== 卡片 Header(对标原点标定) ====== -->
|
||||
<Border Grid.Row="0"
|
||||
Background="#F7F9FC"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
CornerRadius="6,6,0,0"
|
||||
Padding="10,0">
|
||||
<Grid>
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="[] " Foreground="#8892A0" FontSize="14" VerticalAlignment="Center"/>
|
||||
<TextBlock FontWeight="SemiBold" FontSize="13" Foreground="#2D3748" VerticalAlignment="Center">
|
||||
<Run Text="模块"/>
|
||||
<Run Text=" 01: "/>
|
||||
<Run Text="{Binding ModuleName}"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Border Style="{StaticResource BadgeStyle}"
|
||||
Background="#EDF2F7"
|
||||
Visibility="{Binding ShowIndependentBadge}">
|
||||
<TextBlock Text="独立" FontSize="10" Foreground="#718096"/>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ====== Section 1:WS旋转表标定位置(对标避让区域) ====== -->
|
||||
<Border Grid.Row="1"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="10,8">
|
||||
<StackPanel>
|
||||
<!-- 区域标题 -->
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#E8821A" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="WS旋转表标定位置"
|
||||
Foreground="#E8821A"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- X1避让位 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="X1避让位(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding X1AvoidancePosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="80" mw:NumericKeypadAttach.IsEnabled="True"
|
||||
IsEnabled="{Binding CanStartCalib}"/>
|
||||
<Button Grid.Column="2"
|
||||
Content="移到此位置"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action MoveToPosition}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
IsEnabled="{Binding CanStartCalib}"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 起始位置 X2 / Y1 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="40"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="X2:"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding StartX, Mode=TwoWay}" Width="80" mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="Y1:"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding StartY, Mode=TwoWay}" Width="80" mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
<Button Grid.Column="4"
|
||||
Content="中心对齐"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action MoveToCenterPoint}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
IsEnabled="{Binding CanStartCalib}"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ====== Section 2:标定参数 ====== -->
|
||||
<Border Grid.Row="2"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="10,8">
|
||||
<StackPanel>
|
||||
<!-- 区域标题 -->
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2D3748" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="标定参数"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- 行列数 / 旋转步进 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="行列数:"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:IntNumberBox Grid.Column="1"
|
||||
Value="{Binding RowCol, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding CanStartCalib}" Width="80"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="旋转步进(°):"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding RotateStep, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding CanStartCalib}" Width="80"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
</Grid>
|
||||
|
||||
<!-- Wafer间距 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="Wafer间距(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding WaferStep, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding CanStartCalib}" Width="80"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ====== Section 3:验证参数 ====== -->
|
||||
<Border Grid.Row="3"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,0,0,1"
|
||||
Padding="10,8">
|
||||
<StackPanel>
|
||||
<!-- 区域标题 -->
|
||||
<Grid Margin="0,0,0,6">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Ellipse Width="8" Height="8" Fill="#2B6CB0" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBlock Text="验证参数"
|
||||
Foreground="#2B6CB0"
|
||||
Style="{StaticResource SectionHeaderTextStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- 验证起点 X / Y -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="85"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="起点X(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding VerifyStartX, Mode=TwoWay}" Width="80"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="起点Y(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding VerifyStartY, Mode=TwoWay}" Width="80"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
<Button Grid.Column="4"
|
||||
Content="中心对齐"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action VerifyApproachCenter}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
IsEnabled="{Binding CanStartCalib}"/>
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- 验证行列数 / Wafer间距 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="行列数:"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:IntNumberBox Grid.Column="1"
|
||||
Value="{Binding VerifyRowCol, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding CanStartCalib}" Width="80"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="Wafer间距(mm):"
|
||||
Style="{StaticResource ParamLabelStyle}"/>
|
||||
<mw:NumberBox Grid.Column="3"
|
||||
Value="{Binding VerifyWaferStep, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding CanStartCalib}" Width="80"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
<!--<Button Grid.Column="4"
|
||||
Content="设为起点"
|
||||
Style="{StaticResource SmallActionButtonStyle}"
|
||||
Click="{mw:Action SetVerifyStart}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
IsEnabled="{Binding CanStartCalib}"/>-->
|
||||
</Grid>
|
||||
|
||||
<!-- 旋转角度 -->
|
||||
<Grid Margin="0,2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="90"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="旋转角度(°):"
|
||||
Style="{StaticResource ParamLabelStyle}"
|
||||
Margin="6,0"/>
|
||||
<mw:NumberBox Grid.Column="1"
|
||||
Value="{Binding VerifyRotateRange, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
IsEnabled="{Binding CanStartCalib}" Width="80"
|
||||
mw:NumericKeypadAttach.IsEnabled="True"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ====== Section 4: 标定验证进度条 ====== -->
|
||||
<Border Grid.Row="4"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,1,0,0"
|
||||
Background="#F0F7FF"
|
||||
Padding="10,8"
|
||||
Visibility="{Binding IsProgressVisible, Converter={StaticResource
|
||||
BoolToVisibilityConverter}}">
|
||||
<StackPanel>
|
||||
<!-- 进度文本 -->
|
||||
<Grid Margin="0,0,0,6">
|
||||
<TextBlock Text="{Binding ProgressMessage}"
|
||||
FontSize="12"
|
||||
Foreground="#2B6CB0"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding ProgressText, Mode=OneWay}"
|
||||
FontSize="11"
|
||||
Foreground="#718096"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 进度条 -->
|
||||
<ProgressBar Height="6"
|
||||
Minimum="0"
|
||||
Maximum="100"
|
||||
Value="{Binding ProgressPercentage, Mode=OneWay}"
|
||||
Background="#E2E8F0"
|
||||
Foreground="#2B6CB0"
|
||||
BorderThickness="0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- ====== 卡片 Footer(对标原点标定) ====== -->
|
||||
<Border Grid.Row="5"
|
||||
BorderBrush="#E0E4EA"
|
||||
BorderThickness="0,1,0,0"
|
||||
Background="#FAFBFC"
|
||||
CornerRadius="0,0,6,6"
|
||||
Padding="10,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<Button Content="开始标定"
|
||||
Click="{mw:Action StartCalib}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
Style="{StaticResource StartCalibButtonStyle}"
|
||||
IsEnabled="{Binding CanStartCalib}"
|
||||
Margin="0,0,25,0"/>
|
||||
<Button Content="开始验证"
|
||||
Click="{mw:Action StartVerify}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
Style="{StaticResource VerifyButtonStyle}"
|
||||
IsEnabled="{Binding CanStartCalib}"
|
||||
Margin="0,0,25,0"/>
|
||||
<Button Content="停止"
|
||||
Click="{mw:Action Stop}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
Style="{StaticResource StopButtonStyle}"/>
|
||||
<!--<Button Content="写入控制器"
|
||||
Click="{mw:Action WriteToController}"
|
||||
mw:View.ActionTarget="{Binding}"
|
||||
Style="{StaticResource ModuleWriteButtonStyle}"
|
||||
IsEnabled="{Binding CanWriteToController}"/>-->
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<!-- 全局 Loading 遮罩(对标原点标定) -->
|
||||
<customControl:LoadingWaitView Grid.ColumnSpan="2" Panel.ZIndex="1000"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace MainShell.AlgorithmCalib.View
|
||||
{
|
||||
/// <summary>
|
||||
/// RotateMatixFormCalibView.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class RotateMatixFormCalibView : UserControl
|
||||
{
|
||||
public RotateMatixFormCalibView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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