添加 MX-PD-盘古 项目文件
将 MX-PD-盘古 - new 目录下的所有文件添加到主仓库
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user