247 lines
9.9 KiB
C#
247 lines
9.9 KiB
C#
|
|
using MainShell.Common;
|
|||
|
|
using MainShell.Hardware;
|
|||
|
|
using MainShell.Manual.Model;
|
|||
|
|
using MainShell.Models;
|
|||
|
|
using MainShell.Models.Wafer;
|
|||
|
|
using MainShell.ParaSetting.Model;
|
|||
|
|
using MainShell.Process;
|
|||
|
|
using MainShell.ProcessResult;
|
|||
|
|
using MainShell.Recipe.BaseBoard.Model;
|
|||
|
|
using MainShell.Recipe.Models;
|
|||
|
|
using MainShell.Resources.CustomControl;
|
|||
|
|
using MaxwellFramework.Core.Interfaces;
|
|||
|
|
using MwFramework.ManagerService;
|
|||
|
|
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;
|
|||
|
|
|
|||
|
|
namespace MainShell.Manual.ViewModel
|
|||
|
|
{
|
|||
|
|
public class DieBondingViewModel : OperateViewModelBase
|
|||
|
|
{
|
|||
|
|
private readonly RecipeManager _recipeManager;
|
|||
|
|
private readonly IEventAggregator _eventAggregator; // 引用 EventAggregator
|
|||
|
|
private readonly ProcessResultManager _processResultManager;
|
|||
|
|
private readonly HardwareManager _hardwareManager;
|
|||
|
|
private readonly IDieTransferPathGenerator _dieTransferPathGenerator;
|
|||
|
|
|
|||
|
|
|
|||
|
|
private List<DieTransferPathItem> _allDieTransferPathItems = new List<DieTransferPathItem>();
|
|||
|
|
|
|||
|
|
private ObservableCollection<DieTransferPathItem> _dieTransferPathItems = new ObservableCollection<DieTransferPathItem>();
|
|||
|
|
/// <summary>
|
|||
|
|
/// 界面上显示的传输路径集合
|
|||
|
|
/// </summary>
|
|||
|
|
public ObservableCollection<DieTransferPathItem> DieTransferPathItems
|
|||
|
|
{
|
|||
|
|
get { return _dieTransferPathItems; }
|
|||
|
|
set { SetAndNotify(ref _dieTransferPathItems, value); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private DieTransferPathItem _selectedDieTransferPathItem;
|
|||
|
|
public DieTransferPathItem SelectedDieTransferPathItem
|
|||
|
|
{
|
|||
|
|
get => _selectedDieTransferPathItem;
|
|||
|
|
set => SetAndNotify(ref _selectedDieTransferPathItem, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private readonly DieBondingManualSetting _dieBondingManualSetting;
|
|||
|
|
public DieBondingManualSysItem DieBondingManualSysItem => _dieBondingManualSetting.DieBondingManualSysItem;
|
|||
|
|
public PaginationViewModel Pagination { get; } = new PaginationViewModel();
|
|||
|
|
public DieBondingViewModel(IEventAggregator eventAggregator, RecipeManager recipeManager,
|
|||
|
|
ProcessResultManager processResultManager, HardwareManager hardwareManager, IDieTransferPathGenerator dieTransferPathGenerator, IParameterManager parameterManager)
|
|||
|
|
{
|
|||
|
|
_eventAggregator = eventAggregator ?? throw new ArgumentNullException(nameof(eventAggregator));
|
|||
|
|
_recipeManager = recipeManager ?? throw new ArgumentNullException(nameof(recipeManager));
|
|||
|
|
_processResultManager = processResultManager ?? throw new ArgumentNullException(nameof(processResultManager));
|
|||
|
|
_hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager));
|
|||
|
|
_dieTransferPathGenerator = dieTransferPathGenerator ?? throw new ArgumentNullException(nameof(dieTransferPathGenerator));
|
|||
|
|
|
|||
|
|
_cameraAxisViewModel = IoC.Get<Common.Display.ViewModel.CameraAxisViewModel>();
|
|||
|
|
_cameraAxisViewModel.CameraAxisDevices.HardwareDeviceList = hardwareManager.CameraAxisManager.TopCameraAxisDevices;
|
|||
|
|
|
|||
|
|
var _paramlist = parameterManager as IParamList;
|
|||
|
|
|
|||
|
|
_dieBondingManualSetting = _paramlist.GetParameter<DieBondingManualSetting>();
|
|||
|
|
|
|||
|
|
Pagination.PageChanged += (s, e) => LoadData();
|
|||
|
|
|
|||
|
|
LoadData();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void LoadData()
|
|||
|
|
{
|
|||
|
|
// 如果数据源为空,清空并返回
|
|||
|
|
if (_allDieTransferPathItems == null || !_allDieTransferPathItems.Any())
|
|||
|
|
{
|
|||
|
|
DieTransferPathItems = new ObservableCollection<DieTransferPathItem>();
|
|||
|
|
Pagination.TotalItems = 0;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 1. 先更新总数(这很重要,因为TotalPages依赖它)
|
|||
|
|
Pagination.TotalItems = _allDieTransferPathItems.Count();
|
|||
|
|
|
|||
|
|
// 2. 自动修正页码:如果当前页超过了新的总页数,强制跳到最后一页
|
|||
|
|
// 注意:修改 Pagination.CurrentPage 会再次触发 PageChanged -> LoadData,
|
|||
|
|
// 所以我们需要防止无限递归,或者只在必要时修正。
|
|||
|
|
// 在这里,简单的方式是计算 offset 时进行钳制,而不强行修改 CurrentPage 属性(取决于你的需求)
|
|||
|
|
// 或者更好的是:
|
|||
|
|
if (Pagination.CurrentPage > Pagination.TotalItems && Pagination.TotalItems > 0)
|
|||
|
|
{
|
|||
|
|
// 如果这里修改 CurrentPage 触发 LoadData,则本次 LoadData 可以直接中断
|
|||
|
|
Pagination.CurrentPage = Pagination.TotalPages;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 安全计算 Offset
|
|||
|
|
int safePage = Math.Min(Pagination.CurrentPage, Pagination.TotalPages);
|
|||
|
|
safePage = Math.Max(1, safePage); // 确保至少为1
|
|||
|
|
|
|||
|
|
int offset = (safePage - 1) * Pagination.PageSize;
|
|||
|
|
int limit = Pagination.PageSize;
|
|||
|
|
|
|||
|
|
// 4. 重置集合
|
|||
|
|
DieTransferPathItems = new ObservableCollection<DieTransferPathItem>(_allDieTransferPathItems.Skip(offset).Take(limit));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public async Task SaveDieBondingSetAsync()
|
|||
|
|
{
|
|||
|
|
bool success = await Loading.RunAsync(async (token, progress) =>
|
|||
|
|
{
|
|||
|
|
_dieBondingManualSetting.Write();
|
|||
|
|
|
|||
|
|
}, "保存参数...",isIndeterminate:true,canCancel:false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public Task GenerateTransPathAsync()
|
|||
|
|
{
|
|||
|
|
DieTransferPathRequest pathRequest = CreatePathRequest();
|
|||
|
|
DieTransferPathPlan pathPlan = _dieTransferPathGenerator.Generate(pathRequest);
|
|||
|
|
_allDieTransferPathItems = ConvertToPathItems(pathPlan);
|
|||
|
|
Pagination.CurrentPage = 1;
|
|||
|
|
LoadData();
|
|||
|
|
return Task.CompletedTask;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private DieTransferPathRequest CreatePathRequest()
|
|||
|
|
{
|
|||
|
|
DieTransferPathRequest pathRequest = new DieTransferPathRequest();
|
|||
|
|
pathRequest.DieRegion = DieBondingManualSysItem.DieRegion;
|
|||
|
|
pathRequest.SubstrateRegion = DieBondingManualSysItem.SubstrateRegion;
|
|||
|
|
pathRequest.TransPathType = DieBondingManualSysItem.TransPathType;
|
|||
|
|
pathRequest.PadRowDirectionStrategy = DieBondingManualSysItem.PadRowDirectionStrategy;
|
|||
|
|
pathRequest.DieRowDirectionStrategy = DieBondingManualSysItem.DieRowDirectionStrategy;
|
|||
|
|
pathRequest.SkipNgDie = true;
|
|||
|
|
pathRequest.DieCandidates = CreateDieCandidates(DieBondingManualSysItem.DieRegion);
|
|||
|
|
pathRequest.PadCandidates = CreatePadCandidates(DieBondingManualSysItem.SubstrateRegion);
|
|||
|
|
return pathRequest;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<Die> CreateDieCandidates(RegionModel region)
|
|||
|
|
{
|
|||
|
|
List<Die> dieCandidates = new List<Die>();
|
|||
|
|
if (region == null)
|
|||
|
|
{
|
|||
|
|
return dieCandidates;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int row = region.StartRow; row <= region.EndRow; row++)
|
|||
|
|
{
|
|||
|
|
for (int column = region.StartCol; column <= region.EndCol; column++)
|
|||
|
|
{
|
|||
|
|
Die die = new Die();
|
|||
|
|
die.Row = row;
|
|||
|
|
die.Column = column;
|
|||
|
|
die.X = column;
|
|||
|
|
die.Y = row;
|
|||
|
|
die.Status = DieStatus.Normal;
|
|||
|
|
dieCandidates.Add(die);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return dieCandidates;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<Pad> CreatePadCandidates(RegionModel region)
|
|||
|
|
{
|
|||
|
|
List<Pad> padCandidates = new List<Pad>();
|
|||
|
|
if (region == null)
|
|||
|
|
{
|
|||
|
|
return padCandidates;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int row = region.StartRow; row <= region.EndRow; row++)
|
|||
|
|
{
|
|||
|
|
for (int column = region.StartCol; column <= region.EndCol; column++)
|
|||
|
|
{
|
|||
|
|
Pad pad = new Pad();
|
|||
|
|
pad.Row = row;
|
|||
|
|
pad.Column = column;
|
|||
|
|
pad.X = column;
|
|||
|
|
pad.Y = row;
|
|||
|
|
|
|||
|
|
SubstratePoint substratePoint;
|
|||
|
|
if (TryGetSubstratePoint(row, column, out substratePoint))
|
|||
|
|
{
|
|||
|
|
pad.X = substratePoint.X;
|
|||
|
|
pad.Y = substratePoint.Y;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
padCandidates.Add(pad);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return padCandidates;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private bool TryGetSubstratePoint(int row, int column, out SubstratePoint substratePoint)
|
|||
|
|
{
|
|||
|
|
substratePoint = default(SubstratePoint);
|
|||
|
|
|
|||
|
|
SubstratePoint[,] substratePoints = _recipeManager.CurrentSubstrateRecipe != null
|
|||
|
|
? _recipeManager.CurrentSubstrateRecipe.SubstratePoints
|
|||
|
|
: null;
|
|||
|
|
if (substratePoints == null)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int rowIndex = row - 1;
|
|||
|
|
int columnIndex = column - 1;
|
|||
|
|
if (rowIndex < 0 || rowIndex >= substratePoints.GetLength(0) || columnIndex < 0 || columnIndex >= substratePoints.GetLength(1))
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
substratePoint = substratePoints[rowIndex, columnIndex];
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static List<DieTransferPathItem> ConvertToPathItems(DieTransferPathPlan pathPlan)
|
|||
|
|
{
|
|||
|
|
List<DieTransferPathItem> pathItems = new List<DieTransferPathItem>();
|
|||
|
|
if (pathPlan == null || pathPlan.Steps == null)
|
|||
|
|
{
|
|||
|
|
return pathItems;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
foreach (DieTransferPathStep pathStep in pathPlan.Steps)
|
|||
|
|
{
|
|||
|
|
DieTransferPathItem pathItem = DieTransferPathItem.FromPathStep(pathStep);
|
|||
|
|
if (pathItem != null)
|
|||
|
|
{
|
|||
|
|
pathItems.Add(pathItem);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return pathItems;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|