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 { /// /// LineNode.xaml 的交互逻辑 /// 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 points = new List(); // 起始与终止锚点坐标 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 ps = new List(); 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 } }