定义数据类
csharp
/// <summary>
/// 晶圆地图数据
/// </summary>
public class WaferMapData
{
/// <summary>
/// 行数
/// </summary>
public int Rows { get; set; }
/// <summary>
/// 列数
/// </summary>
public int Columns { get; set; }
/// <summary>
/// 数据
/// </summary>
public string[,] Matrix { get; set; }
}
增加helper类
csharp
/// <summary>
/// 晶圆地图帮助类
/// </summary>
public class WaferMapHelper
{
/// <summary>
/// 晶圆图数据解析
/// </summary>
/// <param name="lines">数据</param>
/// <param name="datas">解析数组</param>
/// <param name="isInterval">是否存在间隔</param>
/// <param name="interval">间隔字符串</param>
/// <returns></returns>
public static WaferMapData Parse(string[] lines, Dictionary<string, string> datas, bool isInterval, string interval = " ")
{
int rows = 0, cols = 0;
List<string[]> matrix = new List<string[]>();
// 先按 key 长度倒序排列(先匹配长的,防止例如 "___" 和 "_" 冲突)
var keys = datas.Keys.OrderByDescending(k => k.Length).ToList();
foreach (var line in lines)
{
if (line.StartsWith("ROWCT:"))
rows = int.Parse(line.Substring(6));
else if (line.StartsWith("COLCT:"))
cols = int.Parse(line.Substring(6));
else if (line.StartsWith("RowData:"))
{
string raw = line.Substring(8).Trim();
if (isInterval)
{
raw = raw.Replace(interval, ""); // 如果是间隔分割,则移除间隔字符
}
List<string> rowData = new List<string>();
int i = 0;
while (i < raw.Length)
{
bool matched = false;
foreach (var key in keys)
{
if (i + key.Length <= raw.Length && raw.Substring(i, key.Length) == key)
{
rowData.Add(key);
i += key.Length;
matched = true;
break;
}
}
if (!matched)
{
// 若没有匹配上任何 key,可选择跳过或抛异常,这里添加 '?' 占位
rowData.Add("?");
i += 1;
}
}
matrix.Add(rowData.ToArray());
}
}
// 修正行列数
if (rows != matrix.Count)
rows = matrix.Count;
if (matrix.Count > 0 && cols != matrix[0].Length)
cols = matrix[0].Length;
// 构建结果矩阵
string[,] result = new string[rows, cols];
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
var rawVal = matrix[y][x];
result[y, x] = datas.TryGetValue(rawVal, out var mapped) ? mapped : "?";
}
}
return new WaferMapData
{
Rows = rows,
Columns = cols,
Matrix = result
};
}
/// <summary>
/// 晶圆图渲染
/// </summary>
/// <param name="data">晶圆图数据</param>
/// <param name="dieColorMap">渲染颜色选择</param>
/// <param name="dieSizeX">芯片X尺寸</param>
/// <param name="dieSizeY">芯片Y尺寸</param>
/// <param name="gridThickness">栅格尺寸 等于0则不显示栅格</param>
/// <param name="gridColor">栅格颜色</param>
/// <returns></returns>
public static BitmapSource Render(WaferMapData data, Dictionary<string, Color> dieColorMap, int dieSizeX = 6, int dieSizeY = 6, int gridThickness = 1, Color? gridColor = null)
{
int width = data.Columns * dieSizeX;
int height = data.Rows * dieSizeY;
WriteableBitmap bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
bitmap.Lock();
unsafe
{
IntPtr pBackBuffer = bitmap.BackBuffer;
int stride = bitmap.BackBufferStride;
Color actualGridColor = gridColor ?? Colors.LightGray;
for (int y = 0; y < data.Rows; y++)
{
for (int x = 0; x < data.Columns; x++)
{
string value = data.Matrix[y, x];
Color fillColor = dieColorMap.TryGetValue(value, out var c) ? c : Colors.Gray;
for (int dy = 0; dy < dieSizeY; dy++)
{
for (int dx = 0; dx < dieSizeX; dx++)
{
int px = x * dieSizeX + dx;
int py = y * dieSizeY + dy;
// 当 gridThickness > 0 时才绘制边线
bool isGridLine = gridThickness > 0 &&
(dx < gridThickness || dy < gridThickness);
Color color = isGridLine ? actualGridColor : fillColor;
int offset = py * stride + px * 4;
byte* pPixel = (byte*)pBackBuffer + offset;
pPixel[0] = color.B;
pPixel[1] = color.G;
pPixel[2] = color.R;
pPixel[3] = color.A;
}
}
}
}
}
bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
bitmap.Unlock();
return bitmap;
}
/// <summary>
/// 修改晶圆图数据中指定位置的芯片状态
/// </summary>
/// <param name="data">晶圆图数据</param>
/// <param name="row">目标芯片的行索引(从0开始)</param>
/// <param name="col">目标芯片的列索引(从0开始)</param>
/// <param name="newStatus">新的状态字符</param>
/// <returns>是否成功修改</returns>
public static bool UpdateDieStatus(WaferMapData data, int row, int col, string newStatus)
{
if (row < 0 || row >= data.Rows || col < 0 || col >= data.Columns)
return false;
// 修改状态
data.Matrix[row, col] = newStatus;
return true;
}
/// <summary>
/// 批量修改晶圆图数据中多个芯片的位置状态
/// </summary>
/// <param name="data">晶圆图数据</param>
/// <param name="changes">每项包含 (row, col, newStatus)</param>
/// <returns>成功修改的个数</returns>
public static int UpdateDieStatuses(WaferMapData data, IEnumerable<(int row, int col, string newStatus)> changes)
{
if (data == null || data.Matrix == null)
return 0;
int successCount = 0;
foreach (var (row, col, newStatus) in changes)
{
if (row >= 0 && row < data.Rows && col >= 0 && col < data.Columns)
{
data.Matrix[row, col] = newStatus;
successCount++;
}
}
return successCount;
}
/// <summary>
/// 保存晶圆图为 PNG 文件
/// </summary>
/// <param name="filePath">PNG 文件路径</param>
/// <param name="bitmap">晶圆图数据</param>
public static void SaveBitmapToPng(string filePath, BitmapSource bitmap)
{
FileStream stream = new FileStream(filePath, FileMode.Create);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(stream);
}
/// <summary>
/// 保存晶圆图数据到文件
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="data">晶圆图数据</param>
/// <param name="dieDatas">反解析数组</param>
/// <param name="isInterval">是否保留间隔</param>
/// <param name="interval">间隔字符串</param>
public static void SaveWaferDataToFile(string filePath, WaferMapData data, Dictionary<string, string> dieDatas, bool isInterval, string interval = " ")
{
StreamWriter writer = new StreamWriter(filePath);
writer.WriteLine($"ROWCT:{data.Rows}");
writer.WriteLine($"COLCT:{data.Columns}");
for (int y = 0; y < data.Rows; y++)
{
StringBuilder sb = new StringBuilder("RowData:");
for (int x = 0; x < data.Columns; x++)
{
foreach (var kvp in dieDatas)
{
if (data.Matrix[y, x] == kvp.Key)
{
sb.Append(kvp.Value);
break;
}
}
if (isInterval)
{
sb.Append(interval);
}
}
writer.WriteLine(sb.ToString().TrimEnd());
}
}
/// <summary>
/// 获取晶圆图中所有芯片状态的总数量
/// </summary>
/// <param name="data">晶圆图数据</param>
/// <returns></returns>
public static Dictionary<string, int> CountAllDieStatuses(WaferMapData data)
{
Dictionary<string, int> statusCounts = new Dictionary<string, int>();
if (data == null || data.Matrix == null)
return statusCounts;
for (int y = 0; y < data.Rows; y++)
{
for (int x = 0; x < data.Columns; x++)
{
string value = data.Matrix[y, x];
if (!statusCounts.ContainsKey(value))
statusCounts[value] = 0;
statusCounts[value]++;
}
}
return statusCounts;
}
/// <summary>
/// 获取晶圆图中指定芯片状态的总数量
/// </summary>
/// <param name="data">晶圆图数据</param>
/// <param name="targetStatus">要统计的目标状态(如 "001", "$$$", "X" 等)</param>
/// <returns>该状态芯片的总数</returns>
public static int CountDieStatus(WaferMapData data, string targetStatus)
{
if (data == null || data.Matrix == null)
return 0;
int count = 0;
for (int y = 0; y < data.Rows; y++)
{
for (int x = 0; x < data.Columns; x++)
{
if (data.Matrix[y, x] == targetStatus)
{
count++;
}
}
}
return count;
}
/// <summary>
/// 统计指定行中某个芯片状态的数量
/// </summary>
public static int CountDieStatusInRow(WaferMapData data, int row, string targetStatus)
{
if (data == null || data.Matrix == null || row < 0 || row >= data.Rows)
return 0;
int count = 0;
for (int x = 0; x < data.Columns; x++)
{
if (data.Matrix[row, x] == targetStatus)
count++;
}
return count;
}
/// <summary>
/// 统计指定列中某个芯片状态的数量
/// </summary>
public static int CountDieStatusInColumn(WaferMapData data, int col, string targetStatus)
{
if (data == null || data.Matrix == null || col < 0 || col >= data.Columns)
return 0;
int count = 0;
for (int y = 0; y < data.Rows; y++)
{
if (data.Matrix[y, col] == targetStatus)
count++;
}
return count;
}
/// <summary>
/// 统计指定矩形区域内某个芯片状态的数量
/// </summary>
/// <param name="startRow">起始行索引(包含)</param>
/// <param name="startCol">起始列索引(包含)</param>
/// <param name="endRow">结束行索引(包含)</param>
/// <param name="endCol">结束列索引(包含)</param>
public static int CountDieStatusInRegion(WaferMapData data, int startRow, int startCol, int endRow, int endCol, string targetStatus)
{
if (data == null || data.Matrix == null)
return 0;
int count = 0;
// 限制边界
startRow = Math.Max(0, startRow);
startCol = Math.Max(0, startCol);
endRow = Math.Min(data.Rows - 1, endRow);
endCol = Math.Min(data.Columns - 1, endCol);
for (int y = startRow; y <= endRow; y++)
{
for (int x = startCol; x <= endCol; x++)
{
if (data.Matrix[y, x] == targetStatus)
count++;
}
}
return count;
}
}