123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- using System;
- using System.Windows;
- using System.Windows.Media;
- using System.Windows.Shapes;
- namespace TestTool
- {
- /// <summary>
- /// 箭头所在端
- /// </summary>
- [Flags]
- public enum ArrowEnds
- {
- /// <summary>
- /// 无箭头
- /// </summary>
- None = 0,
- /// <summary>
- /// 开始方向箭头
- /// </summary>
- Start = 1,
- /// <summary>
- /// 结束方向箭头
- /// </summary>
- End = 2,
- /// <summary>
- /// 两端箭头
- /// </summary>
- Both = 3
- }
- public abstract class ArrowBase:Shape
- {
- /// <summary>
- /// 箭头两边夹角的依赖属性
- /// </summary>
- public static readonly DependencyProperty ArrowAngleProperty = DependencyProperty.Register(
- "ArrowAngle",
- typeof(double),
- typeof(ArrowBase),
- new FrameworkPropertyMetadata(45.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
- /// <summary>
- /// 箭头长度的依赖属性
- /// </summary>
- public static readonly DependencyProperty ArrowLengthProperty = DependencyProperty.Register(
- "ArrowLength",
- typeof(double),
- typeof(ArrowBase),
- new FrameworkPropertyMetadata(12.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
- /// <summary>
- /// 箭头所在端的依赖属性
- /// </summary>
- public static readonly DependencyProperty ArrowEndsProperty = DependencyProperty.Register(
- "ArrowEnds",
- typeof(ArrowEnds),
- typeof(ArrowBase),
- new FrameworkPropertyMetadata(ArrowEnds.End, FrameworkPropertyMetadataOptions.AffectsMeasure));
- /// <summary>
- /// 箭头是否闭合的依赖属性
- /// </summary>
- public static readonly DependencyProperty IsArrowClosedProperty = DependencyProperty.Register(
- "IsArrowClosed",
- typeof(bool),
- typeof(ArrowBase),
- new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsMeasure));
- /// <summary>
- /// 开始点
- /// </summary>
- public static readonly DependencyProperty StartPointProperty = DependencyProperty.Register(
- "StartPoint",
- typeof(Point),
- typeof(ArrowBase),
- new FrameworkPropertyMetadata(default(Point), FrameworkPropertyMetadataOptions.AffectsMeasure));
- /// <summary>
- /// 整个形状(包含箭头和具体形状)
- /// </summary>
- private readonly PathGeometry _geometryWhole = new PathGeometry();
- /// <summary>
- /// 除去箭头外的具体形状
- /// </summary>
- private readonly PathFigure _figureConcrete = new PathFigure();
- /// <summary>
- /// 开始处的箭头线段
- /// </summary>
- private readonly PathFigure _figureStart = new PathFigure();
- /// <summary>
- /// 结束处的箭头线段
- /// </summary>
- private readonly PathFigure _figureEnd = new PathFigure();
- /// <summary>
- /// 箭头两边夹角
- /// </summary>
- public double ArrowAngle
- {
- get => (double)GetValue(ArrowAngleProperty);
- set => SetValue(ArrowAngleProperty, value);
- }
- /// <summary>
- /// 箭头两边的长度
- /// </summary>
- public double ArrowLength
- {
- get => (double)GetValue(ArrowLengthProperty);
- set => SetValue(ArrowLengthProperty, value);
- }
- /// <summary>
- /// 箭头所在端
- /// </summary>
- public ArrowEnds ArrowEnds
- {
- get => (ArrowEnds)GetValue(ArrowEndsProperty);
- set => SetValue(ArrowEndsProperty, value);
- }
- /// <summary>
- /// 箭头是否闭合
- /// </summary>
- public bool IsArrowClosed
- {
- get => (bool)GetValue(IsArrowClosedProperty);
- set => SetValue(IsArrowClosedProperty, value);
- }
- /// <summary>
- /// 开始点
- /// </summary>
- public Point StartPoint
- {
- get => (Point)GetValue(StartPointProperty);
- set => SetValue(StartPointProperty, value);
- }
- protected override Geometry DefiningGeometry
- {
- get
- {
- _figureConcrete.StartPoint = StartPoint;
- // 清空具体形状,避免重复添加
- _figureConcrete.Segments.Clear();
- var segements = FillFigure();
- if (segements != null)
- {
- foreach (var segement in segements)
- {
- _figureConcrete.Segments.Add(segement);
- }
- }
- // 绘制开始处的箭头
- if ((ArrowEnds & ArrowEnds.Start) == ArrowEnds.Start)
- {
- CalculateArrow(_figureStart, GetStartArrowEndPoint(), StartPoint);
- }
- // 绘制结束处的箭头
- if ((ArrowEnds & ArrowEnds.End) == ArrowEnds.End)
- {
- CalculateArrow(_figureEnd, GetEndArrowStartPoint(), GetEndArrowEndPoint());
- }
- return _geometryWhole;
- }
- }
- /// <summary>
- /// 获取具体形状的各个组成部分
- /// </summary>
- /// <returns>PathSegment集合</returns>
- protected abstract PathSegmentCollection FillFigure();
- /// <summary>
- /// 获取开始箭头处的结束点
- /// </summary>
- /// <returns>开始箭头处的结束点</returns>
- protected abstract Point GetStartArrowEndPoint();
- /// <summary>
- /// 获取结束箭头处的开始点
- /// </summary>
- /// <returns>结束箭头处的开始点</returns>
- protected abstract Point GetEndArrowStartPoint();
- /// <summary>
- /// 获取结束箭头处的结束点
- /// </summary>
- /// <returns>结束箭头处的结束点</returns>
- protected abstract Point GetEndArrowEndPoint();
- /// <summary>
- /// 计算两个点之间的有向箭头
- /// </summary>
- /// <param name="pathfig">箭头所在的形状</param>
- /// <param name="startPoint">开始点</param>
- /// <param name="endPoint">结束点</param>
- /// <returns>计算好的形状</returns>
- private void CalculateArrow(PathFigure pathfig, Point startPoint, Point endPoint)
- {
- if (pathfig.Segments.Count > 0)
- {
- var polyseg = pathfig.Segments[0] as PolyLineSegment;
- if (polyseg != null)
- {
- var matx = new Matrix();
- Vector vect = startPoint - endPoint;
- // 获取单位向量
- vect.Normalize();
- vect *= ArrowLength;
- // 旋转夹角的一半
- matx.Rotate(ArrowAngle / 2);
- // 计算上半段箭头的点
- pathfig.StartPoint = endPoint + (vect * matx);
- polyseg.Points.Clear();
- polyseg.Points.Add(endPoint);
- matx.Rotate(-ArrowAngle);
- // 计算下半段箭头的点
- polyseg.Points.Add(endPoint + (vect * matx));
- }
- pathfig.IsClosed = IsArrowClosed;
- }
- }
- }
- /// <summary>
- /// 两点之间带箭头的直线
- /// </summary>
- public class ArrowLine : ArrowBase
- {
- #region Fields
- /// <summary>
- /// 结束点
- /// </summary>
- public static readonly DependencyProperty EndPointProperty = DependencyProperty.Register(
- "EndPoint",
- typeof(Point),
- typeof(ArrowLine),
- new FrameworkPropertyMetadata(default(Point), FrameworkPropertyMetadataOptions.AffectsMeasure));
- /// <summary>
- /// 线段
- /// </summary>
- private readonly LineSegment lineSegment = new LineSegment();
- #endregion Fields
- #region Properties
- /// <summary>
- /// 结束点
- /// </summary>
- public Point EndPoint
- {
- get { return (Point)GetValue(EndPointProperty); }
- set { SetValue(EndPointProperty, value); }
- }
- #endregion Properties
- #region Protected Methods
- /// <summary>
- /// 填充Figure
- /// </summary>
- /// <returns>PathSegment集合</returns>
- protected override PathSegmentCollection FillFigure()
- {
- lineSegment.Point = EndPoint;
- return new PathSegmentCollection
- {
- lineSegment
- };
- }
- /// <summary>
- /// 获取开始箭头处的结束点
- /// </summary>
- /// <returns>开始箭头处的结束点</returns>
- protected override Point GetStartArrowEndPoint()
- {
- return EndPoint;
- }
- /// <summary>
- /// 获取结束箭头处的开始点
- /// </summary>
- /// <returns>结束箭头处的开始点</returns>
- protected override Point GetEndArrowStartPoint()
- {
- return StartPoint;
- }
- /// <summary>
- /// 获取结束箭头处的结束点
- /// </summary>
- /// <returns>结束箭头处的结束点</returns>
- protected override Point GetEndArrowEndPoint()
- {
- return EndPoint;
- }
- #endregion Protected Methods
- }
- }
|