//============================================================================ //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.Collections; using System.Runtime.Serialization; using System.Security.Permissions; #if ( !DOTNET1 ) // Is this a .Net 2 compilation? using System.Collections.Generic; #endif namespace DrawGraph { /// /// This class contains the data and methods for an individual curve within /// a graph pane. It carries the settings for the curve including the /// key and item names, colors, symbols and sizes, linetypes, etc. /// /// /// John Champion /// modified by Jerry Vos /// $Revision: 3.40 $ $Date: 2007/04/16 00:03:01 $ [Serializable] abstract public class CurveItem : ISerializable, ICloneable { #region Fields /// /// protected field that stores a instance for this /// , which is used for the /// label. Use the public /// property to access this value. /// internal Label _label; /// /// protected field that stores the boolean value that determines whether this /// is on the bottom X axis or the top X axis (X2). /// Use the public property to access this value. /// protected bool _isX2Axis; /// /// protected field that stores the boolean value that determines whether this /// is on the left Y axis or the right Y axis (Y2). /// Use the public property to access this value. /// protected bool _isY2Axis; /// /// protected field that stores the index number of the Y Axis to which this /// belongs. Use the public property /// to access this value. /// protected int _yAxisIndex; /// /// protected field that stores the boolean value that determines whether this /// is visible on the graph. /// Use the public property to access this value. /// Note that this value turns the curve display on or off, but it does not /// affect the display of the legend entry. To hide the legend entry, you /// have to set to false. /// protected bool _isVisible; // Revision: JCarpenter 10/06 /// /// Protected field that stores the boolean value that determines whether this /// is selected on the graph. /// Use the public property to access this value. /// Note that this value changes the curve display color, but it does not /// affect the display of the legend entry. To hide the legend entry, you /// have to set to false. /// protected bool _isSelected; // Revision: JCarpenter 10/06 /// /// Protected field that stores the boolean value that determines whether this /// can be selected in the graph. /// protected bool _isSelectable; /// /// protected field that stores a boolean value which allows you to override the normal /// ordinal axis behavior. Use the public property to /// access this value. /// protected bool _isOverrideOrdinal; /// /// The of value sets that /// represent this . /// The size of this list determines the number of points that are /// plotted. Note that values defined as /// System.Double.MaxValue are considered "missing" values /// (see ), /// and are not plotted. The curve will have a break at these points /// to indicate the values are missing. /// protected IPointList _points; /// /// A tag object for use by the user. This can be used to store additional /// information associated with the . ZedGraph does /// not use this value for any purpose. /// /// /// Note that, if you are going to Serialize ZedGraph data, then any type /// that you store in must be a serializable type (or /// it will cause an exception). /// public object Tag; /// /// Protected field that stores the hyperlink information for this object. /// internal Link _link; #endregion #region Constructors /// /// constructor the pre-specifies the curve label, the /// x and y data values as a , the curve /// type (Bar or Line/Symbol), the , and the /// . Other properties of the curve are /// defaulted to the values in the class. /// /// A string label (legend entry) for this curve /// An array of double precision values that define /// the independent (X axis) values for this curve /// An array of double precision values that define /// the dependent (Y axis) values for this curve public CurveItem( string label, double[] x, double[] y ) : this( label, new PointPairList( x, y ) ) { } /* public CurveItem( string _label, int y ) : this( _label, new IPointList( ) ) { } */ /// /// constructor the pre-specifies the curve label, the /// x and y data values as a , the curve /// type (Bar or Line/Symbol), the , and the /// . Other properties of the curve are /// defaulted to the values in the class. /// /// A string label (legend entry) for this curve /// A of double precision value pairs that define /// the X and Y values for this curve public CurveItem( string label, IPointList points ) { Init( label ); if ( points == null ) _points = new PointPairList(); else //this.points = (IPointList) _points.Clone(); _points = points; } /// /// Internal initialization routine thats sets some initial values to defaults. /// /// A string label (legend entry) for this curve private void Init( string label ) { _label = new Label( label, null ); _isY2Axis = false; _isX2Axis = false; _isVisible = true; _isOverrideOrdinal = false; this.Tag = null; _yAxisIndex = 0; _link = new Link(); } /// /// constructor that specifies the label of the CurveItem. /// This is the same as CurveItem(label, null, null). /// /// /// A string label (legend entry) for this curve public CurveItem( string label ): this( label, null ) { } /// /// /// public CurveItem( ) { Init( null ); } /// /// The Copy Constructor /// /// The CurveItem object from which to copy public CurveItem( CurveItem rhs ) { _label = rhs._label.Clone(); _isY2Axis = rhs.IsY2Axis; _isX2Axis = rhs.IsX2Axis; _isVisible = rhs.IsVisible; _isOverrideOrdinal = rhs._isOverrideOrdinal; _yAxisIndex = rhs._yAxisIndex; if ( rhs.Tag is ICloneable ) this.Tag = ((ICloneable) rhs.Tag).Clone(); else this.Tag = rhs.Tag; _points = (IPointList) rhs.Points.Clone(); _link = rhs._link.Clone(); } /// /// Implement the interface in a typesafe manner by just /// calling the typed version of Clone. /// /// /// Note that this method must be called with an explicit cast to ICloneable, and /// that it is inherently virtual. For example: /// /// ParentClass foo = new ChildClass(); /// ChildClass bar = (ChildClass) ((ICloneable)foo).Clone(); /// /// Assume that ChildClass is inherited from ParentClass. Even though foo is declared with /// ParentClass, it is actually an instance of ChildClass. Calling the ICloneable implementation /// of Clone() on foo actually calls ChildClass.Clone() as if it were a virtual function. /// /// A deep copy of this object object ICloneable.Clone() { throw new NotImplementedException( "Can't clone an abstract base type -- child types must implement ICloneable" ); //return new PaneBase( this ); } #endregion #region Serialization /// /// Current schema value that defines the version of the serialized file /// public const int schema = 11; /// /// Constructor for deserializing objects /// /// A instance that defines the serialized data /// /// A instance that contains the serialized data /// protected CurveItem( SerializationInfo info, StreamingContext 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( "schema" ); _label = (Label) info.GetValue( "label", typeof(Label) ); _isY2Axis = info.GetBoolean( "isY2Axis" ); if ( sch >= 11 ) _isX2Axis = info.GetBoolean( "isX2Axis" ); else _isX2Axis = false; _isVisible = info.GetBoolean( "isVisible" ); _isOverrideOrdinal = info.GetBoolean( "isOverrideOrdinal" ); // Data Points are always stored as a PointPairList, regardless of the // actual original type (which could be anything that supports IPointList). _points = (PointPairList) info.GetValue( "points", typeof(PointPairList) ); Tag = info.GetValue( "Tag", typeof(object) ); _yAxisIndex = info.GetInt32( "yAxisIndex" ); _link = (Link) info.GetValue( "link", typeof(Link) ); } /// /// 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 virtual void GetObjectData( SerializationInfo info, StreamingContext context ) { info.AddValue( "schema", schema ); info.AddValue( "label", _label ); info.AddValue( "isY2Axis", _isY2Axis ); info.AddValue( "isX2Axis", _isX2Axis ); info.AddValue( "isVisible", _isVisible ); info.AddValue( "isOverrideOrdinal", _isOverrideOrdinal ); // if points is already a PointPairList, use it // otherwise, create a new PointPairList so it can be serialized PointPairList list; if ( _points is PointPairList ) list = _points as PointPairList; else list = new PointPairList( _points ); info.AddValue( "points", list ); info.AddValue( "Tag", Tag ); info.AddValue( "yAxisIndex", _yAxisIndex ); info.AddValue( "link", _link ); } #endregion #region Properties /// /// A instance that represents the /// entry for the this object /// public Label Label { get { return _label; } set { _label = value;} } /// /// The // /// color (FillColor for the Bar). This is a common access to /// Line.Color, /// Border.Color, and /// Fill.Color properties for this curve. /// public Color Color { get { if ( this is BarItem ) return ((BarItem) this).Bar.Fill.Color; else if ( this is LineItem && ((LineItem) this).Line.IsVisible ) return ((LineItem) this).Line.Color; else if ( this is LineItem ) return ((LineItem) this).Symbol.Border.Color; else if ( this is ErrorBarItem ) return ((ErrorBarItem) this).Bar.Color; else if ( this is HiLowBarItem ) return ((HiLowBarItem) this).Bar.Fill.Color; else return Color.Empty; } set { if ( this is BarItem ) { ((BarItem) this).Bar.Fill.Color = value; } else if ( this is LineItem ) { ((LineItem) this).Line.Color = value; ((LineItem) this).Symbol.Border.Color = value; ((LineItem) this).Symbol.Fill.Color = value; } else if ( this is ErrorBarItem ) ((ErrorBarItem) this).Bar.Color = value; else if ( this is HiLowBarItem ) ((HiLowBarItem) this).Bar.Fill.Color = value; } } /// /// Determines whether this is visible on the graph. /// Note that this value turns the curve display on or off, but it does not /// affect the display of the legend entry. To hide the legend entry, you /// have to set to false. /// public bool IsVisible { get { return _isVisible; } set { _isVisible = value; } } // Revision: JCarpenter 10/06 /// /// Determines whether this is selected on the graph. /// Note that this value changes the curve displayed color, but it does not /// affect the display of the legend entry. To hide the legend entry, you /// have to set to false. /// public bool IsSelected { get { return _isSelected; } set { _isSelected = value; /* if ( this is BarItem ) { ( (BarItem)this ).Bar.Fill.UseInactiveColor = !value; } else if ( this is LineItem ) { ( (LineItem)this ).Line.Fill.UseInactiveColor = !value; ( (LineItem)this ).Symbol.Fill.UseInactiveColor = !value; ( (LineItem)this ).Symbol.Fill.UseInactiveColor = !value; } else if ( this is HiLowBarItem ) ( (HiLowBarItem)this ).Bar.Fill.UseInactiveColor = !value; else if ( this is PieItem ) ( (PieItem)this ).Fill.UseInactiveColor = !value; */ } } // Revision: JCarpenter 10/06 /// /// Determines whether this can be selected in the graph. /// public bool IsSelectable { get { return _isSelectable; } set { _isSelectable = value; } } /// /// Gets or sets a value which allows you to override the normal /// ordinal axis behavior. /// /// /// Normally for an ordinal axis type, the actual data values corresponding to the ordinal /// axis will be ignored (essentially they are replaced by ordinal values, e.g., 1, 2, 3, etc). /// If IsOverrideOrdinal is true, then the user data values will be used (even if they don't /// make sense). Fractional values are allowed, such that a value of 1.5 is between the first and /// second ordinal position, etc. /// /// /// public bool IsOverrideOrdinal { get { return _isOverrideOrdinal; } set { _isOverrideOrdinal = value; } } /// /// Gets or sets a value that determines which X axis this /// is assigned to. /// /// /// The /// is on the bottom side of the graph and the /// is on the top side. Assignment to an axis /// determines the scale that is used to draw the curve on the graph. /// /// true to assign the curve to the , /// false to assign the curve to the public bool IsX2Axis { get { return _isX2Axis; } set { _isX2Axis = value; } } /// /// Gets or sets a value that determines which Y axis this /// is assigned to. /// /// /// The /// is on the left side of the graph and the /// is on the right side. Assignment to an axis /// determines the scale that is used to draw the curve on the graph. Note that /// this value is used in combination with the to determine /// which of the Y Axes (if there are multiples) this curve belongs to. /// /// true to assign the curve to the , /// false to assign the curve to the public bool IsY2Axis { get { return _isY2Axis; } set { _isY2Axis = value; } } /// /// Gets or sets the index number of the Y Axis to which this /// belongs. /// /// /// This value is essentially an index number into the /// or , depending on the setting of /// . /// public int YAxisIndex { get { return _yAxisIndex; } set { _yAxisIndex = value; } } /// /// Determines whether this /// is a . This does not include 's /// or 's. /// /// true for a bar chart, or false for a line or pie graph public bool IsBar { get { return this is BarItem; } } /// /// Determines whether this /// is a . /// /// true for a pie chart, or false for a line or bar graph public bool IsPie { get { return this is PieItem; } } /// /// Determines whether this /// is a . /// /// true for a line chart, or false for a bar type public bool IsLine { get { return this is LineItem; } } /// /// Gets a flag indicating if the Z data range should be included in the axis scaling calculations. /// /// The parent of this . /// /// true if the Z data are included, false otherwise abstract internal bool IsZIncluded( GraphPane pane ); /// /// Gets a flag indicating if the X axis is the independent axis for this /// /// The parent of this . /// /// true if the X axis is independent, false otherwise abstract internal bool IsXIndependent( GraphPane pane ); /// /// Readonly property that gives the number of points that define this /// object, which is the number of points in the /// data collection. /// public int NPts { get { if ( _points == null ) return 0; else return _points.Count; } } /// /// The of X,Y point sets that represent this /// . /// public IPointList Points { get { return _points; } set { _points = value; } } /// /// An accessor for the datum for this . /// Index is the ordinal reference (zero based) of the point. /// public PointPair this[int index] { get { if ( _points == null ) return new PointPair( PointPair.Missing, PointPair.Missing ); else return ( _points )[index]; } } /// /// Gets or sets the hyperlink information for this . /// // /// public Link Link { get { return _link; } set { _link = value; } } #endregion #region Rendering Methods /// /// Do all rendering associated with this 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 ordinal position of the current /// curve. /// /// 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. /// abstract public void Draw( Graphics g, GraphPane pane, int pos, float scaleFactor ); /// /// Draw a legend key entry for this at the specified location. /// This abstract base method passes through to or /// to do the rendering. /// /// /// 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 struct that specifies the /// location for the legend key /// /// 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. /// abstract public void DrawLegendKey( Graphics g, GraphPane pane, RectangleF rect, float scaleFactor ); #endregion #region Utility Methods /// /// Add a single x,y coordinate point to the end of the points collection for this curve. /// /// The X coordinate value /// The Y coordinate value public void AddPoint( double x, double y ) { this.AddPoint( new PointPair( x, y ) ); } /// /// Add a object to the end of the points collection for this curve. /// /// /// This method will only work if the instance reference /// at supports the interface. /// Otherwise, it does nothing. /// /// A reference to the object to /// be added public void AddPoint( PointPair point ) { if ( _points == null ) this.Points = new PointPairList(); if ( _points is IPointListEdit ) ( _points as IPointListEdit ).Add( point ); else throw new NotImplementedException(); } /// /// Clears the points from this . This is the same /// as CurveItem.Points.Clear(). /// /// /// This method will only work if the instance reference /// at supports the interface. /// Otherwise, it does nothing. /// public void Clear() { if ( _points is IPointListEdit ) (_points as IPointListEdit).Clear(); else throw new NotImplementedException(); } /// /// Removes a single point from this . /// /// /// This method will only work if the instance reference /// at supports the interface. /// Otherwise, it does nothing. /// /// The ordinal position of the point to be removed. public void RemovePoint( int index ) { if ( _points is IPointListEdit ) (_points as IPointListEdit).RemoveAt( index ); else throw new NotImplementedException(); } /// /// Get the X Axis instance (either or ) to /// which this belongs. /// /// The object to which this curve belongs. /// Either a or to which this /// belongs. /// public Axis GetXAxis( GraphPane pane ) { if ( _isX2Axis ) return pane.X2Axis; else return pane.XAxis; } /// /// Get the Y Axis instance (either or ) to /// which this belongs. /// /// /// This method safely retrieves a Y Axis instance from either the /// or the using the values of and /// . If the value of is out of bounds, the /// default or is used. /// /// The object to which this curve belongs. /// Either a or to which this /// belongs. /// public Axis GetYAxis( GraphPane pane ) { if ( _isY2Axis ) { if ( _yAxisIndex < pane.Y2AxisList.Count ) return pane.Y2AxisList[_yAxisIndex]; else return pane.Y2AxisList[0]; } else { if ( _yAxisIndex < pane.YAxisList.Count ) return pane.YAxisList[_yAxisIndex]; else return pane.YAxisList[0]; } } /// /// Get the index of the Y Axis in the or list to /// which this belongs. /// /// /// This method safely retrieves a Y Axis index into either the /// or the using the values of and /// . If the value of is out of bounds, the /// default or is used, which is index zero. /// /// The object to which this curve belongs. /// An integer value indicating which index position in the list applies to this /// /// public int GetYAxisIndex( GraphPane pane ) { if ( _yAxisIndex >= 0 && _yAxisIndex < ( _isY2Axis ? pane.Y2AxisList.Count : pane.YAxisList.Count ) ) return _yAxisIndex; else return 0; } /// /// Loads some pseudo unique colors/symbols into this CurveItem. This /// is the same as MakeUnique(ColorSymbolRotator.StaticInstance). /// /// /// /// public void MakeUnique() { this.MakeUnique( ColorSymbolRotator.StaticInstance ); } /// /// Loads some pseudo unique colors/symbols into this CurveItem. This /// is mainly useful for differentiating a set of new CurveItems without /// having to pick your own colors/symbols. /// /// /// /// The that is used to pick the color /// and symbol for this method call. /// virtual public void MakeUnique( ColorSymbolRotator rotator ) { this.Color = rotator.NextColor; } /// /// Go through the list of data values for this /// and determine the minimum and maximum values in the data. /// /// The minimum X value in the range of data /// The maximum X value in the range of data /// The minimum Y value in the range of data /// The maximum Y value in the range of data /// ignoreInitial is a boolean value that /// affects the data range that is considered for the automatic scale /// ranging (see ). If true, then initial /// data points where the Y value is zero are not included when /// automatically determining the scale , /// , and size. All data after /// the first non-zero Y value are included. /// /// /// Determines if the auto-scaled axis ranges will subset the /// data points based on any manually set scale range values. /// /// /// A reference to the object that is the parent or /// owner of this object. /// /// virtual public void GetRange( out double xMin, out double xMax, out double yMin, out double yMax, bool ignoreInitial, bool isBoundedRanges, GraphPane pane ) { // The lower and upper bounds of allowable data for the X values. These // values allow you to subset the data values. If the X range is bounded, then // the resulting range for Y will reflect the Y values for the points within the X // bounds. double xLBound = double.MinValue; double xUBound = double.MaxValue; double yLBound = double.MinValue; double yUBound = double.MaxValue; // initialize the values to outrageous ones to start xMin = yMin = Double.MaxValue; xMax = yMax = Double.MinValue; Axis yAxis = this.GetYAxis( pane ); Axis xAxis = this.GetXAxis( pane ); if ( yAxis == null || xAxis == null ) return; if ( isBoundedRanges ) { xLBound = xAxis._scale._lBound; xUBound = xAxis._scale._uBound; yLBound = yAxis._scale._lBound; yUBound = yAxis._scale._uBound; } bool isZIncluded = this.IsZIncluded( pane ); bool isXIndependent = this.IsXIndependent( pane ); bool isXLog = xAxis.Scale.IsLog; bool isYLog = yAxis.Scale.IsLog; // Loop over each point in the arrays //foreach ( PointPair point in this.Points ) for ( int i=0; i xUBound || curY < yLBound || curY > yUBound || ( isZIncluded && isXIndependent && ( curZ < yLBound || curZ > yUBound ) ) || ( isZIncluded && !isXIndependent && ( curZ < xLBound || curZ > xUBound ) ) || ( curX <= 0 && isXLog ) || ( curY <= 0 && isYLog ); // ignoreInitial becomes false at the first non-zero // Y value if ( ignoreInitial && curY != 0 && curY != PointPair.Missing ) ignoreInitial = false; if ( !ignoreInitial && !outOfBounds && curX != PointPair.Missing && curY != PointPair.Missing ) { if ( curX < xMin ) xMin = curX; if ( curX > xMax ) xMax = curX; if ( curY < yMin ) yMin = curY; if ( curY > yMax ) yMax = curY; if ( isZIncluded && isXIndependent && curZ != PointPair.Missing ) { if ( curZ < yMin ) yMin = curZ; if ( curZ > yMax ) yMax = curZ; } else if ( isZIncluded && curZ != PointPair.Missing ) { if ( curZ < xMin ) xMin = curZ; if ( curZ > xMax ) xMax = curZ; } } } } /// Returns a reference to the object that is the "base" /// (independent axis) from which the values are drawn. /// /// This property is determined by the value of for /// , , and /// types. It is always the X axis for regular types. /// Note that the setting can override the /// and settings for bar types /// (this is because all the bars that are clustered together must share the /// same base axis). /// /// /// public virtual Axis BaseAxis( GraphPane pane ) { BarBase barBase; if ( this is BarItem || this is ErrorBarItem || this is HiLowBarItem ) barBase = pane._barSettings.Base; else barBase = _isX2Axis ? BarBase.X2 : BarBase.X; if ( barBase == BarBase.X ) return pane.XAxis; else if ( barBase == BarBase.X2 ) return pane.X2Axis; else if ( barBase == BarBase.Y ) return pane.YAxis; else return pane.Y2Axis; } /// Returns a reference to the object that is the "value" /// (dependent axis) from which the points are drawn. /// /// This property is determined by the value of for /// , , and /// types. It is always the Y axis for regular types. /// /// /// public virtual Axis ValueAxis( GraphPane pane ) { BarBase barBase; if ( this is BarItem || this is ErrorBarItem || this is HiLowBarItem ) barBase = pane._barSettings.Base; else barBase = BarBase.X; if ( barBase == BarBase.X || barBase == BarBase.X2 ) { return GetYAxis( pane ); } else return GetXAxis( pane ); } /// /// Calculate the width of each bar, depending on the actual bar type /// /// The width for an individual bar, in pixel units public float GetBarWidth( GraphPane pane ) { // Total axis width = // npts * ( nbars * ( bar + bargap ) - bargap + clustgap ) // cg * bar = cluster gap // npts = max number of points in any curve // nbars = total number of curves that are of type IsBar // bar = bar width // bg * bar = bar gap // therefore: // totwidth = npts * ( nbars * (bar + bg*bar) - bg*bar + cg*bar ) // totwidth = bar * ( npts * ( nbars * ( 1 + bg ) - bg + cg ) ) // solve for bar float barWidth; if ( this is ErrorBarItem ) barWidth = (float) ( ((ErrorBarItem)this).Bar.Symbol.Size * pane.CalcScaleFactor() ); else if ( this is HiLowBarItem ) // barWidth = (float) ( ((HiLowBarItem)this).Bar.GetBarWidth( pane, // ((HiLowBarItem)this).BaseAxis(pane), pane.CalcScaleFactor() ) ); barWidth = (float) ( ((HiLowBarItem)this).Bar.Size * pane.CalcScaleFactor() ); else // BarItem or LineItem { // For stacked bar types, the bar width will be based on a single bar float numBars = 1.0F; if ( pane._barSettings.Type == BarType.Cluster || pane._barSettings.Type == BarType.ClusterHiLow ) numBars = pane.CurveList.NumBars; float denom = numBars * ( 1.0F + pane._barSettings.MinBarGap ) - pane._barSettings.MinBarGap + pane._barSettings.MinClusterGap; if ( denom <= 0 ) denom = 1; barWidth = pane.BarSettings.GetClusterWidth() / denom; } if ( barWidth <= 0 ) return 1; return barWidth; } /// /// Determine the coords for the rectangle associated with a specified point for /// this /// /// The to which this curve belongs /// The index of the point of interest /// A list of coordinates that represents the "rect" for /// this point (used in an html AREA tag) /// true if it's a valid point, false otherwise abstract public bool GetCoords( GraphPane pane, int i, out string coords ); #endregion #region Inner classes #if ( DOTNET1 ) // Is this a .Net 1.1 compilation? /// /// Compares 's based on the point value at the specified /// index and for the specified axis. /// /// public class Comparer : IComparer { private int index; private SortType sortType; /// /// Constructor for Comparer. /// /// The axis type on which to sort. /// The index number of the point on which to sort public Comparer( SortType type, int index ) { this.sortType = type; this.index = index; } /// /// Compares two s using the previously specified index value /// and axis. Sorts in descending order. /// /// Curve to the left. /// Curve to the right. /// -1, 0, or 1 depending on l.X's relation to r.X public int Compare( object l, object r ) { CurveItem cl = (CurveItem) l; CurveItem cr = (CurveItem) r; if (cl == null && cr == null ) return 0; else if (cl == null && cr != null ) return -1; else if (cl != null && cr == null) return 1; if ( cr != null && cr.NPts <= index ) cr = null; if ( cl != null && cl.NPts <= index ) cl = null; double lVal, rVal; if ( sortType == SortType.XValues ) { lVal = ( l != null ) ? System.Math.Abs( cl[index].X ) : PointPair.Missing; rVal = ( r != null ) ? System.Math.Abs( cr[index].X ) : PointPair.Missing; } else { lVal = ( l != null ) ? System.Math.Abs( cl[index].Y ) : PointPair.Missing; rVal = ( r != null ) ? System.Math.Abs( cr[index].Y ) : PointPair.Missing; } if ( lVal == PointPair.Missing || Double.IsInfinity( lVal ) || Double.IsNaN( lVal ) ) cl = null; if ( rVal == PointPair.Missing || Double.IsInfinity( rVal ) || Double.IsNaN( rVal ) ) cr = null; if ( ( cl == null && cr == null) || ( System.Math.Abs( lVal - rVal ) < 1e-10 ) ) return 0; else if ( cl == null && cr != null ) return -1; else if ( cl != null && r == null ) return 1; else return rVal < lVal ? -1 : 1; } } #else // Otherwise, it's .Net 2.0 so use generics /// /// Compares 's based on the point value at the specified /// index and for the specified axis. /// /// public class Comparer : IComparer { private int index; private SortType sortType; /// /// Constructor for Comparer. /// /// The axis type on which to sort. /// The index number of the point on which to sort public Comparer( SortType type, int index ) { this.sortType = type; this.index = index; } /// /// Compares two s using the previously specified index value /// and axis. Sorts in descending order. /// /// Curve to the left. /// Curve to the right. /// -1, 0, or 1 depending on l.X's relation to r.X public int Compare( CurveItem l, CurveItem r ) { if (l == null && r == null ) return 0; else if (l == null && r != null ) return -1; else if (l != null && r == null) return 1; if ( r != null && r.NPts <= index ) r = null; if ( l != null && l.NPts <= index ) l = null; double lVal, rVal; if ( sortType == SortType.XValues ) { lVal = ( l != null ) ? System.Math.Abs( l[index].X ) : PointPair.Missing; rVal = ( r != null ) ? System.Math.Abs( r[index].X ) : PointPair.Missing; } else { lVal = ( l != null ) ? System.Math.Abs( l[index].Y ) : PointPair.Missing; rVal = ( r != null ) ? System.Math.Abs( r[index].Y ) : PointPair.Missing; } if ( lVal == PointPair.Missing || Double.IsInfinity( lVal ) || Double.IsNaN( lVal ) ) l = null; if ( rVal == PointPair.Missing || Double.IsInfinity( rVal ) || Double.IsNaN( rVal ) ) r = null; if ( (l == null && r == null) || ( System.Math.Abs( lVal - rVal ) < 1e-10 ) ) return 0; else if (l == null && r != null ) return -1; else if (l != null && r == null) return 1; else return rVal < lVal ? -1 : 1; } } #endif #endregion } }