Files
test_demo/MX-PD-盘古 - new/PanGu.DieBonderApp/MainShell/Process/DieTransfer/DiePositioning/WaferScanPlanner.cs

191 lines
8.6 KiB
C#
Raw Normal View History

using MaxwellFramework.Core.Attributes;
using System;
using MainShell.Common;
using MainShell.Recipe.Models;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
namespace MainShell.Process
{
[Singleton]
public class WaferScanPlanner : IWaferScanPlanner
{
private readonly IWaferMachineAdapter _waferMachineAdapter;
public WaferScanPlanner(IWaferMachineAdapter waferMachineAdapter)
{
_waferMachineAdapter = waferMachineAdapter ?? throw new ArgumentNullException(nameof(waferMachineAdapter));
}
public WaferScanPlan CreatePlan(WaferDiePositionContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
WaferScanSettings scanSettings = context.ScanSettings ?? throw new InvalidOperationException("DiePosition: scan settings are required for scan planning.");
Point cameraFieldOfView = _waferMachineAdapter.GetCameraFieldOfView(context);
ValidateCameraFieldOfView(cameraFieldOfView);
WaferScanArea scanArea = BuildScanArea(context, scanSettings, cameraFieldOfView);
double stepX = CalculateStep(cameraFieldOfView.X, scanSettings.OverlapRateX);
double stepY = CalculateStep(cameraFieldOfView.Y, scanSettings.OverlapRateY);
int scanColumnCount = CalculateScanCount(scanArea.WaferWidth, cameraFieldOfView.X, stepX);
int scanRowCount = CalculateScanCount(scanArea.WaferHeight, cameraFieldOfView.Y, stepY);
List<Point> rawPathPoints = BuildRawPathPoints(scanArea, scanSettings, stepX, stepY, scanColumnCount, scanRowCount);
List<WaferPlannerPointAdjustment> adjustments = new List<WaferPlannerPointAdjustment>();
List<Point> finalPathPoints = BuildAdjustedPathPoints(rawPathPoints, context, scanSettings, adjustments);
Point startPoint = finalPathPoints.Count > 0 ? finalPathPoints[0] : scanArea.StartPoint;
Point endPoint = finalPathPoints.Count > 0 ? finalPathPoints[finalPathPoints.Count - 1] : scanArea.EndPoint;
WaferScanPlan scanPlan = new WaferScanPlan();
scanPlan.ScanRowCount = scanRowCount;
scanPlan.ScanColumnCount = scanColumnCount;
scanPlan.PathPoints = finalPathPoints;
scanPlan.RawPathPoints = rawPathPoints;
scanPlan.FinalPathPoints = finalPathPoints;
scanPlan.ScanArea = scanArea;
scanPlan.StartPoint = startPoint;
scanPlan.EndPoint = endPoint;
scanPlan.StepX = stepX;
scanPlan.StepY = stepY;
scanPlan.OverlapX = NormalizeOverlap(scanSettings.OverlapRateX);
scanPlan.OverlapY = NormalizeOverlap(scanSettings.OverlapRateY);
scanPlan.Adjustments = adjustments;
scanPlan.PathGenerationMessage = string.Format(
CultureInfo.InvariantCulture,
"DiePosition: generated serpentine scan plan with {0} points ({1}x{2}), stepX={3:F3}, stepY={4:F3}, adjusted={5}.",
scanPlan.PathPointCount,
scanColumnCount,
scanRowCount,
stepX,
stepY,
adjustments.Count(x => x.WasAdjusted));
scanPlan.SoftLimitAdjustedCount = adjustments.Count(x => x.WasAdjusted);
scanPlan.AddedCoveragePointCount = 0;
context.ScanArea = scanArea;
return scanPlan;
}
private static void ValidateCameraFieldOfView(Point cameraFieldOfView)
{
if (cameraFieldOfView.X <= 0d || cameraFieldOfView.Y <= 0d)
{
throw new InvalidOperationException("DiePosition: camera field of view must be greater than zero.");
}
}
private static WaferScanArea BuildScanArea(WaferDiePositionContext context, WaferScanSettings scanSettings, Point cameraFieldOfView)
{
double waferWidth = context.WaferRecipe != null && context.WaferRecipe.WaferInfo != null ? context.WaferRecipe.WaferInfo.WaferWidth : 0d;
double waferHeight = context.WaferRecipe != null && context.WaferRecipe.WaferInfo != null ? context.WaferRecipe.WaferInfo.WaferHeight : 0d;
double effectiveWaferWidth = Math.Max(cameraFieldOfView.X, waferWidth);
double effectiveWaferHeight = Math.Max(cameraFieldOfView.Y, waferHeight);
double endX = scanSettings.StartPointX + ResolveDirectionSign(scanSettings.ScanDirectionX) * Math.Max(0d, effectiveWaferWidth - cameraFieldOfView.X);
double endY = scanSettings.StartPointY + ResolveDirectionSign(scanSettings.ScanDirectionY) * Math.Max(0d, effectiveWaferHeight - cameraFieldOfView.Y);
WaferScanArea scanArea = new WaferScanArea();
scanArea.StartPoint = new Point(scanSettings.StartPointX, scanSettings.StartPointY);
scanArea.EndPoint = new Point(endX, endY);
scanArea.MinX = Math.Min(scanArea.StartPoint.X, scanArea.EndPoint.X);
scanArea.MaxX = Math.Max(scanArea.StartPoint.X, scanArea.EndPoint.X);
scanArea.MinY = Math.Min(scanArea.StartPoint.Y, scanArea.EndPoint.Y);
scanArea.MaxY = Math.Max(scanArea.StartPoint.Y, scanArea.EndPoint.Y);
scanArea.WaferWidth = effectiveWaferWidth;
scanArea.WaferHeight = effectiveWaferHeight;
return scanArea;
}
private static double CalculateStep(double fov, double overlapRate)
{
double normalizedOverlap = NormalizeOverlap(overlapRate);
double step = fov * (1d - normalizedOverlap);
if (step <= 0d)
{
return fov;
}
return step;
}
private static double NormalizeOverlap(double overlapRate)
{
if (overlapRate < 0d)
{
return 0d;
}
if (overlapRate >= 1d)
{
return 0.95d;
}
return overlapRate;
}
private static int CalculateScanCount(double waferSpan, double fov, double step)
{
if (waferSpan <= fov)
{
return 1;
}
return (int)Math.Ceiling((waferSpan - fov) / step) + 1;
}
private static List<Point> BuildRawPathPoints(WaferScanArea scanArea, WaferScanSettings scanSettings, double stepX, double stepY, int scanColumnCount, int scanRowCount)
{
List<Point> rawPathPoints = new List<Point>();
int directionX = ResolveDirectionSign(scanSettings.ScanDirectionX);
int directionY = ResolveDirectionSign(scanSettings.ScanDirectionY);
for (int rowIndex = 0; rowIndex < scanRowCount; rowIndex++)
{
double y = scanArea.StartPoint.Y + rowIndex * stepY * directionY;
bool reverseColumns = rowIndex % 2 == 1;
for (int columnIndex = 0; columnIndex < scanColumnCount; columnIndex++)
{
int serpentineColumnIndex = reverseColumns ? (scanColumnCount - 1 - columnIndex) : columnIndex;
double x = scanArea.StartPoint.X + serpentineColumnIndex * stepX * directionX;
rawPathPoints.Add(new Point(x, y));
}
}
return rawPathPoints;
}
private List<Point> BuildAdjustedPathPoints(List<Point> rawPathPoints, WaferDiePositionContext context, WaferScanSettings scanSettings, List<WaferPlannerPointAdjustment> adjustments)
{
List<Point> adjustedPathPoints = new List<Point>();
foreach (Point rawPathPoint in rawPathPoints)
{
Point adjustedPoint = _waferMachineAdapter.AdjustPointWithinSoftLimit(
rawPathPoint,
context,
scanSettings.SoftLimitOffsetMm,
out bool adjusted,
out string reason);
WaferPlannerPointAdjustment adjustment = new WaferPlannerPointAdjustment();
adjustment.OriginalPoint = rawPathPoint;
adjustment.AdjustedPoint = adjustedPoint;
adjustment.WasAdjusted = adjusted;
adjustment.Reason = reason;
adjustments.Add(adjustment);
adjustedPathPoints.Add(adjustedPoint);
}
return adjustedPathPoints;
}
private static int ResolveDirectionSign(TransPathDirection direction)
{
return direction == TransPathDirection.Negative ? -1 : 1;
}
}
}