BGA手动空隙测量:画气泡圆+焊球圆交互、拖拽调整、空隙率计算、VoidLimit编辑、右键删除
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user