Arrows.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. using System;
  2. using System.Windows;
  3. using System.Windows.Media;
  4. using System.Windows.Shapes;
  5. namespace TestTool
  6. {
  7. /// <summary>
  8. /// 箭头所在端
  9. /// </summary>
  10. [Flags]
  11. public enum ArrowEnds
  12. {
  13. /// <summary>
  14. /// 无箭头
  15. /// </summary>
  16. None = 0,
  17. /// <summary>
  18. /// 开始方向箭头
  19. /// </summary>
  20. Start = 1,
  21. /// <summary>
  22. /// 结束方向箭头
  23. /// </summary>
  24. End = 2,
  25. /// <summary>
  26. /// 两端箭头
  27. /// </summary>
  28. Both = 3
  29. }
  30. public abstract class ArrowBase:Shape
  31. {
  32. /// <summary>
  33. /// 箭头两边夹角的依赖属性
  34. /// </summary>
  35. public static readonly DependencyProperty ArrowAngleProperty = DependencyProperty.Register(
  36. "ArrowAngle",
  37. typeof(double),
  38. typeof(ArrowBase),
  39. new FrameworkPropertyMetadata(45.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
  40. /// <summary>
  41. /// 箭头长度的依赖属性
  42. /// </summary>
  43. public static readonly DependencyProperty ArrowLengthProperty = DependencyProperty.Register(
  44. "ArrowLength",
  45. typeof(double),
  46. typeof(ArrowBase),
  47. new FrameworkPropertyMetadata(12.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
  48. /// <summary>
  49. /// 箭头所在端的依赖属性
  50. /// </summary>
  51. public static readonly DependencyProperty ArrowEndsProperty = DependencyProperty.Register(
  52. "ArrowEnds",
  53. typeof(ArrowEnds),
  54. typeof(ArrowBase),
  55. new FrameworkPropertyMetadata(ArrowEnds.End, FrameworkPropertyMetadataOptions.AffectsMeasure));
  56. /// <summary>
  57. /// 箭头是否闭合的依赖属性
  58. /// </summary>
  59. public static readonly DependencyProperty IsArrowClosedProperty = DependencyProperty.Register(
  60. "IsArrowClosed",
  61. typeof(bool),
  62. typeof(ArrowBase),
  63. new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsMeasure));
  64. /// <summary>
  65. /// 开始点
  66. /// </summary>
  67. public static readonly DependencyProperty StartPointProperty = DependencyProperty.Register(
  68. "StartPoint",
  69. typeof(Point),
  70. typeof(ArrowBase),
  71. new FrameworkPropertyMetadata(default(Point), FrameworkPropertyMetadataOptions.AffectsMeasure));
  72. /// <summary>
  73. /// 整个形状(包含箭头和具体形状)
  74. /// </summary>
  75. private readonly PathGeometry _geometryWhole = new PathGeometry();
  76. /// <summary>
  77. /// 除去箭头外的具体形状
  78. /// </summary>
  79. private readonly PathFigure _figureConcrete = new PathFigure();
  80. /// <summary>
  81. /// 开始处的箭头线段
  82. /// </summary>
  83. private readonly PathFigure _figureStart = new PathFigure();
  84. /// <summary>
  85. /// 结束处的箭头线段
  86. /// </summary>
  87. private readonly PathFigure _figureEnd = new PathFigure();
  88. /// <summary>
  89. /// 箭头两边夹角
  90. /// </summary>
  91. public double ArrowAngle
  92. {
  93. get => (double)GetValue(ArrowAngleProperty);
  94. set => SetValue(ArrowAngleProperty, value);
  95. }
  96. /// <summary>
  97. /// 箭头两边的长度
  98. /// </summary>
  99. public double ArrowLength
  100. {
  101. get => (double)GetValue(ArrowLengthProperty);
  102. set => SetValue(ArrowLengthProperty, value);
  103. }
  104. /// <summary>
  105. /// 箭头所在端
  106. /// </summary>
  107. public ArrowEnds ArrowEnds
  108. {
  109. get => (ArrowEnds)GetValue(ArrowEndsProperty);
  110. set => SetValue(ArrowEndsProperty, value);
  111. }
  112. /// <summary>
  113. /// 箭头是否闭合
  114. /// </summary>
  115. public bool IsArrowClosed
  116. {
  117. get => (bool)GetValue(IsArrowClosedProperty);
  118. set => SetValue(IsArrowClosedProperty, value);
  119. }
  120. /// <summary>
  121. /// 开始点
  122. /// </summary>
  123. public Point StartPoint
  124. {
  125. get => (Point)GetValue(StartPointProperty);
  126. set => SetValue(StartPointProperty, value);
  127. }
  128. protected override Geometry DefiningGeometry
  129. {
  130. get
  131. {
  132. _figureConcrete.StartPoint = StartPoint;
  133. // 清空具体形状,避免重复添加
  134. _figureConcrete.Segments.Clear();
  135. var segements = FillFigure();
  136. if (segements != null)
  137. {
  138. foreach (var segement in segements)
  139. {
  140. _figureConcrete.Segments.Add(segement);
  141. }
  142. }
  143. // 绘制开始处的箭头
  144. if ((ArrowEnds & ArrowEnds.Start) == ArrowEnds.Start)
  145. {
  146. CalculateArrow(_figureStart, GetStartArrowEndPoint(), StartPoint);
  147. }
  148. // 绘制结束处的箭头
  149. if ((ArrowEnds & ArrowEnds.End) == ArrowEnds.End)
  150. {
  151. CalculateArrow(_figureEnd, GetEndArrowStartPoint(), GetEndArrowEndPoint());
  152. }
  153. return _geometryWhole;
  154. }
  155. }
  156. /// <summary>
  157. /// 获取具体形状的各个组成部分
  158. /// </summary>
  159. /// <returns>PathSegment集合</returns>
  160. protected abstract PathSegmentCollection FillFigure();
  161. /// <summary>
  162. /// 获取开始箭头处的结束点
  163. /// </summary>
  164. /// <returns>开始箭头处的结束点</returns>
  165. protected abstract Point GetStartArrowEndPoint();
  166. /// <summary>
  167. /// 获取结束箭头处的开始点
  168. /// </summary>
  169. /// <returns>结束箭头处的开始点</returns>
  170. protected abstract Point GetEndArrowStartPoint();
  171. /// <summary>
  172. /// 获取结束箭头处的结束点
  173. /// </summary>
  174. /// <returns>结束箭头处的结束点</returns>
  175. protected abstract Point GetEndArrowEndPoint();
  176. /// <summary>
  177. /// 计算两个点之间的有向箭头
  178. /// </summary>
  179. /// <param name="pathfig">箭头所在的形状</param>
  180. /// <param name="startPoint">开始点</param>
  181. /// <param name="endPoint">结束点</param>
  182. /// <returns>计算好的形状</returns>
  183. private void CalculateArrow(PathFigure pathfig, Point startPoint, Point endPoint)
  184. {
  185. if (pathfig.Segments.Count > 0)
  186. {
  187. var polyseg = pathfig.Segments[0] as PolyLineSegment;
  188. if (polyseg != null)
  189. {
  190. var matx = new Matrix();
  191. Vector vect = startPoint - endPoint;
  192. // 获取单位向量
  193. vect.Normalize();
  194. vect *= ArrowLength;
  195. // 旋转夹角的一半
  196. matx.Rotate(ArrowAngle / 2);
  197. // 计算上半段箭头的点
  198. pathfig.StartPoint = endPoint + (vect * matx);
  199. polyseg.Points.Clear();
  200. polyseg.Points.Add(endPoint);
  201. matx.Rotate(-ArrowAngle);
  202. // 计算下半段箭头的点
  203. polyseg.Points.Add(endPoint + (vect * matx));
  204. }
  205. pathfig.IsClosed = IsArrowClosed;
  206. }
  207. }
  208. }
  209. /// <summary>
  210. /// 两点之间带箭头的直线
  211. /// </summary>
  212. public class ArrowLine : ArrowBase
  213. {
  214. #region Fields
  215. /// <summary>
  216. /// 结束点
  217. /// </summary>
  218. public static readonly DependencyProperty EndPointProperty = DependencyProperty.Register(
  219. "EndPoint",
  220. typeof(Point),
  221. typeof(ArrowLine),
  222. new FrameworkPropertyMetadata(default(Point), FrameworkPropertyMetadataOptions.AffectsMeasure));
  223. /// <summary>
  224. /// 线段
  225. /// </summary>
  226. private readonly LineSegment lineSegment = new LineSegment();
  227. #endregion Fields
  228. #region Properties
  229. /// <summary>
  230. /// 结束点
  231. /// </summary>
  232. public Point EndPoint
  233. {
  234. get { return (Point)GetValue(EndPointProperty); }
  235. set { SetValue(EndPointProperty, value); }
  236. }
  237. #endregion Properties
  238. #region Protected Methods
  239. /// <summary>
  240. /// 填充Figure
  241. /// </summary>
  242. /// <returns>PathSegment集合</returns>
  243. protected override PathSegmentCollection FillFigure()
  244. {
  245. lineSegment.Point = EndPoint;
  246. return new PathSegmentCollection
  247. {
  248. lineSegment
  249. };
  250. }
  251. /// <summary>
  252. /// 获取开始箭头处的结束点
  253. /// </summary>
  254. /// <returns>开始箭头处的结束点</returns>
  255. protected override Point GetStartArrowEndPoint()
  256. {
  257. return EndPoint;
  258. }
  259. /// <summary>
  260. /// 获取结束箭头处的开始点
  261. /// </summary>
  262. /// <returns>结束箭头处的开始点</returns>
  263. protected override Point GetEndArrowStartPoint()
  264. {
  265. return StartPoint;
  266. }
  267. /// <summary>
  268. /// 获取结束箭头处的结束点
  269. /// </summary>
  270. /// <returns>结束箭头处的结束点</returns>
  271. protected override Point GetEndArrowEndPoint()
  272. {
  273. return EndPoint;
  274. }
  275. #endregion Protected Methods
  276. }
  277. }