BGA手动空隙测量:画气泡圆+焊球圆交互、拖拽调整、空隙率计算、VoidLimit编辑、右键删除

This commit is contained in:
李伟
2026-04-27 10:38:56 +08:00
parent e2f1b13e0e
commit e7ae7085df
6 changed files with 350 additions and 6 deletions
@@ -41,7 +41,8 @@
MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseLeftButtonDown="Canvas_MouseLeftButtonDown"
MouseLeftButtonUp="Canvas_MouseLeftButtonUp" MouseLeftButtonUp="Canvas_MouseLeftButtonUp"
MouseMove="Canvas_MouseMove" MouseMove="Canvas_MouseMove"
MouseRightButtonDown="Canvas_MouseRightButtonDown"> MouseRightButtonDown="Canvas_MouseRightButtonDown"
PreviewMouseRightButtonUp="Canvas_PreviewMouseRightButtonUp">
<!-- 背景图像 --> <!-- 背景图像 -->
<Image x:Name="backgroundImage" <Image x:Name="backgroundImage"
@@ -346,6 +346,7 @@ namespace XP.ImageProcessing.RoiControl.Controls
private readonly System.Collections.Generic.List<Models.PointToLineGroup> _ptlGroups = new(); private readonly System.Collections.Generic.List<Models.PointToLineGroup> _ptlGroups = new();
private readonly System.Collections.Generic.List<Models.AngleGroup> _angleGroups = new(); private readonly System.Collections.Generic.List<Models.AngleGroup> _angleGroups = new();
private readonly System.Collections.Generic.List<Models.FillRateGroup> _frGroups = new(); private readonly System.Collections.Generic.List<Models.FillRateGroup> _frGroups = new();
private readonly System.Collections.Generic.List<Models.BgaVoidGroup> _bgaGroups = new();
// 点点距临时状态 // 点点距临时状态
private Ellipse _pendingDot; private Ellipse _pendingDot;
@@ -363,6 +364,12 @@ namespace XP.ImageProcessing.RoiControl.Controls
private Line _angleTempLineA; private Line _angleTempLineA;
private Point? _angleTempV, _angleTempA; private Point? _angleTempV, _angleTempA;
// BGA 空隙测量状态
private Models.BgaVoidGroup _bgaCurrent; // 当前正在编辑的 BGA 组
private bool _bgaDrawBall; // true=画焊球, false=画气泡
private Point? _bgaPendingCenter; // 等待第二次点击定半径
private Ellipse _bgaPendingDot;
// 拖拽状态 // 拖拽状态
private Ellipse _mDraggingDot; private Ellipse _mDraggingDot;
private object _mDraggingOwner; private object _mDraggingOwner;
@@ -396,6 +403,8 @@ namespace XP.ImageProcessing.RoiControl.Controls
if (_angleTempADot != null) { _measureOverlay.Children.Remove(_angleTempADot); _angleTempADot = null; } if (_angleTempADot != null) { _measureOverlay.Children.Remove(_angleTempADot); _angleTempADot = null; }
if (_angleTempLineA != null) { _measureOverlay.Children.Remove(_angleTempLineA); _angleTempLineA = null; } if (_angleTempLineA != null) { _measureOverlay.Children.Remove(_angleTempLineA); _angleTempLineA = null; }
_angleTempV = _angleTempA = null; _angleClickCount = 0; _angleTempV = _angleTempA = null; _angleClickCount = 0;
if (_bgaPendingDot != null) { _measureOverlay.Children.Remove(_bgaPendingDot); _bgaPendingDot = null; }
_bgaPendingCenter = null;
} }
private void EnsureMeasureOverlay() private void EnsureMeasureOverlay()
@@ -410,7 +419,7 @@ namespace XP.ImageProcessing.RoiControl.Controls
private void RemoveMeasureOverlay() private void RemoveMeasureOverlay()
{ {
if (_measureOverlay != null) { mainCanvas.Children.Remove(_measureOverlay); _measureOverlay = null; } if (_measureOverlay != null) { mainCanvas.Children.Remove(_measureOverlay); _measureOverlay = null; }
_ppGroups.Clear(); _ptlGroups.Clear(); _angleGroups.Clear(); _frGroups.Clear(); _ppGroups.Clear(); _ptlGroups.Clear(); _angleGroups.Clear(); _frGroups.Clear(); _bgaGroups.Clear();
_pendingDot = null; _pendingPoint = null; _pendingDot = null; _pendingPoint = null;
_ptlTempDot1 = _ptlTempDot2 = null; _ptlTempLine = null; _ptlTempDot1 = _ptlTempDot2 = null; _ptlTempLine = null;
_ptlTempL1 = _ptlTempL2 = null; _ptlClickCount = 0; _ptlTempL1 = _ptlTempL2 = null; _ptlClickCount = 0;
@@ -420,7 +429,7 @@ namespace XP.ImageProcessing.RoiControl.Controls
} }
public void ClearMeasurements() => RemoveMeasureOverlay(); public void ClearMeasurements() => RemoveMeasureOverlay();
public int MeasureCount => _ppGroups.Count + _ptlGroups.Count + _angleGroups.Count + _frGroups.Count; public int MeasureCount => _ppGroups.Count + _ptlGroups.Count + _angleGroups.Count + _frGroups.Count + _bgaGroups.Count;
// ── 点击分发 ── // ── 点击分发 ──
@@ -437,6 +446,8 @@ namespace XP.ImageProcessing.RoiControl.Controls
HandleAngleClick(pos); HandleAngleClick(pos);
else if (CurrentMeasureMode == Models.MeasureMode.FillRate) else if (CurrentMeasureMode == Models.MeasureMode.FillRate)
HandleFillRateClick(pos); HandleFillRateClick(pos);
else if (CurrentMeasureMode == Models.MeasureMode.BgaVoid)
HandleBgaVoidClick(pos);
} }
// ── 点点距 ── // ── 点点距 ──
@@ -634,7 +645,7 @@ namespace XP.ImageProcessing.RoiControl.Controls
g.Label = new TextBlock { FontSize = 13, FontWeight = FontWeights.Bold, Cursor = Cursors.Hand }; g.Label = new TextBlock { FontSize = 13, FontWeight = FontWeights.Bold, Cursor = Cursors.Hand };
g.Label.SetValue(ContextMenuService.IsEnabledProperty, false); g.Label.SetValue(ContextMenuService.IsEnabledProperty, false);
g.Label.MouseRightButtonUp += (s, ev) => { ShowTHTLimitEditor(g); ev.Handled = true; }; g.Label.PreviewMouseRightButtonUp += (s, ev) => { ShowTHTLimitEditor(g); ev.Handled = true; };
g.DotE1 = CreateMDot(Brushes.DodgerBlue); g.DotE1 = CreateMDot(Brushes.DodgerBlue);
g.DotE2 = CreateMDot(Brushes.Cyan); g.DotE2 = CreateMDot(Brushes.Cyan);
@@ -674,6 +685,153 @@ namespace XP.ImageProcessing.RoiControl.Controls
return p; return p;
} }
// ── BGA 空隙测量 ──
private void HandleBgaVoidClick(Point pos)
{
if (_measureOverlay == null) EnsureMeasureOverlay();
if (_measureOverlay == null) return;
// 第一次进入:创建新的 BGA 组
if (_bgaCurrent == null)
{
_bgaCurrent = new Models.BgaVoidGroup();
var currentGroup = _bgaCurrent; // 局部变量供闭包捕获
_bgaCurrent.Label = new TextBlock { FontSize = 13, FontWeight = FontWeights.Bold, Cursor = System.Windows.Input.Cursors.Hand, Visibility = Visibility.Collapsed };
_bgaCurrent.Label.SetValue(ContextMenuService.IsEnabledProperty, false);
_bgaCurrent.Label.PreviewMouseRightButtonUp += (s, ev) => { ShowBgaLimitEditor(currentGroup); ev.Handled = true; };
_measureOverlay.Children.Add(_bgaCurrent.Label);
_bgaDrawBall = false;
RaiseMeasureStatusChanged("BGA空隙 - 点击画气泡圆心(右键切换为画焊球)");
}
if (!_bgaPendingCenter.HasValue)
{
// 第一次点击:圆心
_bgaPendingCenter = pos;
_bgaPendingDot = CreateMDot(_bgaDrawBall ? Brushes.Lime : Brushes.Orange);
_measureOverlay.Children.Add(_bgaPendingDot);
SetDotPos(_bgaPendingDot, pos);
RaiseMeasureStatusChanged(_bgaDrawBall ? "BGA - 焊球圆心已定,点击边缘定半径" : "BGA - 气泡圆心已定,点击边缘定半径");
}
else
{
// 第二次点击:半径
double r = Math.Max(5, Models.FillRateGroup.Dist(pos, _bgaPendingCenter.Value));
var circle = CreateBgaCircle(_bgaPendingCenter.Value, r, _bgaDrawBall);
if (_bgaDrawBall)
{
// 如果已有焊球,移除旧的
if (_bgaCurrent.Ball != null)
{
_measureOverlay.Children.Remove(_bgaCurrent.Ball.Shape);
_measureOverlay.Children.Remove(_bgaCurrent.Ball.CenterDot);
_measureOverlay.Children.Remove(_bgaCurrent.Ball.EdgeDot);
}
_bgaCurrent.Ball = circle;
// 画完焊球 → 完成本组,计算结果
_bgaGroups.Add(_bgaCurrent);
RenumberAll();
_bgaCurrent.UpdateLabel();
_bgaCurrent.Label.Cursor = System.Windows.Input.Cursors.Hand;
RaiseMeasureCompleted(_bgaCurrent.Ball.Center, _bgaCurrent.Ball.Center, _bgaCurrent.VoidRate, MeasureCount, "BgaVoid");
_bgaCurrent = null;
_bgaDrawBall = false;
CurrentMeasureMode = Models.MeasureMode.None;
}
else
{
_bgaCurrent.Voids.Add(circle);
RaiseMeasureStatusChanged($"BGA - 已画 {_bgaCurrent.Voids.Count} 个气泡,继续画气泡或右键切换画焊球");
}
// 清除临时点
if (_bgaPendingDot != null) { _measureOverlay.Children.Remove(_bgaPendingDot); _bgaPendingDot = null; }
_bgaPendingCenter = null;
}
}
/// <summary>右键切换气泡/焊球模式(在 BGA 测量模式下)</summary>
private void HandleBgaRightClick()
{
if (CurrentMeasureMode != Models.MeasureMode.BgaVoid || _bgaCurrent == null) return;
_bgaDrawBall = !_bgaDrawBall;
RaiseMeasureStatusChanged(_bgaDrawBall ? "BGA - 已切换为画焊球模式" : "BGA - 已切换为画气泡模式");
}
private Models.BgaCircle CreateBgaCircle(Point center, double radius, bool isBall)
{
var c = new Models.BgaCircle { Center = center, Radius = radius, IsBall = isBall };
c.Shape = new Ellipse
{
Stroke = isBall ? Brushes.Lime : Brushes.Orange,
StrokeThickness = isBall ? 2 : 1.5,
Fill = Brushes.Transparent,
IsHitTestVisible = false
};
c.CenterDot = CreateMDot(isBall ? Brushes.Lime : Brushes.Orange);
c.EdgeDot = CreateMDot(isBall ? Brushes.Lime : Brushes.Orange);
c.EdgeDot.Width = 8; c.EdgeDot.Height = 8;
c.EdgeDot.Cursor = System.Windows.Input.Cursors.SizeAll;
_measureOverlay.Children.Add(c.Shape);
_measureOverlay.Children.Add(c.CenterDot);
_measureOverlay.Children.Add(c.EdgeDot);
c.UpdateVisuals();
return c;
}
// BGA Limit 编辑(和 FillRate 类似)
private void ShowBgaLimitEditor(Models.BgaVoidGroup g)
{
if (_measureOverlay == null || g == null) return;
RemoveTHTEditor();
double left = Canvas.GetLeft(g.Label);
double top = Canvas.GetTop(g.Label) + 22;
_thtEditLabel = new TextBlock
{
Text = "VoidLimit(%):",
FontSize = 11, Foreground = Brushes.White,
Background = new SolidColorBrush(Color.FromArgb(180, 0, 0, 0)),
Padding = new Thickness(3, 1, 3, 1)
};
Canvas.SetLeft(_thtEditLabel, left);
Canvas.SetTop(_thtEditLabel, top);
_measureOverlay.Children.Add(_thtEditLabel);
_thtEditBox = new TextBox
{
Text = g.VoidLimit.ToString("F1"),
Width = 60, Height = 22, FontSize = 12,
Background = Brushes.White, BorderBrush = Brushes.Orange, BorderThickness = new Thickness(2),
Padding = new Thickness(2, 0, 2, 0)
};
Canvas.SetLeft(_thtEditBox, left + 85);
Canvas.SetTop(_thtEditBox, top);
_measureOverlay.Children.Add(_thtEditBox);
_thtEditBox.Focus();
_thtEditBox.SelectAll();
_thtEditBox.KeyDown += (s, ev) =>
{
if (ev.Key == System.Windows.Input.Key.Enter)
{
if (double.TryParse(_thtEditBox.Text, out double val))
{
g.VoidLimit = System.Math.Clamp(val, 0, 100);
g.UpdateLabel();
RaiseMeasureCompleted(g.Ball?.Center ?? default, g.Ball?.Center ?? default, g.VoidRate, MeasureCount, "BgaVoid");
}
RemoveTHTEditor();
}
else if (ev.Key == System.Windows.Input.Key.Escape) RemoveTHTEditor();
};
_thtEditBox.LostFocus += (s, ev) => RemoveTHTEditor();
}
// ── 共用:圆点创建、定位、拖拽、删除 ── // ── 共用:圆点创建、定位、拖拽、删除 ──
private Ellipse CreateMDot(Brush fill) private Ellipse CreateMDot(Brush fill)
@@ -741,6 +899,22 @@ namespace XP.ImageProcessing.RoiControl.Controls
if (g.E4BH == dot) { _mDraggingOwner = g; _mDraggingRole = "E4B"; break; } if (g.E4BH == dot) { _mDraggingOwner = g; _mDraggingRole = "E4B"; break; }
} }
} }
// 查找 BGA 组
if (_mDraggingOwner == null)
{
foreach (var g in _bgaGroups)
{
if (g.Ball?.CenterDot == dot) { _mDraggingOwner = g; _mDraggingRole = "BallCenter"; break; }
if (g.Ball?.EdgeDot == dot) { _mDraggingOwner = g; _mDraggingRole = "BallEdge"; break; }
bool found = false;
for (int vi = 0; vi < g.Voids.Count; vi++)
{
if (g.Voids[vi].CenterDot == dot) { _mDraggingOwner = g; _mDraggingRole = $"V{vi}Center"; found = true; break; }
if (g.Voids[vi].EdgeDot == dot) { _mDraggingOwner = g; _mDraggingRole = $"V{vi}Edge"; found = true; break; }
}
if (found) break;
}
}
if (_mDraggingOwner != null) { _mDraggingDot = dot; dot.CaptureMouse(); e.Handled = true; } if (_mDraggingOwner != null) { _mDraggingDot = dot; dot.CaptureMouse(); e.Handled = true; }
} }
@@ -791,6 +965,35 @@ namespace XP.ImageProcessing.RoiControl.Controls
frg.UpdateVisuals(); frg.UpdateVisuals();
RaiseMeasureCompleted(frg.E3, frg.E4, frg.FillRate, MeasureCount, "FillRate"); RaiseMeasureCompleted(frg.E3, frg.E4, frg.FillRate, MeasureCount, "FillRate");
} }
else if (_mDraggingOwner is Models.BgaVoidGroup bgag)
{
if (_mDraggingRole == "BallCenter" && bgag.Ball != null)
{
bgag.Ball.Center = pos; bgag.Ball.UpdateVisuals();
}
else if (_mDraggingRole == "BallEdge" && bgag.Ball != null)
{
bgag.Ball.Radius = Math.Max(5, Models.FillRateGroup.Dist(pos, bgag.Ball.Center));
bgag.Ball.UpdateVisuals();
}
else if (_mDraggingRole.StartsWith("V") && _mDraggingRole.Length > 1)
{
// 解析 V{index}Center 或 V{index}Edge
string rest = _mDraggingRole.Substring(1);
bool isEdge = rest.EndsWith("Edge");
string idxStr = isEdge ? rest.Replace("Edge", "") : rest.Replace("Center", "");
if (int.TryParse(idxStr, out int vi) && vi >= 0 && vi < bgag.Voids.Count)
{
if (isEdge)
bgag.Voids[vi].Radius = Math.Max(5, Models.FillRateGroup.Dist(pos, bgag.Voids[vi].Center));
else
bgag.Voids[vi].Center = pos;
bgag.Voids[vi].UpdateVisuals();
}
}
bgag.UpdateLabel();
RaiseMeasureCompleted(bgag.Ball?.Center ?? default, bgag.Ball?.Center ?? default, bgag.VoidRate, MeasureCount, "BgaVoid");
}
e.Handled = true; e.Handled = true;
} }
@@ -858,6 +1061,27 @@ namespace XP.ImageProcessing.RoiControl.Controls
e.Handled = true; return; e.Handled = true; return;
} }
} }
// BGA 删除
foreach (var g in _bgaGroups)
{
bool match = g.Ball?.CenterDot == dot || g.Ball?.EdgeDot == dot;
if (!match)
{
foreach (var v in g.Voids)
{
if (v.CenterDot == dot || v.EdgeDot == dot) { match = true; break; }
}
}
if (match)
{
foreach (var el in g.AllElements)
_measureOverlay.Children.Remove(el);
_bgaGroups.Remove(g);
RenumberAll();
RaiseMeasureStatusChanged($"已删除测量 | 剩余 {MeasureCount} 条");
e.Handled = true; return;
}
}
} }
// ── 重编号 ── // ── 重编号 ──
@@ -885,6 +1109,11 @@ namespace XP.ImageProcessing.RoiControl.Controls
_frGroups[i].Index = i + 1; _frGroups[i].Index = i + 1;
_frGroups[i].UpdateVisuals(); _frGroups[i].UpdateVisuals();
} }
for (int i = 0; i < _bgaGroups.Count; i++)
{
_bgaGroups[i].Index = i + 1;
_bgaGroups[i].UpdateLabel();
}
} }
// ── 填锡率阈值编辑 ── // ── 填锡率阈值编辑 ──
@@ -1164,11 +1393,27 @@ namespace XP.ImageProcessing.RoiControl.Controls
private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e) private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{ {
// BGA 模式下右键切换气泡/焊球
if (CurrentMeasureMode == Models.MeasureMode.BgaVoid && _bgaCurrent != null)
{
HandleBgaRightClick();
e.Handled = true;
return;
}
// 右键点击完成多边形 // 右键点击完成多边形
OnRightClick(); OnRightClick();
// 不设 e.Handled,让 ContextMenu 正常弹出 // 不设 e.Handled,让 ContextMenu 正常弹出
} }
private void Canvas_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
// BGA 模式下阻止 ContextMenu 弹出
if (CurrentMeasureMode == Models.MeasureMode.BgaVoid && _bgaCurrent != null)
{
e.Handled = true;
}
}
private void ROI_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) private void ROI_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{ {
// 选择ROI // 选择ROI
@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace XP.ImageProcessing.RoiControl.Models
{
/// <summary>BGA 空隙测量中的一个圆(气泡或焊球)</summary>
public class BgaCircle
{
public Ellipse Shape { get; set; } // 圆形轮廓
public Ellipse CenterDot { get; set; } // 中心拖拽点
public Ellipse EdgeDot { get; set; } // 边缘拖拽点(调半径)
public Point Center { get; set; }
public double Radius { get; set; }
public bool IsBall { get; set; } // true=焊球, false=气泡
public double Area => Math.PI * Radius * Radius;
public void UpdateVisuals()
{
double d = Radius * 2;
Shape.Width = d; Shape.Height = d;
Canvas.SetLeft(Shape, Center.X - Radius);
Canvas.SetTop(Shape, Center.Y - Radius);
Canvas.SetLeft(CenterDot, Center.X - CenterDot.Width / 2);
Canvas.SetTop(CenterDot, Center.Y - CenterDot.Height / 2);
var edgePt = new Point(Center.X + Radius, Center.Y);
Canvas.SetLeft(EdgeDot, edgePt.X - EdgeDot.Width / 2);
Canvas.SetTop(EdgeDot, edgePt.Y - EdgeDot.Height / 2);
}
}
/// <summary>一次 BGA 空隙测量组(1个焊球 + N个气泡 + 标签)</summary>
public class BgaVoidGroup
{
public BgaCircle Ball { get; set; }
public List<BgaCircle> Voids { get; } = new();
public TextBlock Label { get; set; }
public int Index { get; set; }
public double VoidLimit { get; set; } = 25.0;
public double VoidRate
{
get
{
if (Ball == null || Ball.Area < 1) return 0;
double totalVoid = 0;
foreach (var v in Voids) totalVoid += v.Area;
return Math.Clamp(totalVoid / Ball.Area * 100.0, 0, 100);
}
}
public string Classification => VoidRate <= VoidLimit ? "PASS" : "FAIL";
public void UpdateLabel()
{
if (Label == null || Ball == null) return;
double rate = VoidRate;
string cls = Classification;
Label.Text = (Index > 0 ? $"#{Index} " : "") +
$"Void: {rate:F1}% | Limit: {VoidLimit:F1}% | {cls}";
Label.Foreground = cls == "PASS" ? Brushes.Lime : Brushes.Red;
Canvas.SetLeft(Label, Ball.Center.X + Ball.Radius + 10);
Canvas.SetTop(Label, Ball.Center.Y - 10);
Label.Visibility = Visibility.Visible;
}
/// <summary>获取所有 UI 元素</summary>
public List<UIElement> AllElements
{
get
{
var list = new List<UIElement>();
if (Ball != null) { list.Add(Ball.Shape); list.Add(Ball.CenterDot); list.Add(Ball.EdgeDot); }
foreach (var v in Voids) { list.Add(v.Shape); list.Add(v.CenterDot); list.Add(v.EdgeDot); }
if (Label != null) list.Add(Label);
return list;
}
}
}
}
@@ -6,6 +6,7 @@ namespace XP.ImageProcessing.RoiControl.Models
PointDistance, PointDistance,
PointToLine, PointToLine,
Angle, Angle,
FillRate FillRate,
BgaVoid
} }
} }
+8 -1
View File
@@ -443,7 +443,7 @@
Text="通孔填锡率" /> Text="通孔填锡率" />
</StackPanel> </StackPanel>
<!-- 第三列: BGA空隙测量 --> <!-- 第三列: BGA空隙测量 + 气泡测量 -->
<StackPanel> <StackPanel>
<telerik:RadRibbonButton <telerik:RadRibbonButton
telerik:ScreenTip.Description="BGA焊球空隙率检测" telerik:ScreenTip.Description="BGA焊球空隙率检测"
@@ -452,6 +452,13 @@
Size="Medium" Size="Medium"
SmallImage="/Assets/Icons/bga.png" SmallImage="/Assets/Icons/bga.png"
Text="BGA空隙" /> Text="BGA空隙" />
<telerik:RadRibbonButton
telerik:ScreenTip.Description="手动气泡测量(魔棒+画笔)"
telerik:ScreenTip.Title="气泡测量"
Command="{Binding BubbleMeasureCommand}"
Size="Medium"
SmallImage="/Assets/Icons/pores.png"
Text="气泡测量" />
</StackPanel> </StackPanel>
</telerik:RadRibbonGroup> </telerik:RadRibbonGroup>
<!-- <!--
@@ -41,12 +41,14 @@ namespace XplorePlane.Views
"PointToLine" => "点线距", "PointToLine" => "点线距",
"Angle" => "角度", "Angle" => "角度",
"FillRate" => "填锡率", "FillRate" => "填锡率",
"BgaVoid" => "BGA空隙",
_ => "点点距" _ => "点点距"
}; };
string valueText = args.MeasureType switch string valueText = args.MeasureType switch
{ {
"Angle" => $"{args.Distance:F2}°", "Angle" => $"{args.Distance:F2}°",
"FillRate" => $"{args.Distance:F1}%", "FillRate" => $"{args.Distance:F1}%",
"BgaVoid" => $"{args.Distance:F1}%",
_ => $"{args.Distance:F2} px" _ => $"{args.Distance:F2} px"
}; };
SetStatus($"{typeLabel}: {valueText} | 共 {args.TotalCount} 条测量"); SetStatus($"{typeLabel}: {valueText} | 共 {args.TotalCount} 条测量");
@@ -76,6 +78,7 @@ namespace XplorePlane.Views
MeasurementToolMode.PointLineDistance => XP.ImageProcessing.RoiControl.Models.MeasureMode.PointToLine, MeasurementToolMode.PointLineDistance => XP.ImageProcessing.RoiControl.Models.MeasureMode.PointToLine,
MeasurementToolMode.Angle => XP.ImageProcessing.RoiControl.Models.MeasureMode.Angle, MeasurementToolMode.Angle => XP.ImageProcessing.RoiControl.Models.MeasureMode.Angle,
MeasurementToolMode.ThroughHoleFillRate => XP.ImageProcessing.RoiControl.Models.MeasureMode.FillRate, MeasurementToolMode.ThroughHoleFillRate => XP.ImageProcessing.RoiControl.Models.MeasureMode.FillRate,
MeasurementToolMode.BgaVoid => XP.ImageProcessing.RoiControl.Models.MeasureMode.BgaVoid,
_ => XP.ImageProcessing.RoiControl.Models.MeasureMode.None _ => XP.ImageProcessing.RoiControl.Models.MeasureMode.None
}; };
}, Prism.Events.ThreadOption.UIThread); }, Prism.Events.ThreadOption.UIThread);