ArrowLineBase.cs 6.0 KB

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