Files
2025-07-14 21:08:46 +08:00

677 lines
20 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace VisionFrame.Nodes
{
/// <summary>
/// LineNode.xaml 的交互逻辑
/// </summary>
public partial class LineNode : UserControl, INotifyPropertyChanged
{
public double X1
{
get { return (double)GetValue(X1Property); }
set { SetValue(X1Property, value); }
}
public static readonly DependencyProperty X1Property =
DependencyProperty.Register("X1", typeof(double),
typeof(LineNode),
new PropertyMetadata(0.0, OnPropertyChanged));
public double Y1
{
get { return (double)GetValue(Y1Property); }
set { SetValue(Y1Property, value); }
}
public static readonly DependencyProperty Y1Property =
DependencyProperty.Register("Y1", typeof(double),
typeof(LineNode),
new PropertyMetadata(0.0, OnPropertyChanged));
public double X2
{
get { return (double)GetValue(X2Property); }
set { SetValue(X2Property, value); }
}
public static readonly DependencyProperty X2Property =
DependencyProperty.Register("X2", typeof(double),
typeof(LineNode),
new PropertyMetadata(0.0, OnPropertyChanged));
public double Y2
{
get { return (double)GetValue(Y2Property); }
set { SetValue(Y2Property, value); }
}
public static readonly DependencyProperty Y2Property =
DependencyProperty.Register("Y2", typeof(double),
typeof(LineNode),
new PropertyMetadata(0.0, OnPropertyChanged));
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as LineNode).InvalidateVisual();
}
public string StartAnchor
{
get { return (string)GetValue(StartAnchorProperty); }
set { SetValue(StartAnchorProperty, value); }
}
public static readonly DependencyProperty StartAnchorProperty =
DependencyProperty.Register("StartAnchor", typeof(string),
typeof(LineNode),
new PropertyMetadata(""));
public string EndAnchor
{
get { return (string)GetValue(EndAnchorProperty); }
set { SetValue(EndAnchorProperty, value); }
}
public static readonly DependencyProperty EndAnchorProperty =
DependencyProperty.Register("EndAnchor", typeof(string),
typeof(LineNode),
new PropertyMetadata(""));
public event PropertyChangedEventHandler? PropertyChanged;
public Thickness CancelLocation { get; set; }
public LineNode()
{
InitializeComponent();
}
protected override void OnRender(DrawingContext drawingContext)
{
List<Point> points = new List<Point>();
// 起始与终止锚点坐标
Point start = new Point(X1, Y1);
Point end = new Point(X2, Y2);
//
if (EndAnchor == "N")
{
if (X2 < X1)
end += new Vector(2, 0);
else if (X2 > X1)
end += new Vector(-2, 0);
if (Y2 > Y1)
end += new Vector(0, -2);
else if (Y2 < Y1)
end += new Vector(0, 2);
}
// 起始延伸坐标
Point start_extend = new Point(X1, Y1);
if (StartAnchor == "T")
start_extend = new Point(X1, Y1 - 20);
else if (StartAnchor == "B")
start_extend = new Point(X1, Y1 + 20);
else if (StartAnchor == "L")
start_extend = new Point(X1 - 20, Y1);
else if (StartAnchor == "R")
start_extend = new Point(X1 + 20, Y1);
// 终点延伸坐标
Point end_extend = new Point(end.X, end.Y);
if (EndAnchor == "T")
end_extend = new Point(end.X, end.Y - 20);
else if (EndAnchor == "B")
end_extend = new Point(end.X, end.Y + 20);
else if (EndAnchor == "L")
end_extend = new Point(end.X - 20, end.Y);
else if (EndAnchor == "R")
end_extend = new Point(end.X + 20, end.Y);
// 添加第一点
points.Add(start);
// 添加延伸点(针对第一点),起点是哪个锚点
points.Add(start_extend);
// 添加动态点
// 锚点名称 TBLR 反射
MethodInfo mi = this.GetType().GetMethod(StartAnchor + "2" + EndAnchor,
BindingFlags.NonPublic | BindingFlags.Instance);
if (mi == null) return;
Point[] ps = (Point[])mi.Invoke(this, new object[] {
start_extend,
end_extend
});
points.AddRange(ps);
//points.AddRange(this.B2T(new Point(X1, Y1 + 20), new Point(X2, Y2 - 20)));
// 添加一个延伸点(针对最终点),终点是哪个锚点
points.Add(end_extend);
// 添加最终点
points.Add(end);
//StreamGeometry geometry = new StreamGeometry();
//using (StreamGeometryContext ctx = geometry.Open())
//{
// Point first = points.FirstOrDefault();
// ctx.BeginFigure(first, false, false);
// ctx.PolyLineTo(points, true, true);
//}
var geometry = GetBrokenGeometry(points.ToArray(), false, false);
if (EndAnchor != "N")
{
//points[points.Count - 2];// 终延
//points[points.Count - 1];// 终
Point[] arrow_points = this.GetArrowPoints(points[points.Count - 2], points[points.Count - 1]);
var arrow_geo = this.GetBrokenGeometry(arrow_points, true, true);
PathGeometry path = PathGeometry.CreateFromGeometry(geometry);
// 整合
path.AddGeometry(arrow_geo);
path.Freeze();
geometry = path;
}
//drawingContext.DrawLine(new Pen(Brushes.Red, 2), new Point(X1, Y1), new Point(X2, Y2));
drawingContext.DrawGeometry(
Brushes.Orange,
new Pen(Brushes.Orange, 2),
geometry);
if (ps.Length == 2)
{
var p = ps[0] + (ps[1] - ps[0]) / 2;
CancelLocation = new Thickness(p.X - 7, p.Y - 7, 0, 0);
}
else if (ps.Length == 1)
CancelLocation = new Thickness(ps[0].X - 7, ps[0].Y - 7, 0, 0);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CancelLocation)));
}
private Geometry GetBrokenGeometry(Point[] points, bool isFill, bool isClose)
{
StreamGeometry geometry = new StreamGeometry();
using (StreamGeometryContext ctx = geometry.Open())
{
Point first = points.FirstOrDefault();
ctx.BeginFigure(first, isFill, isClose);
ctx.PolyLineTo(points, true, true);
}
return geometry;
}
private Point[] GetArrowPoints(Point start, Point end)
{
Vector vec = start - end;
// 规范化 单位化
vec.Normalize();
vec *= 8;
Matrix matrix = new Matrix();
matrix.Rotate(20);
Point p1 = end + vec * matrix;
matrix.Rotate(-40);
Point p2 = end + vec * matrix;
return new Point[] { p1, end, p2 };
}
#region
// 下对上
private Point[] B2T(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (end.Y > start.Y)
{
ps.Add(new Point(start.X, start.Y + cy));
ps.Add(new Point(end.X, start.Y + cy));
}
else if (end.Y < start.Y)
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(start.X + cx, end.Y));
}
return ps.ToArray();
}
// 下对左
private Point[] B2L(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.X > end.X)
{
ps.Add(new Point(end.X, start.Y));
}
else if (start.Y < end.Y)
{
ps.Add(new Point(start.X, end.Y));
}
else
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
return ps.ToArray();
}
// 下对右
private Point[] B2R(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.X < end.X)
{
ps.Add(new Point(end.X, start.Y));
}
else if (start.Y < end.Y)
{
ps.Add(new Point(start.X, end.Y));
}
else
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
return ps.ToArray();
}
// 下对下
private Point[] B2B(Point start, Point end)
{
double cy = end.Y - start.Y;
List<Point> ps = new List<Point>();
if (start.Y > end.Y)
{
ps.Add(new Point(end.X, start.Y));
}
else if (start.Y < end.Y)
{
ps.Add(new Point(start.X, end.Y));
}
return ps.ToArray();
}
// 下对空
private Point[] B2N(Point start, Point end)
{
List<Point> ps = new List<Point>();
if (start.Y > end.Y)
{
ps.Add(new Point(end.X, start.Y));
}
else
{
ps.Add(new Point(start.X, end.Y));
}
return ps.ToArray();
}
#endregion
#region
// From右锚点To上锚点
private Point[] R2T(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
List<Point> ps = new List<Point>();
if (start.X > end.X)
{
ps.Add(new Point(start.X, end.Y));
}
else if (start.Y < end.Y)
{
ps.Add(new Point(end.X, start.Y));
}
else
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
return ps.ToArray();
}
// From右锚点To左锚点
private Point[] R2L(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.X > end.X)
{
ps.Add(new Point(start.X, start.Y + cy));
ps.Add(new Point(end.X, end.Y - cy));
}
else
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
return ps.ToArray();
}
// From右锚点To右锚点
private Point[] R2R(Point start, Point end)
{
List<Point> ps = new List<Point>();
if (start.X > end.X)
{
ps.Add(new Point(start.X, end.Y));
}
else
{
ps.Add(new Point(end.X, start.Y));
}
return ps.ToArray();
}
// From右锚点To下锚点
private Point[] R2B(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.X > end.X && start.Y > end.Y)
{
ps.Add(new Point(start.X, start.Y + cy));
ps.Add(new Point(end.X, start.Y + cy));
}
else if (start.X < end.X && start.Y < end.Y)
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
else if (start.X < end.X)
{
ps.Add(new Point(end.X, start.Y));
}
else
{
ps.Add(new Point(start.X, end.Y));
}
return ps.ToArray();
}
// Fromd右锚点To NULL
private Point[] R2N(Point start, Point end)
{
List<Point> ps = new List<Point>();
if (start.X > end.X)
{
ps.Add(new Point(start.X, end.Y));
}
else
{
ps.Add(new Point(end.X, start.Y));
}
return ps.ToArray();
}
#endregion
#region
// From左锚点To上锚点
private Point[] L2T(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.X > end.X && start.Y > end.Y)
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
else if (start.X < end.X && start.Y < end.Y)
{
ps.Add(new Point(start.X, start.Y + cy));
ps.Add(new Point(end.X, end.Y - cy));
}
else if (start.X < end.X)
{
ps.Add(new Point(start.X, end.Y));
}
else
{
ps.Add(new Point(end.X, start.Y));
}
return ps.ToArray();
}
// From左锚点To左锚点
private Point[] L2L(Point start, Point end)
{
List<Point> ps = new List<Point>();
if (start.X > end.X)
{
ps.Add(new Point(end.X, start.Y));
}
else
{
ps.Add(new Point(start.X, end.Y));
}
return ps.ToArray();
}
// From左锚点To右锚点
private Point[] L2R(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.X < end.X)
{
ps.Add(new Point(start.X, start.Y + cy));
ps.Add(new Point(end.X, start.Y + cy));
}
else
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(start.X + cx, end.Y));
}
return ps.ToArray();
}
// From左锚点To下锚点
private Point[] L2B(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.X < end.X && start.Y > end.Y)
{
ps.Add(new Point(start.X, start.Y + cy));
ps.Add(new Point(end.X, end.Y - cy));
}
else if (start.X > end.X && start.Y < end.Y)
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
else if (start.X > end.X)
{
ps.Add(new Point(end.X, start.Y));
}
else
{
ps.Add(new Point(start.X, end.Y));
}
return ps.ToArray();
}
// Fromd左锚点To NULL
private Point[] L2N(Point start, Point end)
{
List<Point> ps = new List<Point>();
if (start.X > end.X)
{
ps.Add(new Point(end.X, start.Y));
}
else
{
ps.Add(new Point(start.X, end.Y));
}
return ps.ToArray();
}
#endregion
#region
// From上锚点To上锚点
private Point[] T2T(Point start, Point end)
{
List<Point> ps = new List<Point>();
if (start.Y > end.Y)
{
ps.Add(new Point(start.X, end.Y));
}
else
{
ps.Add(new Point(end.X, start.Y));
}
return ps.ToArray();
}
// From上锚点To下锚点
private Point[] T2B(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.Y > end.Y)
{
ps.Add(new Point(start.X, start.Y + cy));
ps.Add(new Point(end.X, end.Y - cy));
}
else
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
return ps.ToArray();
}
// From上锚点To左锚点
private Point[] T2L(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.Y > end.Y && start.X > end.X)
{
ps.Add(new Point(start.X, start.Y + cy));
ps.Add(new Point(end.X, end.Y - cy));
}
else if (start.Y < end.Y && start.X < end.X)
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
else if (start.X < end.X)
{
ps.Add(new Point(start.X, end.Y));
}
else
{
ps.Add(new Point(end.X, start.Y));
}
return ps.ToArray();
}
// From上锚点To右锚点
private Point[] T2R(Point start, Point end)
{
double cx = (end.X - start.X) / 2;
double cy = (end.Y - start.Y) / 2;
List<Point> ps = new List<Point>();
if (start.Y > end.Y && start.X > end.X)
{
ps.Add(new Point(start.X, end.Y));
}
else if (start.Y < end.Y && start.X < end.X)
{
ps.Add(new Point(end.X, start.Y));
}
else if (start.X < end.X)
{
ps.Add(new Point(start.X, start.Y + cy));
ps.Add(new Point(end.X, end.Y - cy));
}
else
{
ps.Add(new Point(start.X + cx, start.Y));
ps.Add(new Point(end.X - cx, end.Y));
}
return ps.ToArray();
}
// Fromd上锚点To NULL
private Point[] T2N(Point start, Point end)
{
List<Point> ps = new List<Point>();
if (start.Y > end.Y)
{
ps.Add(new Point(start.X, end.Y));
}
else
{
ps.Add(new Point(end.X, start.Y));
}
return ps.ToArray();
}
#endregion
}
}