//============================================================================ //ZedGraph Class Library - A Flexible Line Graph/Bar Graph Library in C# //Copyright ?2004 John Champion // //This library is free software; you can redistribute it and/or //modify it under the terms of the GNU Lesser General Public //License as published by the Free Software Foundation; either //version 2.1 of the License, or (at your option) any later version. // //This library is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //Lesser General Public License for more details. // //You should have received a copy of the GNU Lesser General Public //License along with this library; if not, write to the Free Software //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //============================================================================= using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Collections; using System.Runtime.Serialization; using System.Security.Permissions; namespace DrawGraph { /// /// A class that represents a graphic arrow or line object on the graph. A list of /// ArrowObj objects is maintained by the collection class. /// /// /// John Champion /// $Revision: 3.4 $ $Date: 2007/01/25 07:56:08 $ [Serializable] public class ArrowObj : LineObj, ICloneable, ISerializable { #region Fields /// /// Private field that stores the arrowhead size, measured in points. /// Use the public property to access this value. /// private float _size; /// /// Private boolean field that stores the arrowhead state. /// Use the public property to access this value. /// /// true if an arrowhead is to be drawn, false otherwise private bool _isArrowHead; #endregion #region Defaults /// /// A simple struct that defines the /// default property values for the class. /// new public struct Default { /// /// The default size for the item arrowhead /// ( property). Units are in points (1/72 inch). /// public static float Size = 12.0F; /// /// The default display mode for the item arrowhead /// ( property). true to show the /// arrowhead, false to hide it. /// public static bool IsArrowHead = true; } #endregion #region Properties /// /// The size of the arrowhead. /// /// The display of the arrowhead can be /// enabled or disabled with the property. /// /// The size is defined in points (1/72 inch) /// public float Size { get { return _size; } set { _size = value; } } /// /// Determines whether or not to draw an arrowhead /// /// true to show the arrowhead, false to show the line segment /// only /// public bool IsArrowHead { get { return _isArrowHead; } set { _isArrowHead = value; } } #endregion #region Constructors /// Constructors for the object /// /// A constructor that allows the position, color, and size of the /// to be pre-specified. /// /// An arbitrary specification /// for the arrow /// The size of the arrowhead, measured in points. /// The x position of the starting point that defines the /// arrow. The units of this position are specified by the /// property. /// The y position of the starting point that defines the /// arrow. The units of this position are specified by the /// property. /// The x position of the ending point that defines the /// arrow. The units of this position are specified by the /// property. /// The y position of the ending point that defines the /// arrow. The units of this position are specified by the /// property. public ArrowObj( Color color, float size, double x1, double y1, double x2, double y2 ) : base( color, x1, y1, x2, y2 ) { _isArrowHead = Default.IsArrowHead; _size = size; } /// /// A constructor that allows only the position of the /// arrow to be pre-specified. All other properties are set to /// default values /// /// The x position of the starting point that defines the /// . The units of this position are specified by the /// property. /// The y position of the starting point that defines the /// . The units of this position are specified by the /// property. /// The x position of the ending point that defines the /// . The units of this position are specified by the /// property. /// The y position of the ending point that defines the /// . The units of this position are specified by the /// property. public ArrowObj( double x1, double y1, double x2, double y2 ) : this( LineBase.Default.Color, Default.Size, x1, y1, x2, y2 ) { } /// /// Default constructor -- places the at location /// (0,0) to (1,1). All other values are defaulted. /// public ArrowObj() : this( LineBase.Default.Color, Default.Size, 0, 0, 1, 1 ) { } /// /// The Copy Constructor /// /// The object from which to copy public ArrowObj( ArrowObj rhs ) : base( rhs ) { _size = rhs.Size; _isArrowHead = rhs.IsArrowHead; } /// /// Implement the interface in a typesafe manner by just /// calling the typed version of /// /// A deep copy of this object object ICloneable.Clone() { return this.Clone(); } /// /// Typesafe, deep-copy clone method. /// /// A new, independent copy of this class public new ArrowObj Clone() { return new ArrowObj( this ); } #endregion #region Serialization /// /// Current schema value that defines the version of the serialized file /// public const int schema3 = 10; /// /// Constructor for deserializing objects /// /// A instance that defines the serialized data /// /// A instance that contains the serialized data /// protected ArrowObj( SerializationInfo info, StreamingContext context ) : base( info, context ) { // The schema value is just a file version parameter. You can use it to make future versions // backwards compatible as new member variables are added to classes int sch = info.GetInt32( "schema3" ); _size = info.GetSingle( "size" ); _isArrowHead = info.GetBoolean( "isArrowHead" ); } /// /// Populates a instance with the data needed to serialize the target object /// /// A instance that defines the serialized data /// A instance that contains the serialized data [SecurityPermissionAttribute( SecurityAction.Demand, SerializationFormatter = true )] public override void GetObjectData( SerializationInfo info, StreamingContext context ) { base.GetObjectData( info, context ); info.AddValue( "schema3", schema2 ); info.AddValue( "size", _size ); info.AddValue( "isArrowHead", _isArrowHead ); } #endregion #region Rendering Methods /// /// Render this object to the specified device. /// /// /// This method is normally only called by the Draw method /// of the parent collection object. /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// /// A reference to the object that is the parent or /// owner of this object. /// /// /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent object using the /// method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// override public void Draw( Graphics g, PaneBase pane, float scaleFactor ) { // Convert the arrow coordinates from the user coordinate system // to the screen coordinate system PointF pix1 = this.Location.TransformTopLeft( pane ); PointF pix2 = this.Location.TransformBottomRight( pane ); if ( pix1.X > -10000 && pix1.X < 100000 && pix1.Y > -100000 && pix1.Y < 100000 && pix2.X > -10000 && pix2.X < 100000 && pix2.Y > -100000 && pix2.Y < 100000 ) { // get a scaled size for the arrowhead float scaledSize = (float)( _size * scaleFactor ); // calculate the length and the angle of the arrow "vector" double dy = pix2.Y - pix1.Y; double dx = pix2.X - pix1.X; float angle = (float)Math.Atan2( dy, dx ) * 180.0F / (float)Math.PI; float length = (float)Math.Sqrt( dx * dx + dy * dy ); // Save the old transform matrix Matrix transform = g.Transform; // Move the coordinate system so it is located at the starting point // of this arrow g.TranslateTransform( pix1.X, pix1.Y ); // Rotate the coordinate system according to the angle of this arrow // about the starting point g.RotateTransform( angle ); // get a pen according to this arrow properties using ( Pen pen = _line.GetPen( pane, scaleFactor ) ) //new Pen( _color, pane.ScaledPenWidth( _penWidth, scaleFactor ) ) ) { //pen.DashStyle = _style; // Only show the arrowhead if required if ( _isArrowHead ) { // Draw the line segment for this arrow g.DrawLine( pen, 0, 0, length - scaledSize + 1, 0 ); // Create a polygon representing the arrowhead based on the scaled // size PointF[] polyPt = new PointF[4]; float hsize = scaledSize / 3.0F; polyPt[0].X = length; polyPt[0].Y = 0; polyPt[1].X = length - scaledSize; polyPt[1].Y = hsize; polyPt[2].X = length - scaledSize; polyPt[2].Y = -hsize; polyPt[3] = polyPt[0]; using ( SolidBrush brush = new SolidBrush( _line._color ) ) // render the arrowhead g.FillPolygon( brush, polyPt ); } else g.DrawLine( pen, 0, 0, length, 0 ); } // Restore the transform matrix back to its original state g.Transform = transform; } } #endregion } }