347 lines
15 KiB
C#
347 lines
15 KiB
C#
|
|
using MainShell.Common;
|
||
|
|
using MainShell.Models.Wafer;
|
||
|
|
using MainShell.Recipe.BaseBoard.Model;
|
||
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
namespace MainShell.Process
|
||
|
|
{
|
||
|
|
public class DieTransferPathGenerator : IDieTransferPathGenerator
|
||
|
|
{
|
||
|
|
public DieTransferPathPlan Generate(DieTransferPathRequest request)
|
||
|
|
{
|
||
|
|
return GenerateByRegion(request);
|
||
|
|
}
|
||
|
|
|
||
|
|
public DieTransferPathRegionPlan GenerateByRegion(DieTransferPathRequest request)
|
||
|
|
{
|
||
|
|
if (request == null)
|
||
|
|
{
|
||
|
|
throw new ArgumentNullException(nameof(request));
|
||
|
|
}
|
||
|
|
|
||
|
|
DieTransferPlanningContext planningContext = DieTransferPlanningContext.Create(request);
|
||
|
|
int effectiveCount = Math.Min(planningContext.AvailablePadCount, planningContext.AvailableDieCount);
|
||
|
|
List<PadTransferRow> remainingPadRows;
|
||
|
|
List<DieTransferRow> remainingDieRows;
|
||
|
|
List<PadTransferRow> activePadRows = DieTransferPlanningContext.TrimPadRows(planningContext.PadRows, effectiveCount, out remainingPadRows);
|
||
|
|
List<DieTransferRow> activeDieRows = DieTransferPlanningContext.TrimDieRows(planningContext.DieRows, effectiveCount, out remainingDieRows);
|
||
|
|
DieTransferPathRegionPlan pathPlan = GenerateByRows(activePadRows, activeDieRows, planningContext.TransPathType);
|
||
|
|
List<Pad> remainingPads = GetOrderedPads(remainingPadRows);
|
||
|
|
List<Die> remainingDies = GetOrderedDies(remainingDieRows);
|
||
|
|
|
||
|
|
pathPlan.AvailableDieCount = planningContext.AvailableDieCount;
|
||
|
|
pathPlan.AvailablePadCount = planningContext.AvailablePadCount;
|
||
|
|
pathPlan.RemainingPads = remainingPads;
|
||
|
|
pathPlan.RemainingDies = remainingDies;
|
||
|
|
pathPlan.RemainingPadRows = DieTransferPlanningContext.CreatePadRows(remainingPads, planningContext.SubstrateRegion, planningContext.PadRowDirectionStrategy);
|
||
|
|
pathPlan.RemainingDieRows = DieTransferPlanningContext.CreateDieRows(remainingDies, planningContext.DieRegion, planningContext.SkipNgDie, planningContext.DieRowDirectionStrategy);
|
||
|
|
pathPlan.RemainingSubstrateRegion = CreateRegionFromPads(remainingPads);
|
||
|
|
pathPlan.RemainingDieRegion = CreateRegionFromDies(remainingDies);
|
||
|
|
return pathPlan;
|
||
|
|
}
|
||
|
|
|
||
|
|
public DieTransferPathRegionPlan GenerateByCandidates(
|
||
|
|
IReadOnlyCollection<Pad> padCandidates,
|
||
|
|
IReadOnlyCollection<Die> dieCandidates,
|
||
|
|
TransPathType transPathType,
|
||
|
|
bool skipNgDie,
|
||
|
|
DieTransferRowTraversalStrategy padRowDirectionStrategy,
|
||
|
|
DieTransferRowTraversalStrategy dieRowDirectionStrategy)
|
||
|
|
{
|
||
|
|
DieTransferPathRequest request = new DieTransferPathRequest();
|
||
|
|
request.PadCandidates = padCandidates ?? Array.Empty<Pad>();
|
||
|
|
request.DieCandidates = dieCandidates ?? Array.Empty<Die>();
|
||
|
|
request.TransPathType = transPathType;
|
||
|
|
request.SkipNgDie = skipNgDie;
|
||
|
|
request.PadRowDirectionStrategy = padRowDirectionStrategy;
|
||
|
|
request.DieRowDirectionStrategy = dieRowDirectionStrategy;
|
||
|
|
|
||
|
|
return GenerateByRegion(request);
|
||
|
|
}
|
||
|
|
|
||
|
|
public DieTransferPathRegionPlan GenerateByRows(
|
||
|
|
IReadOnlyCollection<PadTransferRow> padRows,
|
||
|
|
IReadOnlyCollection<DieTransferRow> dieRows,
|
||
|
|
TransPathType transPathType)
|
||
|
|
{
|
||
|
|
IReadOnlyCollection<PadTransferRow> safePadRows = padRows ?? Array.Empty<PadTransferRow>();
|
||
|
|
IReadOnlyCollection<DieTransferRow> safeDieRows = dieRows ?? Array.Empty<DieTransferRow>();
|
||
|
|
List<Pad> orderedPads = GetOrderedPads(safePadRows);
|
||
|
|
List<Die> orderedDies = GetOrderedDies(safeDieRows);
|
||
|
|
List<DieTransferPathStep> steps = CreateSteps(orderedDies, orderedPads, transPathType);
|
||
|
|
List<Pad> remainingPads = CreateRemainingPads(orderedPads, steps);
|
||
|
|
List<Die> remainingDies = CreateRemainingDies(orderedDies, steps);
|
||
|
|
|
||
|
|
DieTransferPathRegionPlan pathPlan = new DieTransferPathRegionPlan();
|
||
|
|
pathPlan.TransPathType = transPathType;
|
||
|
|
pathPlan.AvailablePadCount = GetAvailablePadCount(safePadRows);
|
||
|
|
pathPlan.AvailableDieCount = GetAvailableDieCount(safeDieRows);
|
||
|
|
pathPlan.Steps = steps;
|
||
|
|
pathPlan.RemainingPads = remainingPads;
|
||
|
|
pathPlan.RemainingDies = remainingDies;
|
||
|
|
pathPlan.RemainingPadRows = CreateRemainingPadRows(safePadRows, remainingPads);
|
||
|
|
pathPlan.RemainingDieRows = CreateRemainingDieRows(safeDieRows, remainingDies);
|
||
|
|
pathPlan.RemainingSubstrateRegion = CreateRegionFromPads(remainingPads);
|
||
|
|
pathPlan.RemainingDieRegion = CreateRegionFromDies(remainingDies);
|
||
|
|
return pathPlan;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<DieTransferPathStep> CreateSteps(IReadOnlyList<Die> dies, IReadOnlyList<Pad> pads, TransPathType transPathType)
|
||
|
|
{
|
||
|
|
return transPathType == TransPathType.Nearest
|
||
|
|
? BuildNearestSteps(dies, pads, transPathType)
|
||
|
|
: BuildSequenceSteps(dies, pads, transPathType);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<DieTransferPathStep> BuildSequenceSteps(IReadOnlyList<Die> dies, IReadOnlyList<Pad> pads, TransPathType transPathType)
|
||
|
|
{
|
||
|
|
int stepCount = Math.Min(dies.Count, pads.Count);
|
||
|
|
List<DieTransferPathStep> steps = new List<DieTransferPathStep>(stepCount);
|
||
|
|
|
||
|
|
for (int i = 0; i < stepCount; i++)
|
||
|
|
{
|
||
|
|
steps.Add(CreateStep(i + 1, dies[i], pads[i], transPathType));
|
||
|
|
}
|
||
|
|
|
||
|
|
return steps;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<DieTransferPathStep> BuildNearestSteps(IReadOnlyList<Die> dies, IReadOnlyList<Pad> pads, TransPathType transPathType)
|
||
|
|
{
|
||
|
|
List<Die> remainingDies = (dies ?? Array.Empty<Die>()).Where(die => die != null).ToList();
|
||
|
|
List<DieTransferPathStep> steps = new List<DieTransferPathStep>(Math.Min(remainingDies.Count, pads.Count));
|
||
|
|
int stepIndex = 1;
|
||
|
|
|
||
|
|
foreach (Pad pad in pads)
|
||
|
|
{
|
||
|
|
if (remainingDies.Count == 0)
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
Die nearestDie = SelectNearestDie(pad, remainingDies);
|
||
|
|
steps.Add(CreateStep(stepIndex, nearestDie, pad, transPathType));
|
||
|
|
remainingDies.Remove(nearestDie);
|
||
|
|
stepIndex++;
|
||
|
|
}
|
||
|
|
|
||
|
|
return steps;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Die SelectNearestDie(Pad pad, IReadOnlyList<Die> dies)
|
||
|
|
{
|
||
|
|
Die selectedDie = null;
|
||
|
|
double bestDistance = double.MaxValue;
|
||
|
|
|
||
|
|
for (int index = 0; index < dies.Count; index++)
|
||
|
|
{
|
||
|
|
Die die = dies[index];
|
||
|
|
double currentDistance = CalculateSquaredDistance(die.X, die.Y, pad.X, pad.Y);
|
||
|
|
if (currentDistance < bestDistance)
|
||
|
|
{
|
||
|
|
selectedDie = die;
|
||
|
|
bestDistance = currentDistance;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return selectedDie;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static double CalculateSquaredDistance(double sourceX, double sourceY, double targetX, double targetY)
|
||
|
|
{
|
||
|
|
double deltaX = sourceX - targetX;
|
||
|
|
double deltaY = sourceY - targetY;
|
||
|
|
return (deltaX * deltaX) + (deltaY * deltaY);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static DieTransferPathStep CreateStep(int stepIndex, Die die, Pad pad, TransPathType transPathType)
|
||
|
|
{
|
||
|
|
DieTransferPathStep step = new DieTransferPathStep();
|
||
|
|
step.StepIndex = stepIndex;
|
||
|
|
step.DieRow = die.Row;
|
||
|
|
step.DieColumn = die.Column;
|
||
|
|
step.PadRow = pad.Row;
|
||
|
|
step.PadColumn = pad.Column;
|
||
|
|
step.DieX = die.X;
|
||
|
|
step.DieY = die.Y;
|
||
|
|
step.PadX = pad.X;
|
||
|
|
step.PadY = pad.Y;
|
||
|
|
step.TransPathType = transPathType;
|
||
|
|
return step;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static int GetAvailablePadCount(IEnumerable<PadTransferRow> padRows)
|
||
|
|
{
|
||
|
|
return (padRows ?? Array.Empty<PadTransferRow>())
|
||
|
|
.Where(row => row != null)
|
||
|
|
.Sum(row => row.AvailableCount);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static int GetAvailableDieCount(IEnumerable<DieTransferRow> dieRows)
|
||
|
|
{
|
||
|
|
return (dieRows ?? Array.Empty<DieTransferRow>())
|
||
|
|
.Where(row => row != null)
|
||
|
|
.Sum(row => row.AvailableCount);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<Pad> GetOrderedPads(IEnumerable<PadTransferRow> padRows)
|
||
|
|
{
|
||
|
|
List<Pad> orderedPads = new List<Pad>();
|
||
|
|
|
||
|
|
foreach (PadTransferRow padRow in (padRows ?? Array.Empty<PadTransferRow>()).Where(row => row != null).OrderBy(row => row.RowIndex))
|
||
|
|
{
|
||
|
|
orderedPads.AddRange(padRow.GetAvailablePads());
|
||
|
|
}
|
||
|
|
|
||
|
|
return orderedPads;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<Die> GetOrderedDies(IEnumerable<DieTransferRow> dieRows)
|
||
|
|
{
|
||
|
|
List<Die> orderedDies = new List<Die>();
|
||
|
|
|
||
|
|
foreach (DieTransferRow dieRow in (dieRows ?? Array.Empty<DieTransferRow>()).Where(row => row != null).OrderBy(row => row.RowIndex))
|
||
|
|
{
|
||
|
|
orderedDies.AddRange(dieRow.GetAvailableDies());
|
||
|
|
}
|
||
|
|
|
||
|
|
return orderedDies;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<PadTransferRow> CreateRemainingPadRows(IEnumerable<PadTransferRow> sourceRows, IReadOnlyCollection<Pad> remainingPads)
|
||
|
|
{
|
||
|
|
HashSet<string> remainingPadKeys = CreatePointKeys(remainingPads, pad => pad.Row, pad => pad.Column);
|
||
|
|
List<PadTransferRow> remainingPadRows = new List<PadTransferRow>();
|
||
|
|
|
||
|
|
foreach (PadTransferRow sourceRow in (sourceRows ?? Array.Empty<PadTransferRow>()).Where(row => row != null).OrderBy(row => row.RowIndex))
|
||
|
|
{
|
||
|
|
List<Pad> rowPads = (sourceRow.Pads ?? new List<Pad>())
|
||
|
|
.Where(pad => pad != null && remainingPadKeys.Contains(CreatePointKey(pad.Row, pad.Column)))
|
||
|
|
.OrderBy(pad => pad.Column)
|
||
|
|
.ToList();
|
||
|
|
if (rowPads.Count == 0)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
PadTransferRow remainingRow = new PadTransferRow();
|
||
|
|
remainingRow.RowIndex = sourceRow.RowIndex;
|
||
|
|
remainingRow.Direction = sourceRow.Direction;
|
||
|
|
remainingRow.Pads = rowPads;
|
||
|
|
remainingPadRows.Add(remainingRow);
|
||
|
|
}
|
||
|
|
|
||
|
|
return remainingPadRows;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<DieTransferRow> CreateRemainingDieRows(IEnumerable<DieTransferRow> sourceRows, IReadOnlyCollection<Die> remainingDies)
|
||
|
|
{
|
||
|
|
HashSet<string> remainingDieKeys = CreatePointKeys(remainingDies, die => die.Row, die => die.Column);
|
||
|
|
List<DieTransferRow> remainingDieRows = new List<DieTransferRow>();
|
||
|
|
|
||
|
|
foreach (DieTransferRow sourceRow in (sourceRows ?? Array.Empty<DieTransferRow>()).Where(row => row != null).OrderBy(row => row.RowIndex))
|
||
|
|
{
|
||
|
|
List<Die> rowDies = (sourceRow.Dies ?? new List<Die>())
|
||
|
|
.Where(die => die != null && remainingDieKeys.Contains(CreatePointKey(die.Row, die.Column)))
|
||
|
|
.OrderBy(die => die.Column)
|
||
|
|
.ToList();
|
||
|
|
if (rowDies.Count == 0)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
DieTransferRow remainingRow = new DieTransferRow();
|
||
|
|
remainingRow.RowIndex = sourceRow.RowIndex;
|
||
|
|
remainingRow.Direction = sourceRow.Direction;
|
||
|
|
remainingRow.SkipNgDie = sourceRow.SkipNgDie;
|
||
|
|
remainingRow.Dies = rowDies;
|
||
|
|
remainingDieRows.Add(remainingRow);
|
||
|
|
}
|
||
|
|
|
||
|
|
return remainingDieRows;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static HashSet<string> CreatePointKeys<TPoint>(IEnumerable<TPoint> points, Func<TPoint, int> getRow, Func<TPoint, int> getColumn)
|
||
|
|
where TPoint : class
|
||
|
|
{
|
||
|
|
HashSet<string> pointKeys = new HashSet<string>();
|
||
|
|
|
||
|
|
foreach (TPoint point in points ?? Array.Empty<TPoint>())
|
||
|
|
{
|
||
|
|
if (point == null)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
pointKeys.Add(CreatePointKey(getRow(point), getColumn(point)));
|
||
|
|
}
|
||
|
|
|
||
|
|
return pointKeys;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<Pad> CreateRemainingPads(IReadOnlyList<Pad> orderedPads, IReadOnlyList<DieTransferPathStep> steps)
|
||
|
|
{
|
||
|
|
HashSet<string> usedPadKeys = new HashSet<string>();
|
||
|
|
foreach (DieTransferPathStep step in steps ?? Array.Empty<DieTransferPathStep>())
|
||
|
|
{
|
||
|
|
usedPadKeys.Add(CreatePointKey(step.PadRow, step.PadColumn));
|
||
|
|
}
|
||
|
|
|
||
|
|
return (orderedPads ?? Array.Empty<Pad>())
|
||
|
|
.Where(pad => pad != null && !usedPadKeys.Contains(CreatePointKey(pad.Row, pad.Column)))
|
||
|
|
.ToList();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<Die> CreateRemainingDies(IReadOnlyList<Die> orderedDies, IReadOnlyList<DieTransferPathStep> steps)
|
||
|
|
{
|
||
|
|
HashSet<string> usedDieKeys = new HashSet<string>();
|
||
|
|
foreach (DieTransferPathStep step in steps ?? Array.Empty<DieTransferPathStep>())
|
||
|
|
{
|
||
|
|
usedDieKeys.Add(CreatePointKey(step.DieRow, step.DieColumn));
|
||
|
|
}
|
||
|
|
|
||
|
|
return (orderedDies ?? Array.Empty<Die>())
|
||
|
|
.Where(die => die != null && !usedDieKeys.Contains(CreatePointKey(die.Row, die.Column)))
|
||
|
|
.ToList();
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string CreatePointKey(int row, int column)
|
||
|
|
{
|
||
|
|
return $"{row}:{column}";
|
||
|
|
}
|
||
|
|
|
||
|
|
private static DieTransferRegion CreateRegionFromPads(IEnumerable<Pad> pads)
|
||
|
|
{
|
||
|
|
List<Pad> availablePads = (pads ?? Array.Empty<Pad>()).Where(pad => pad != null).ToList();
|
||
|
|
if (availablePads.Count == 0)
|
||
|
|
{
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
DieTransferRegion region = new DieTransferRegion();
|
||
|
|
region.StartRow = availablePads.Min(pad => pad.Row);
|
||
|
|
region.StartCol = availablePads.Min(pad => pad.Column);
|
||
|
|
region.EndRow = availablePads.Max(pad => pad.Row);
|
||
|
|
region.EndCol = availablePads.Max(pad => pad.Column);
|
||
|
|
return region;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static DieTransferRegion CreateRegionFromDies(IEnumerable<Die> dies)
|
||
|
|
{
|
||
|
|
List<Die> availableDies = (dies ?? Array.Empty<Die>()).Where(die => die != null).ToList();
|
||
|
|
if (availableDies.Count == 0)
|
||
|
|
{
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
DieTransferRegion region = new DieTransferRegion();
|
||
|
|
region.StartRow = availableDies.Min(die => die.Row);
|
||
|
|
region.StartCol = availableDies.Min(die => die.Column);
|
||
|
|
region.EndRow = availableDies.Max(die => die.Row);
|
||
|
|
region.EndCol = availableDies.Max(die => die.Column);
|
||
|
|
return region;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|