259 lines
10 KiB
C#
259 lines
10 KiB
C#
using MainShell.Common;
|
|
using MainShell.Models;
|
|
using MainShell.Models.Wafer;
|
|
using MainShell.Recipe.BaseBoard.Model;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace MainShell.Process
|
|
{
|
|
public class DieTransferPlanningContext
|
|
{
|
|
public DieTransferPlanningContext()
|
|
{
|
|
PadRows = new List<PadTransferRow>();
|
|
DieRows = new List<DieTransferRow>();
|
|
TransPathType = TransPathType.Sequence;
|
|
PadRowDirectionStrategy = DieTransferRowTraversalStrategy.AllPositive;
|
|
DieRowDirectionStrategy = DieTransferRowTraversalStrategy.Serpentine;
|
|
SkipNgDie = true;
|
|
}
|
|
|
|
public DieTransferRegion DieRegion { get; set; }
|
|
|
|
public DieTransferRegion SubstrateRegion { get; set; }
|
|
|
|
public TransPathType TransPathType { get; set; }
|
|
|
|
public DieTransferRowTraversalStrategy PadRowDirectionStrategy { get; set; }
|
|
|
|
public DieTransferRowTraversalStrategy DieRowDirectionStrategy { get; set; }
|
|
|
|
public bool SkipNgDie { get; set; }
|
|
|
|
public List<PadTransferRow> PadRows { get; set; }
|
|
|
|
public List<DieTransferRow> DieRows { get; set; }
|
|
|
|
public int AvailablePadCount
|
|
{
|
|
get
|
|
{
|
|
return PadRows == null ? 0 : PadRows.Sum(row => row.AvailableCount);
|
|
}
|
|
}
|
|
|
|
public int AvailableDieCount
|
|
{
|
|
get
|
|
{
|
|
return DieRows == null ? 0 : DieRows.Sum(row => row.AvailableCount);
|
|
}
|
|
}
|
|
|
|
public List<Pad> GetOrderedPads()
|
|
{
|
|
List<Pad> pads = new List<Pad>();
|
|
if (PadRows == null)
|
|
{
|
|
return pads;
|
|
}
|
|
|
|
foreach (PadTransferRow row in PadRows.OrderBy(item => item.RowIndex))
|
|
{
|
|
pads.AddRange(row.GetAvailablePads());
|
|
}
|
|
|
|
return pads;
|
|
}
|
|
|
|
public List<Die> GetOrderedDies()
|
|
{
|
|
List<Die> dies = new List<Die>();
|
|
if (DieRows == null)
|
|
{
|
|
return dies;
|
|
}
|
|
|
|
foreach (DieTransferRow row in DieRows.OrderBy(item => item.RowIndex))
|
|
{
|
|
dies.AddRange(row.GetAvailableDies());
|
|
}
|
|
|
|
return dies;
|
|
}
|
|
|
|
public static DieTransferPlanningContext Create(DieTransferPathRequest request)
|
|
{
|
|
if (request == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(request));
|
|
}
|
|
|
|
DieTransferPlanningContext context = new DieTransferPlanningContext();
|
|
context.DieRegion = DieTransferRegion.FromRegionModel(request.DieRegion);
|
|
context.SubstrateRegion = DieTransferRegion.FromRegionModel(request.SubstrateRegion);
|
|
context.TransPathType = request.TransPathType;
|
|
context.PadRowDirectionStrategy = request.PadRowDirectionStrategy;
|
|
context.DieRowDirectionStrategy = request.DieRowDirectionStrategy;
|
|
context.SkipNgDie = request.SkipNgDie;
|
|
context.PadRows = CreatePadRows(request.PadCandidates, context.SubstrateRegion, context.PadRowDirectionStrategy);
|
|
context.DieRows = CreateDieRows(request.DieCandidates, context.DieRegion, request.SkipNgDie, context.DieRowDirectionStrategy);
|
|
return context;
|
|
}
|
|
|
|
public static List<PadTransferRow> CreatePadRows(IReadOnlyCollection<Pad> padCandidates, DieTransferRegion region, DieTransferRowTraversalStrategy rowTraversalStrategy)
|
|
{
|
|
IEnumerable<Pad> filteredPads = (padCandidates ?? Array.Empty<Pad>())
|
|
.Where(pad => pad != null && IsInRegion(pad.Row, pad.Column, region));
|
|
|
|
List<PadTransferRow> rows = new List<PadTransferRow>();
|
|
foreach (IGrouping<int, Pad> rowGroup in filteredPads.GroupBy(pad => pad.Row).OrderBy(group => group.Key))
|
|
{
|
|
PadTransferRow row = new PadTransferRow();
|
|
row.RowIndex = rowGroup.Key;
|
|
row.Direction = ResolveRowDirection(rowGroup.Key, rowTraversalStrategy);
|
|
row.Pads = rowGroup.OrderBy(pad => pad.Column).ToList();
|
|
rows.Add(row);
|
|
}
|
|
|
|
return rows;
|
|
}
|
|
|
|
public static List<DieTransferRow> CreateDieRows(IReadOnlyCollection<Die> dieCandidates, DieTransferRegion region, bool skipNgDie, DieTransferRowTraversalStrategy rowTraversalStrategy)
|
|
{
|
|
IEnumerable<Die> filteredDies = (dieCandidates ?? Array.Empty<Die>())
|
|
.Where(die => die != null && IsInRegion(die.Row, die.Column, region));
|
|
|
|
List<DieTransferRow> rows = new List<DieTransferRow>();
|
|
foreach (IGrouping<int, Die> rowGroup in filteredDies.GroupBy(die => die.Row).OrderBy(group => group.Key))
|
|
{
|
|
DieTransferRow row = new DieTransferRow();
|
|
row.RowIndex = rowGroup.Key;
|
|
row.Direction = ResolveRowDirection(rowGroup.Key, rowTraversalStrategy);
|
|
row.SkipNgDie = skipNgDie;
|
|
row.Dies = rowGroup.OrderBy(die => die.Column).ToList();
|
|
rows.Add(row);
|
|
}
|
|
|
|
return rows;
|
|
}
|
|
|
|
public static List<PadTransferRow> TrimPadRows(IReadOnlyCollection<PadTransferRow> sourceRows, int targetCount, out List<PadTransferRow> remainingRows)
|
|
{
|
|
List<PadTransferRow> activeRows = new List<PadTransferRow>();
|
|
remainingRows = new List<PadTransferRow>();
|
|
int remainingCount = Math.Max(0, targetCount);
|
|
|
|
foreach (PadTransferRow sourceRow in (sourceRows ?? Array.Empty<PadTransferRow>()).Where(row => row != null).OrderBy(row => row.RowIndex))
|
|
{
|
|
List<Pad> availablePads = sourceRow.GetAvailablePads().ToList();
|
|
if (availablePads.Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (remainingCount <= 0)
|
|
{
|
|
remainingRows.Add(CreatePadRow(sourceRow.RowIndex, sourceRow.Direction, availablePads));
|
|
continue;
|
|
}
|
|
|
|
if (availablePads.Count <= remainingCount)
|
|
{
|
|
activeRows.Add(CreatePadRow(sourceRow.RowIndex, sourceRow.Direction, availablePads));
|
|
remainingCount -= availablePads.Count;
|
|
continue;
|
|
}
|
|
|
|
activeRows.Add(CreatePadRow(sourceRow.RowIndex, sourceRow.Direction, availablePads.Take(remainingCount)));
|
|
remainingRows.Add(CreatePadRow(sourceRow.RowIndex, sourceRow.Direction, availablePads.Skip(remainingCount)));
|
|
remainingCount = 0;
|
|
}
|
|
|
|
return activeRows;
|
|
}
|
|
|
|
public static List<DieTransferRow> TrimDieRows(IReadOnlyCollection<DieTransferRow> sourceRows, int targetCount, out List<DieTransferRow> remainingRows)
|
|
{
|
|
List<DieTransferRow> activeRows = new List<DieTransferRow>();
|
|
remainingRows = new List<DieTransferRow>();
|
|
int remainingCount = Math.Max(0, targetCount);
|
|
|
|
foreach (DieTransferRow sourceRow in (sourceRows ?? Array.Empty<DieTransferRow>()).Where(row => row != null).OrderBy(row => row.RowIndex))
|
|
{
|
|
List<Die> availableDies = sourceRow.GetAvailableDies().ToList();
|
|
if (availableDies.Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (remainingCount <= 0)
|
|
{
|
|
remainingRows.Add(CreateDieRow(sourceRow.RowIndex, sourceRow.Direction, sourceRow.SkipNgDie, availableDies));
|
|
continue;
|
|
}
|
|
|
|
if (availableDies.Count <= remainingCount)
|
|
{
|
|
activeRows.Add(CreateDieRow(sourceRow.RowIndex, sourceRow.Direction, sourceRow.SkipNgDie, availableDies));
|
|
remainingCount -= availableDies.Count;
|
|
continue;
|
|
}
|
|
|
|
activeRows.Add(CreateDieRow(sourceRow.RowIndex, sourceRow.Direction, sourceRow.SkipNgDie, availableDies.Take(remainingCount)));
|
|
remainingRows.Add(CreateDieRow(sourceRow.RowIndex, sourceRow.Direction, sourceRow.SkipNgDie, availableDies.Skip(remainingCount)));
|
|
remainingCount = 0;
|
|
}
|
|
|
|
return activeRows;
|
|
}
|
|
|
|
private static bool IsInRegion(int row, int column, DieTransferRegion region)
|
|
{
|
|
if (region == null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return region.Contains(row, column);
|
|
}
|
|
|
|
private static DieTransferRowDirection ResolveRowDirection(int rowIndex, DieTransferRowTraversalStrategy rowTraversalStrategy)
|
|
{
|
|
switch (rowTraversalStrategy)
|
|
{
|
|
case DieTransferRowTraversalStrategy.AllNegative:
|
|
return DieTransferRowDirection.Negative;
|
|
|
|
case DieTransferRowTraversalStrategy.Serpentine:
|
|
return rowIndex % 2 == 0 ? DieTransferRowDirection.Negative : DieTransferRowDirection.Positive;
|
|
|
|
case DieTransferRowTraversalStrategy.AllPositive:
|
|
default:
|
|
return DieTransferRowDirection.Positive;
|
|
}
|
|
}
|
|
|
|
private static PadTransferRow CreatePadRow(int rowIndex, DieTransferRowDirection direction, IEnumerable<Pad> pads)
|
|
{
|
|
PadTransferRow row = new PadTransferRow();
|
|
row.RowIndex = rowIndex;
|
|
row.Direction = direction;
|
|
row.Pads = (pads ?? Array.Empty<Pad>()).Where(pad => pad != null).ToList();
|
|
return row;
|
|
}
|
|
|
|
private static DieTransferRow CreateDieRow(int rowIndex, DieTransferRowDirection direction, bool skipNgDie, IEnumerable<Die> dies)
|
|
{
|
|
DieTransferRow row = new DieTransferRow();
|
|
row.RowIndex = rowIndex;
|
|
row.Direction = direction;
|
|
row.SkipNgDie = skipNgDie;
|
|
row.Dies = (dies ?? Array.Empty<Die>()).Where(die => die != null).ToList();
|
|
return row;
|
|
}
|
|
}
|
|
}
|