//---------------------------------------------- // ArrowLineBase.cs (c) 2007 by Charles Petzold //---------------------------------------------- using System.Windows; using System.Windows.Media; using System.Windows.Shapes; namespace DrawGraph { public enum ArrowEnds { None = 0, Start = 1, End = 2, Both = 3 } public abstract class ArrowLineBase : Shape { protected PathGeometry pathgeo; protected PathFigure pathfigLine; protected PolyLineSegment polysegLine; PathFigure pathfigHead1; PolyLineSegment polysegHead1; PathFigure pathfigHead2; PolyLineSegment polysegHead2; /// /// Identifies the ArrowAngle dependency property. /// public static readonly DependencyProperty ArrowAngleProperty = DependencyProperty.Register("ArrowAngle", typeof(double), typeof(ArrowLineBase), new FrameworkPropertyMetadata(45.0, FrameworkPropertyMetadataOptions.AffectsMeasure)); /// /// Gets or sets the angle between the two sides of the arrowhead. /// public double ArrowAngle { set { SetValue(ArrowAngleProperty, value); } get { return (double) GetValue(ArrowAngleProperty); } } /// /// Identifies the ArrowLength dependency property. /// public static readonly DependencyProperty ArrowLengthProperty = DependencyProperty.Register("ArrowLength", typeof(double), typeof(ArrowLineBase), new FrameworkPropertyMetadata(12.0, FrameworkPropertyMetadataOptions.AffectsMeasure)); /// /// Gets or sets the length of the two sides of the arrowhead. /// public double ArrowLength { set { SetValue(ArrowLengthProperty, value); } get { return (double) GetValue(ArrowLengthProperty); } } /// /// Identifies the ArrowEnds dependency property. /// public static readonly DependencyProperty ArrowEndsProperty = DependencyProperty.Register("ArrowEnds", typeof(ArrowEnds), typeof(ArrowLineBase), new FrameworkPropertyMetadata(ArrowEnds.End, FrameworkPropertyMetadataOptions.AffectsMeasure)); /// /// Gets or sets the property that determines which ends of the /// line have arrows. /// public ArrowEnds ArrowEnds { set { SetValue(ArrowEndsProperty, value); } get { return (ArrowEnds) GetValue(ArrowEndsProperty); } } /// /// Identifies the IsArrowClosed dependency property. /// public static readonly DependencyProperty IsArrowClosedProperty = DependencyProperty.Register("IsArrowClosed", typeof(bool), typeof(ArrowLineBase), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsMeasure)); /// /// Gets or sets the property that determines if the arrow head /// is closed to resemble a triangle. /// public bool IsArrowClosed { set { SetValue(IsArrowClosedProperty, value); } get { return (bool) GetValue(IsArrowClosedProperty); } } /// /// Initializes a new instance of ArrowLineBase. /// public ArrowLineBase() { pathgeo = new PathGeometry(); pathfigLine = new PathFigure(); polysegLine = new PolyLineSegment(); pathfigLine.Segments.Add(polysegLine); pathfigHead1 = new PathFigure(); polysegHead1 = new PolyLineSegment(); pathfigHead1.Segments.Add(polysegHead1); pathfigHead2 = new PathFigure(); polysegHead2 = new PolyLineSegment(); pathfigHead2.Segments.Add(polysegHead2); } /// /// Gets a value that represents the Geometry of the ArrowLine. /// protected override Geometry DefiningGeometry { get { int count = polysegLine.Points.Count; if (count > 0) { // Draw the arrow at the start of the line. if ((ArrowEnds & ArrowEnds.Start) == ArrowEnds.Start) { Point pt1 = pathfigLine.StartPoint; Point pt2 = polysegLine.Points[0]; pathgeo.Figures.Add(CalculateArrow(pathfigHead1, pt2, pt1)); } // Draw the arrow at the end of the line. if ((ArrowEnds & ArrowEnds.End) == ArrowEnds.End) { Point pt1 = count == 1 ? pathfigLine.StartPoint : polysegLine.Points[count - 2]; Point pt2 = polysegLine.Points[count - 1]; pathgeo.Figures.Add(CalculateArrow(pathfigHead2, pt1, pt2)); } } return pathgeo; } } PathFigure CalculateArrow(PathFigure pathfig, Point pt1, Point pt2) { var matx = new System.Windows.Media.Matrix(); var vect = pt1 - pt2; vect.Normalize(); vect *= ArrowLength; var polyseg = pathfig.Segments[0] as PolyLineSegment; polyseg.Points.Clear(); matx.Rotate(ArrowAngle / 2); pathfig.StartPoint = pt2 + vect * matx; polyseg.Points.Add(pt2); matx.Rotate(-ArrowAngle); polyseg.Points.Add(pt2 + vect * matx); pathfig.IsClosed = IsArrowClosed; return pathfig; } } }