集成测量工具:点点距、点线距、角度测量;十字辅助线;右键菜单;图像自适应窗口优化
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace XP.ImageProcessing.RoiControl.Models
|
||||
{
|
||||
/// <summary>一次角度测量的所有视觉元素(顶点V + 射线端点A/B + 两条射线 + 弧线 + 标签)</summary>
|
||||
public class AngleGroup
|
||||
{
|
||||
public Ellipse DotV { get; set; } // 顶点
|
||||
public Ellipse DotA { get; set; } // 射线端点A
|
||||
public Ellipse DotB { get; set; } // 射线端点B
|
||||
public Line LineA { get; set; } // 射线VA
|
||||
public Line LineB { get; set; } // 射线VB
|
||||
public Path Arc { get; set; } // 角度弧线
|
||||
public TextBlock Label { get; set; }
|
||||
public Point V { get; set; }
|
||||
public Point A { get; set; }
|
||||
public Point B { get; set; }
|
||||
|
||||
public double AngleDeg
|
||||
{
|
||||
get
|
||||
{
|
||||
double vax = A.X - V.X, vay = A.Y - V.Y;
|
||||
double vbx = B.X - V.X, vby = B.Y - V.Y;
|
||||
double lenA = Math.Sqrt(vax * vax + vay * vay);
|
||||
double lenB = Math.Sqrt(vbx * vbx + vby * vby);
|
||||
if (lenA < 0.001 || lenB < 0.001) return 0;
|
||||
double dot = vax * vbx + vay * vby;
|
||||
double cos = Math.Clamp(dot / (lenA * lenB), -1.0, 1.0);
|
||||
return Math.Acos(cos) * 180.0 / Math.PI;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateVisuals()
|
||||
{
|
||||
// 射线
|
||||
LineA.X1 = V.X; LineA.Y1 = V.Y; LineA.X2 = A.X; LineA.Y2 = A.Y;
|
||||
LineA.Visibility = Visibility.Visible;
|
||||
LineB.X1 = V.X; LineB.Y1 = V.Y; LineB.X2 = B.X; LineB.Y2 = B.Y;
|
||||
LineB.Visibility = Visibility.Visible;
|
||||
|
||||
// 弧线
|
||||
double vax = A.X - V.X, vay = A.Y - V.Y;
|
||||
double vbx = B.X - V.X, vby = B.Y - V.Y;
|
||||
double lenA = Math.Sqrt(vax * vax + vay * vay);
|
||||
double lenB = Math.Sqrt(vbx * vbx + vby * vby);
|
||||
|
||||
if (lenA < 1 || lenB < 1) { Arc.Visibility = Visibility.Collapsed; return; }
|
||||
|
||||
double arcRadius = Math.Min(30, Math.Min(lenA, lenB) * 0.3);
|
||||
if (arcRadius < 8) arcRadius = 8;
|
||||
|
||||
double angleARad = Math.Atan2(vay, vax);
|
||||
double angleBRad = Math.Atan2(vby, vbx);
|
||||
double cross = vax * vby - vay * vbx;
|
||||
double angleDeg = AngleDeg;
|
||||
bool isLargeArc = angleDeg > 180;
|
||||
var sweepDir = cross >= 0 ? SweepDirection.Clockwise : SweepDirection.Counterclockwise;
|
||||
|
||||
var startPt = new Point(V.X + arcRadius * Math.Cos(angleARad), V.Y + arcRadius * Math.Sin(angleARad));
|
||||
var endPt = new Point(V.X + arcRadius * Math.Cos(angleBRad), V.Y + arcRadius * Math.Sin(angleBRad));
|
||||
|
||||
var arcSeg = new ArcSegment(endPt, new Size(arcRadius, arcRadius), 0, isLargeArc, sweepDir, true);
|
||||
var fig = new PathFigure(startPt, new[] { arcSeg }, false);
|
||||
Arc.Data = new PathGeometry(new[] { fig });
|
||||
Arc.Visibility = Visibility.Visible;
|
||||
|
||||
// 标签位置
|
||||
double midAngle = (angleARad + angleBRad) / 2.0;
|
||||
double testX = Math.Cos(midAngle), testY = Math.Sin(midAngle);
|
||||
double testCross = vax * testY - vay * testX;
|
||||
if ((cross >= 0 && testCross < 0) || (cross < 0 && testCross >= 0))
|
||||
midAngle += Math.PI;
|
||||
|
||||
double labelDist = arcRadius + 16;
|
||||
Label.Text = $"{angleDeg:F1}°";
|
||||
Canvas.SetLeft(Label, V.X + labelDist * Math.Cos(midAngle) - 15);
|
||||
Canvas.SetTop(Label, V.Y + labelDist * Math.Sin(midAngle) - 8);
|
||||
Label.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace XP.ImageProcessing.RoiControl.Models
|
||||
{
|
||||
None,
|
||||
PointDistance,
|
||||
PointToLine
|
||||
PointToLine,
|
||||
Angle
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user