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 { /// BGA 空隙测量中的一个圆(气泡或焊球) 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); } } /// 一次 BGA 空隙测量组(1个焊球 + N个气泡 + 标签) public class BgaVoidGroup { public BgaCircle Ball { get; set; } public List 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; } /// 获取所有 UI 元素 public List AllElements { get { var list = new List(); 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; } } } }