ArrowLineBase.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. //----------------------------------------------
  2. // ArrowLineBase.cs (c) 2007 by Charles Petzold
  3. //----------------------------------------------
  4. using System;
  5. using System.Windows;
  6. using System.Windows.Media;
  7. using System.Windows.Shapes;
  8. namespace DrawGraph
  9. {
  10. public enum ArrowEnds
  11. {
  12. None = 0,
  13. Start = 1,
  14. End = 2,
  15. Both = 3
  16. }
  17. public abstract class ArrowLineBase : Shape
  18. {
  19. protected PathGeometry pathgeo;
  20. protected PathFigure pathfigLine;
  21. protected PolyLineSegment polysegLine;
  22. PathFigure pathfigHead1;
  23. PolyLineSegment polysegHead1;
  24. PathFigure pathfigHead2;
  25. PolyLineSegment polysegHead2;
  26. /// <summary>
  27. /// Identifies the ArrowAngle dependency property.
  28. /// </summary>
  29. public static readonly DependencyProperty ArrowAngleProperty =
  30. DependencyProperty.Register("ArrowAngle",
  31. typeof(double), typeof(ArrowLineBase),
  32. new FrameworkPropertyMetadata(45.0,
  33. FrameworkPropertyMetadataOptions.AffectsMeasure));
  34. /// <summary>
  35. /// Gets or sets the angle between the two sides of the arrowhead.
  36. /// </summary>
  37. public double ArrowAngle
  38. {
  39. set { SetValue(ArrowAngleProperty, value); }
  40. get { return (double)GetValue(ArrowAngleProperty); }
  41. }
  42. /// <summary>
  43. /// Identifies the ArrowLength dependency property.
  44. /// </summary>
  45. public static readonly DependencyProperty ArrowLengthProperty =
  46. DependencyProperty.Register("ArrowLength",
  47. typeof(double), typeof(ArrowLineBase),
  48. new FrameworkPropertyMetadata(12.0,
  49. FrameworkPropertyMetadataOptions.AffectsMeasure));
  50. /// <summary>
  51. /// Gets or sets the length of the two sides of the arrowhead.
  52. /// </summary>
  53. public double ArrowLength
  54. {
  55. set { SetValue(ArrowLengthProperty, value); }
  56. get { return (double)GetValue(ArrowLengthProperty); }
  57. }
  58. /// <summary>
  59. /// Identifies the ArrowEnds dependency property.
  60. /// </summary>
  61. public static readonly DependencyProperty ArrowEndsProperty =
  62. DependencyProperty.Register("ArrowEnds",
  63. typeof(ArrowEnds), typeof(ArrowLineBase),
  64. new FrameworkPropertyMetadata(ArrowEnds.End,
  65. FrameworkPropertyMetadataOptions.AffectsMeasure));
  66. /// <summary>
  67. /// Gets or sets the property that determines which ends of the
  68. /// line have arrows.
  69. /// </summary>
  70. public ArrowEnds ArrowEnds
  71. {
  72. set { SetValue(ArrowEndsProperty, value); }
  73. get { return (ArrowEnds)GetValue(ArrowEndsProperty); }
  74. }
  75. /// <summary>
  76. /// Identifies the IsArrowClosed dependency property.
  77. /// </summary>
  78. public static readonly DependencyProperty IsArrowClosedProperty =
  79. DependencyProperty.Register("IsArrowClosed",
  80. typeof(bool), typeof(ArrowLineBase),
  81. new FrameworkPropertyMetadata(false,
  82. FrameworkPropertyMetadataOptions.AffectsMeasure));
  83. /// <summary>
  84. /// Gets or sets the property that determines if the arrow head
  85. /// is closed to resemble a triangle.
  86. /// </summary>
  87. public bool IsArrowClosed
  88. {
  89. set { SetValue(IsArrowClosedProperty, value); }
  90. get { return (bool)GetValue(IsArrowClosedProperty); }
  91. }
  92. /// <summary>
  93. /// Initializes a new instance of ArrowLineBase.
  94. /// </summary>
  95. public ArrowLineBase()
  96. {
  97. pathgeo = new PathGeometry();
  98. pathfigLine = new PathFigure();
  99. polysegLine = new PolyLineSegment();
  100. pathfigLine.Segments.Add(polysegLine);
  101. pathfigHead1 = new PathFigure();
  102. polysegHead1 = new PolyLineSegment();
  103. pathfigHead1.Segments.Add(polysegHead1);
  104. pathfigHead2 = new PathFigure();
  105. polysegHead2 = new PolyLineSegment();
  106. pathfigHead2.Segments.Add(polysegHead2);
  107. }
  108. /// <summary>
  109. /// Gets a value that represents the Geometry of the ArrowLine.
  110. /// </summary>
  111. protected override Geometry DefiningGeometry
  112. {
  113. get
  114. {
  115. int count = polysegLine.Points.Count;
  116. if (count > 0)
  117. {
  118. // Draw the arrow at the start of the line.
  119. if ((ArrowEnds & ArrowEnds.Start) == ArrowEnds.Start)
  120. {
  121. Point pt1 = pathfigLine.StartPoint;
  122. Point pt2 = polysegLine.Points[0];
  123. pathgeo.Figures.Add(CalculateArrow(pathfigHead1, pt2, pt1));
  124. }
  125. // Draw the arrow at the end of the line.
  126. if ((ArrowEnds & ArrowEnds.End) == ArrowEnds.End)
  127. {
  128. Point pt1 = count == 1 ? pathfigLine.StartPoint :
  129. polysegLine.Points[count - 2];
  130. Point pt2 = polysegLine.Points[count - 1];
  131. pathgeo.Figures.Add(CalculateArrow(pathfigHead2, pt1, pt2));
  132. }
  133. }
  134. return pathgeo;
  135. }
  136. }
  137. PathFigure CalculateArrow(PathFigure pathfig, Point pt1, Point pt2)
  138. {
  139. Matrix matx = new Matrix();
  140. Vector vect = pt1 - pt2;
  141. vect.Normalize();
  142. vect *= ArrowLength;
  143. PolyLineSegment polyseg = pathfig.Segments[0] as PolyLineSegment;
  144. polyseg.Points.Clear();
  145. matx.Rotate(ArrowAngle / 2);
  146. pathfig.StartPoint = pt2 + vect * matx;
  147. polyseg.Points.Add(pt2);
  148. matx.Rotate(-ArrowAngle);
  149. polyseg.Points.Add(pt2 + vect * matx);
  150. pathfig.IsClosed = IsArrowClosed;
  151. return pathfig;
  152. }
  153. }
  154. }