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

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

View File

@@ -0,0 +1,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; }
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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
{
}
}

View File

@@ -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; } // 逼近XDie=X2, Pad=X1
public double ApproachYPos { get; set; } // 逼近YDie=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; } // 验证起点XDie=X2, Pad=X1
public double WaferStartVerifyY { get; set; } // 验证起点YDie=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实际Xreal坐标
public double DieRealY { get; set; } // die实际Yreal坐标
public double DieRulerX { get; set; } // die轴位置Xruler坐标
public double DieRulerY { get; set; } // die轴位置Yruler坐标
// Pad对位飞拍pad坐标
public double PadRealX { get; set; } // pad实际Xreal坐标
public double PadRealY { get; set; } // pad实际Yreal坐标
public double PadRulerX { get; set; } // pad轴位置Xruler坐标
public double PadRulerY { get; set; } // pad轴位置Yruler坐标
// 对位结果
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>>();
}
}

View File

@@ -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,
};
}
}
}

View File

@@ -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)); } }
}
}
}

View File

@@ -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)); } }
}
}
}

View File

@@ -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)); } }
}
}
}

View File

@@ -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,
}
};
}
}
}

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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的移动量(此处直接移动或查表再移动)。

View File

@@ -0,0 +1,12 @@
旧项目的标定页面为CameraFusionCalibAView.xaml里面的融合标定和验证1是新项目需要的流程
CameraFusionCali02AViewModel.xaml是原项目的CameraFusionCali02AViewModel.cs
CameraFusionCalibrationMotion02A.xaml是原项目的CameraFusionCalibrationMotion02A.cs
旧项目的ws轴是x2、Y2pad轴是X1、Y1
新项目的ws轴是X2、Y1pad轴是x1、Y2
新项目的需求是pad融合标定和die融合标定并且有分别的验证
然后总体又有一个整体的验证,及对位流程

View File

@@ -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])
));
}
}
}
}

View File

@@ -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>
/// 步骤2bDie网格飞拍
/// 以首点为起点按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);
// === 步骤3aDie 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);
// === 步骤3bPad 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);
// === 步骤3cX2补偿 ===
// 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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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
});
}
}
}

View File

@@ -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])
));
}
}
}
}

View File

@@ -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}");
}
}
}
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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&lt;Point&gt;
///// 对标原 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
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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>

View File

@@ -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()
{
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>
<!-- ====== 卡片 1WS运动系标定位置 ====== -->
<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>
<!-- ====== 卡片 3WS起始位置 ====== -->
<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>
<!-- ====== 卡片 1WS运动系标定位置 ====== -->
<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>
<!-- ====== 卡片 2WS运动位置验证 ====== -->
<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>

View File

@@ -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();
}
}
}

View File

@@ -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>
<!-- ====== 步骤2Die网格飞拍 ====== -->
<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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>
<!-- ====== 卡片 1PHS运动系标定位置 ====== -->
<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>
<!-- ====== 卡片 3PHS起始位置 ====== -->
<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>
<!-- ====== 卡片 1PHS运动系标定位置 ====== -->
<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>
<!-- ====== 卡片 2PHS运动位置验证 ====== -->
<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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}

View File

@@ -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 1WS旋转表标定位置对标避让区域 ====== -->
<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>

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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()
{
}
}
}

View File

@@ -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}";
}
}
}

View File

@@ -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;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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}";
}
}
}

View File

@@ -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)
{
}
}
}

View File

@@ -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}";
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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;
}
}
}

View File

@@ -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}";
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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
}
}