diff --git a/XplorePlane/Models/Inspection/Task/InspectionTaskStage.cs b/XplorePlane/Models/Inspection/Task/InspectionTaskStage.cs
index f26e1641..99d1f7f6 100644
--- a/XplorePlane/Models/Inspection/Task/InspectionTaskStage.cs
+++ b/XplorePlane/Models/Inspection/Task/InspectionTaskStage.cs
@@ -18,6 +18,7 @@ namespace XplorePlane.Models.Inspection.Tasks
BGADetected,
/// Stage 3 检测池 Block 分组完成
PoolGenerated,
+ BubbleParameters,
/// Stage 5 首件 Block 校准完成
Calibration,
/// Stage 6 已应用校准到全部 Block,等待扫描
@@ -42,7 +43,8 @@ namespace XplorePlane.Models.Inspection.Tasks
[InspectionTaskStage.Created] = new[] { InspectionTaskStage.ImageAdjust, InspectionTaskStage.Aborted },
[InspectionTaskStage.ImageAdjust] = new[] { InspectionTaskStage.BGADetected, InspectionTaskStage.Created, InspectionTaskStage.Aborted },
[InspectionTaskStage.BGADetected] = new[] { InspectionTaskStage.PoolGenerated, InspectionTaskStage.ImageAdjust, InspectionTaskStage.Aborted },
- [InspectionTaskStage.PoolGenerated] = new[] { InspectionTaskStage.Calibration, InspectionTaskStage.BGADetected, InspectionTaskStage.Aborted },
+ [InspectionTaskStage.PoolGenerated] = new[] { InspectionTaskStage.BubbleParameters, InspectionTaskStage.BGADetected, InspectionTaskStage.Aborted },
+ [InspectionTaskStage.BubbleParameters] = new[] { InspectionTaskStage.Calibration, InspectionTaskStage.PoolGenerated, InspectionTaskStage.Aborted },
[InspectionTaskStage.Calibration] = new[] { InspectionTaskStage.ReadyToScan, InspectionTaskStage.PoolGenerated, InspectionTaskStage.Aborted },
[InspectionTaskStage.ReadyToScan] = new[] { InspectionTaskStage.Scanning, InspectionTaskStage.Calibration, InspectionTaskStage.Aborted },
[InspectionTaskStage.Scanning] = new[] { InspectionTaskStage.Analysis, InspectionTaskStage.ReadyToScan, InspectionTaskStage.Aborted },
diff --git a/XplorePlane/Services/ImageProcessing/WizardOverlayRenderer.cs b/XplorePlane/Services/ImageProcessing/WizardOverlayRenderer.cs
index e9f6ae2f..87f47679 100644
--- a/XplorePlane/Services/ImageProcessing/WizardOverlayRenderer.cs
+++ b/XplorePlane/Services/ImageProcessing/WizardOverlayRenderer.cs
@@ -101,7 +101,7 @@ namespace XplorePlane.Services.ImageProcessing
Width = Math.Max(1, block.Width),
Height = Math.Max(1, block.Height),
Stroke = stroke,
- StrokeThickness = 2,
+ StrokeThickness = 4,
Fill = Brushes.Transparent,
IsHitTestVisible = false
};
@@ -113,13 +113,13 @@ namespace XplorePlane.Services.ImageProcessing
{
X1 = block.CenterX - crossHalf, Y1 = block.CenterY,
X2 = block.CenterX + crossHalf, Y2 = block.CenterY,
- Stroke = stroke, StrokeThickness = 1.5, IsHitTestVisible = false
+ Stroke = stroke, StrokeThickness = 2.5, IsHitTestVisible = false
};
var vLine = new System.Windows.Shapes.Line
{
X1 = block.CenterX, Y1 = block.CenterY - crossHalf,
X2 = block.CenterX, Y2 = block.CenterY + crossHalf,
- Stroke = stroke, StrokeThickness = 1.5, IsHitTestVisible = false
+ Stroke = stroke, StrokeThickness = 2.5, IsHitTestVisible = false
};
canvas.Children.Add(hLine);
canvas.Children.Add(vLine);
diff --git a/XplorePlane/Services/Inspection/Task/BallOverlayService.cs b/XplorePlane/Services/Inspection/Task/BallOverlayService.cs
index c1f323c6..8d3f5ad9 100644
--- a/XplorePlane/Services/Inspection/Task/BallOverlayService.cs
+++ b/XplorePlane/Services/Inspection/Task/BallOverlayService.cs
@@ -28,9 +28,7 @@ namespace XplorePlane.Services.Inspection.Tasks
{
ArgumentNullException.ThrowIfNull(balls);
ArgumentNullException.ThrowIfNull(context);
- var labels = BgaBallGroupLabeler.AssignLabels(
- balls,
- XplorePlane.Models.Inspection.BgaGridIndexingMode.AlphaNumericTopLeft);
+ var labels = BgaBallGroupLabeler.AssignLabels(balls, context.IndexingMode);
_overlay.PublishBgaBalls(balls.Select(ball => new BallOverlayItem
{
Id = ball.Id,
diff --git a/XplorePlane/Services/Inspection/Task/BlockGeneratorService.cs b/XplorePlane/Services/Inspection/Task/BlockGeneratorService.cs
index 9271eecd..4e90702a 100644
--- a/XplorePlane/Services/Inspection/Task/BlockGeneratorService.cs
+++ b/XplorePlane/Services/Inspection/Task/BlockGeneratorService.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using XplorePlane.Models.Inspection;
using XplorePlane.Models.Inspection.Tasks;
namespace XplorePlane.Services.Inspection.Tasks
@@ -24,7 +25,8 @@ namespace XplorePlane.Services.Inspection.Tasks
InspectionPool GeneratePool(
IReadOnlyList balls,
int columns, int rows, int ballsPerBlock,
- int refWidth, int refHeight);
+ int refWidth, int refHeight,
+ BgaGridIndexingMode indexingMode = BgaGridIndexingMode.AlphaNumericTopLeft);
}
///
@@ -36,7 +38,8 @@ namespace XplorePlane.Services.Inspection.Tasks
public InspectionPool GeneratePool(
IReadOnlyList balls,
int columns, int rows, int ballsPerBlock,
- int refWidth, int refHeight)
+ int refWidth, int refHeight,
+ BgaGridIndexingMode indexingMode = BgaGridIndexingMode.AlphaNumericTopLeft)
{
if (columns <= 0) throw new ArgumentOutOfRangeException(nameof(columns));
if (rows <= 0) throw new ArgumentOutOfRangeException(nameof(rows));
@@ -72,21 +75,17 @@ namespace XplorePlane.Services.Inspection.Tasks
blockId++;
// 计算质心
- double centroidX = cellBalls.Length > 0
- ? cellBalls.Average(b => b.X)
- : (xMin + xMax) / 2.0;
- double centroidY = cellBalls.Length > 0
- ? cellBalls.Average(b => b.Y)
- : (yMin + yMax) / 2.0;
-
- string name = $"{IndexToLetters(row)}{col + 1}";
+ // Block 边界必须使用网格单元中心,不能使用球心作为矩形中心,否则相邻 Block 会重叠。
+ double blockCenterX = (xMin + xMax) / 2.0;
+ double blockCenterY = (yMin + yMax) / 2.0;
+ string name = GetBlockName(row, col, rows, columns, indexingMode);
blocks.Add(new InspectionBlock
{
Id = blockId,
Name = name,
- CenterX = centroidX,
- CenterY = centroidY,
+ CenterX = blockCenterX,
+ CenterY = blockCenterY,
Width = cellWidth,
Height = cellHeight,
Balls = cellBalls,
@@ -107,11 +106,12 @@ namespace XplorePlane.Services.Inspection.Tasks
};
}
- /// 将行索引转换为字母前缀:0→A, 1→B, ..., 25→Z。
- private static string IndexToLetters(int index)
+ private static string GetBlockName(
+ int row, int column, int rows, int columns, BgaGridIndexingMode indexingMode)
{
- if (index < 0) return "?";
- return ((char)('A' + (index % 26))).ToString();
+ var grid = new BgaGridGeometry(
+ rows, columns, 0, 0, Array.Empty(), indexingMode);
+ return BgaTargetIdGenerator.Generate(grid)[row * columns + column];
}
}
-}
\ No newline at end of file
+}
diff --git a/XplorePlane/Services/Inspection/Task/TaskWizardOverlayService.cs b/XplorePlane/Services/Inspection/Task/TaskWizardOverlayService.cs
index 9122f3a6..4b0331d2 100644
--- a/XplorePlane/Services/Inspection/Task/TaskWizardOverlayService.cs
+++ b/XplorePlane/Services/Inspection/Task/TaskWizardOverlayService.cs
@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
+using XplorePlane.Models.Inspection;
namespace XplorePlane.Services.Inspection.Tasks
{
@@ -84,7 +85,8 @@ namespace XplorePlane.Services.Inspection.Tasks
double OriginY = 0,
double ScaleX = 1,
double ScaleY = 1,
- string SourceId = "");
+ string SourceId = "",
+ BgaGridIndexingMode IndexingMode = BgaGridIndexingMode.AlphaNumericTopLeft);
/// Block 叠加层元素。
public class BlockOverlayItem
diff --git a/XplorePlane/ViewModels/Inspection/TaskWizard/InspectionTaskWizardViewModel.cs b/XplorePlane/ViewModels/Inspection/TaskWizard/InspectionTaskWizardViewModel.cs
index fba9a9b0..dbb2a021 100644
--- a/XplorePlane/ViewModels/Inspection/TaskWizard/InspectionTaskWizardViewModel.cs
+++ b/XplorePlane/ViewModels/Inspection/TaskWizard/InspectionTaskWizardViewModel.cs
@@ -204,6 +204,14 @@ namespace XplorePlane.ViewModels.Inspection.TaskWizard
set => SetProperty(ref _ballsPerBlock, value);
}
+ private string _indexingMode = "AlphaNumericTopLeft";
+
+ public string IndexingMode
+ {
+ get => _indexingMode;
+ set => SetProperty(ref _indexingMode, value);
+ }
+
private double _sensitivity = 50.0;
public double Sensitivity
@@ -356,10 +364,11 @@ namespace XplorePlane.ViewModels.Inspection.TaskWizard
"首件校准", // Stage 5
"应用确认", // Stage 6
"自动扫描", // Stage 7
- "结果输出" // Stage 8
+ "结果分析", // Stage 8
+ "结果输出" // Stage 9
};
- public const int StageCount = 9;
+ public const int StageCount = 10;
// ── 命令 ──
@@ -466,6 +475,7 @@ namespace XplorePlane.ViewModels.Inspection.TaskWizard
InspectionTaskStage.ImageAdjust => !string.IsNullOrWhiteSpace(PipelineSummary),
InspectionTaskStage.BGADetected => DetectedBalls.Count > 0,
InspectionTaskStage.PoolGenerated => Pool != null,
+ InspectionTaskStage.BubbleParameters => Pool != null,
InspectionTaskStage.Calibration => TaskCalibrationResult != null,
InspectionTaskStage.ReadyToScan => true,
InspectionTaskStage.Completed => true,
@@ -482,6 +492,7 @@ namespace XplorePlane.ViewModels.Inspection.TaskWizard
InspectionTaskStage.ImageAdjust => string.IsNullOrWhiteSpace(PipelineSummary) ? "PipelineSummary=空" : "PipelineSummary=正常",
InspectionTaskStage.BGADetected => $"DetectedBalls.Count={DetectedBalls.Count}",
InspectionTaskStage.PoolGenerated => $"Pool={(Pool == null ? "null" : "正常")}",
+ InspectionTaskStage.BubbleParameters => $"Pool={(Pool == null ? "null" : "正常")}",
InspectionTaskStage.Calibration => $"TaskCalibrationResult={(TaskCalibrationResult == null ? "null" : "正常")}",
InspectionTaskStage.Scanning => "扫描中,下一步禁用",
InspectionTaskStage.Analysis => "分析中,下一步禁用",
@@ -634,7 +645,8 @@ namespace XplorePlane.ViewModels.Inspection.TaskWizard
BallCoordinateSystem.ViewportImage,
sourceImage.PixelWidth,
sourceImage.PixelHeight,
- SourceId: InspectionTask.Id.ToString()));
+ SourceId: InspectionTask.Id.ToString(),
+ IndexingMode: ParseIndexingMode(IndexingMode)));
_eventAggregator.GetEvent().Publish(DetectedBalls);
CurrentStage = InspectionTaskStage.BGADetected;
}
@@ -660,7 +672,7 @@ namespace XplorePlane.ViewModels.Inspection.TaskWizard
var (refWidth, refHeight) = GetReferenceImageSize();
var pool = _blockGenerator.GeneratePool(
DetectedBalls, PoolColumns, PoolRows, BallsPerBlock,
- refWidth, refHeight);
+ refWidth, refHeight, ParseIndexingMode(IndexingMode));
Pool = pool;
InspectionTask = InspectionTask with { Pool = pool, Stage = InspectionTaskStage.PoolGenerated };
@@ -703,10 +715,11 @@ namespace XplorePlane.ViewModels.Inspection.TaskWizard
if (Pool != null)
{
- InspectionTask = InspectionTask with { BubbleParameters = bp, Stage = InspectionTaskStage.Calibration };
+ InspectionTask = InspectionTask with { BubbleParameters = bp, Stage = InspectionTaskStage.BubbleParameters };
}
- CurrentStage = InspectionTaskStage.Calibration;
+ // 参数设置完成后停留在当前步骤,使“下一步”进入首件校准;校准仍需显式执行。
+ CurrentStage = InspectionTaskStage.BubbleParameters;
_logger.LogInformation("✓ 气泡参数已应用");
}
@@ -1007,5 +1020,13 @@ namespace XplorePlane.ViewModels.Inspection.TaskWizard
return (bitmap.PixelWidth, bitmap.PixelHeight);
return (1024, 1024);
}
+
+ private static BgaGridIndexingMode ParseIndexingMode(string? value) => value switch
+ {
+ "AlphaNumericTopRight" => BgaGridIndexingMode.AlphaNumericTopRight,
+ "AlphaNumericColumnMajorTopLeft" => BgaGridIndexingMode.AlphaNumericColumnMajorTopLeft,
+ "AlphaNumericColumnMajorBottomLeft" => BgaGridIndexingMode.AlphaNumericColumnMajorBottomLeft,
+ _ => BgaGridIndexingMode.AlphaNumericTopLeft
+ };
}
}
diff --git a/XplorePlane/Views/Inspection/TaskWizard/InspectionTaskWizardWindow.xaml b/XplorePlane/Views/Inspection/TaskWizard/InspectionTaskWizardWindow.xaml
index f80a9e7c..4b5f53b8 100644
--- a/XplorePlane/Views/Inspection/TaskWizard/InspectionTaskWizardWindow.xaml
+++ b/XplorePlane/Views/Inspection/TaskWizard/InspectionTaskWizardWindow.xaml
@@ -219,6 +219,7 @@
+
@@ -240,6 +241,17 @@
+
+
+
+
+
+
+
+
+
+