File: Common\General\Axis.cs
Project: ndp\fx\src\DataVisualization\System.Windows.Forms.DataVisualization.csproj (System.Windows.Forms.DataVisualization)
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
//   Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
//  File:		Axis.cs
//
//  Namespace:	System.Web.UI.WebControls[Windows.Forms].Charting
//
//	Classes:	Axis
//
//  Purpose:	Axis related properties and methods. Axis class gives 
//				information to Common.Chart series about 
//				position in the Common.Chart area and keeps all necessary 
//				information about axes.
//
//	Reviewed:	GS - August 6, 2002
//				AG - August 7, 2002
//
//===================================================================
 
#region Used namespace
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.Diagnostics.CodeAnalysis;
#if Microsoft_CONTROL
	using System.Windows.Forms.DataVisualization.Charting;
	using System.Windows.Forms.DataVisualization.Charting.Data;
	using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
	using System.Windows.Forms.DataVisualization.Charting.Utilities;
	using System.Windows.Forms.DataVisualization.Charting.Borders3D;
 
#else
using System.Web;
using System.Web.UI;
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.DataVisualization.Charting.Data;
using System.Web.UI.DataVisualization.Charting.Utilities;
using System.Web.UI.DataVisualization.Charting.ChartTypes;
#endif
 
 
#endregion
 
#if Microsoft_CONTROL
	namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
 
#endif
{
    #region Axis name enumeration
 
    /// <summary>
    /// An enumeration of auto-fitting styles of the axis labels.
    /// </summary>
    [Flags]
    public enum LabelAutoFitStyles
    {
        /// <summary>
        /// No auto-fitting.
        /// </summary>
        None = 0,
        /// <summary>
        /// Allow font size increasing.
        /// </summary>
        IncreaseFont = 1,
        /// <summary>
        /// Allow font size decreasing.
        /// </summary>
        DecreaseFont = 2,
        /// <summary>
        /// Allow using staggered labels.
        /// </summary>
        StaggeredLabels = 4,
        /// <summary>
        /// Allow changing labels angle using values of 0, 30, 60 and 90 degrees.
        /// </summary>
        LabelsAngleStep30 = 8,
        /// <summary>
        /// Allow changing labels angle using values of 0, 45, 90 degrees.
        /// </summary>
        LabelsAngleStep45 = 16,
        /// <summary>
        /// Allow changing labels angle using values of 0 and 90 degrees.
        /// </summary>
        LabelsAngleStep90 = 32,
        /// <summary>
        /// Allow replacing spaces with the new line character.
        /// </summary>
        WordWrap = 64,
    }
 
    /// <summary>
    /// An enumeration of axis names.
    /// </summary>
    public enum AxisName
    {
        /// <summary>
        /// Primary X Axis.
        /// </summary>
 
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "X")]
        X = 0,
        /// <summary>
        /// Primary Y Axis.
        /// </summary>
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Y")]
        Y = 1,
        /// <summary>
        /// Secondary X Axis.
        /// </summary>
        X2 = 2,
        /// <summary>
        /// Secondary Y Axis.
        /// </summary>
        Y2 = 3
    }
 
    #endregion
 
    /// <summary>
    /// The Axis class gives information to the Common.Chart series 
    /// about positions in the Common.Chart area and keeps all of 
    ///	the data about the axis.
    /// </summary>
    [
        SRDescription("DescriptionAttributeAxis_Axis"),
        DefaultProperty("Enabled"),
    ]
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
#if Microsoft_CONTROL
    public partial class Axis :  ChartNamedElement
#else
	public partial class Axis :  ChartNamedElement, IChartMapArea
#endif
    {
        #region Axis fields
 
        /// <summary>
        /// Plot area position
        /// </summary>
        internal ElementPosition PlotAreaPosition;
 
        // This field synchronies Store and Reset temporary values
        private bool _storeValuesEnabled = true;
 
        private FontCache _fontCache = new FontCache();
        private Font  _titleFont;
        private Color _titleForeColor = Color.Black;
        private StringAlignment _titleAlignment = StringAlignment.Center;
        private string _title = "";
        private int _lineWidth = 1;
        private ChartDashStyle _lineDashStyle = ChartDashStyle.Solid;
        private Color _lineColor = Color.Black;
        private bool _isLabelAutoFit = true;
        private AxisArrowStyle _arrowStyle = AxisArrowStyle.None;
        private StripLinesCollection _stripLines = null;
        private bool _isMarksNextToAxis = true;
 
        // Default text orientation
        private TextOrientation _textOrientation = TextOrientation.Auto;
 
        // Size of the axis elements in percentage
        internal float titleSize = 0F;
        internal float labelSize = 0F;
        internal float labelNearOffset = 0F;
        internal float labelFarOffset = 0F;
        internal float unRotatedLabelSize = 0F;
        internal float markSize = 0F;
        internal float scrollBarSize = 0F;
        internal float totlaGroupingLabelsSize = 0F;
        internal float[] groupingLabelSizes = null;
        internal float totlaGroupingLabelsSizeAdjustment = 0f;
        private LabelAutoFitStyles _labelAutoFitStyle = LabelAutoFitStyles.DecreaseFont |
                                                            LabelAutoFitStyles.IncreaseFont |
                                                            LabelAutoFitStyles.LabelsAngleStep30 |
                                                            LabelAutoFitStyles.StaggeredLabels |
                                                            LabelAutoFitStyles.WordWrap;
 
        // Auto calculated font for labels
        internal Font autoLabelFont = null;
        internal int autoLabelAngle = -1000;
        internal int autoLabelOffset = -1;
 
        // Labels auto fitting constants
        private float _aveLabelFontSize = 10F;
        private float _minLabelFontSize = 5F;
        // Determines maximum label size of the chart area.
        private float _maximumAutoSize = 75f;
 
        // Chart title position rectangle
        private RectangleF _titlePosition = RectangleF.Empty;
 
        // Element spacing size
        internal const float elementSpacing = 1F;
 
        // Maximum total size of the axis's elements in percentage
        private const float maxAxisElementsSize = 75F;
 
        // Maximum size of the axis title in percentage
        private const float maxAxisTitleSize = 20F;
 
        // Maximum size of the axis second row of labels in percentage 
        // of the total labels size
        private const float maxAxisLabelRow2Size = 45F;
 
        // Maximum size of the axis tick marks in percentage
        private const float maxAxisMarkSize = 20F;
 
        // Minimum cached value from data series.
        internal double minimumFromData = double.NaN;
 
        // Maximum cached value from data series.
        internal double maximumFromData = double.NaN;
 
        // Flag, which tells to Set Data method to take, again values from 
        // data source and not to use cached values.
        internal bool refreshMinMaxFromData = true;
 
        // Flag, which tells to Set Data method to take, again values from 
        // data source and not to use cached values.
        internal int numberOfPointsInAllSeries = 0;
 
        // Original axis scaleView position
        private double _originalViewPosition = double.NaN;
 
 
        /// <summary>
        /// Indicates that isInterlaced strip lines will be displayed for the axis.
        /// </summary>
        private bool _isInterlaced = false;
 
        /// <summary>
        /// Color used to draw isInterlaced strip lines for the axis.
        /// </summary>
        private Color _interlacedColor = Color.Empty;
 
        /// <summary>
        /// Axis interval offset.
        /// </summary>
        private double _intervalOffset = 0;
 
        /// <summary>
        /// Axis interval.
        /// </summary>
        internal double interval = 0;
 
        /// <summary>
        /// Axis interval units type.
        /// </summary>
        internal DateTimeIntervalType intervalType = DateTimeIntervalType.Auto;
 
        /// <summary>
        /// Axis interval offset units type.
        /// </summary>
        internal DateTimeIntervalType intervalOffsetType = DateTimeIntervalType.Auto;
 
        /// <summary>
		/// Minimum font size that can be used by the labels auto-fitting algorithm.
		/// </summary>
		internal int					labelAutoFitMinFontSize = 6;
 
		/// <summary>
		/// Maximum font size that can be used by the labels auto-fitting algorithm.
		/// </summary>
		internal int					labelAutoFitMaxFontSize = 10;
 
		/// <summary>
		/// Axis tooltip
		/// </summary>
		private	string					_toolTip = String.Empty;
 
        /// <summary>
        /// Axis HREF
        /// </summary>
        private string _url = String.Empty;
 
#if !Microsoft_CONTROL
 
        
        /// <summary>
		/// Axis map area attributes
		/// </summary>
		private	string					_mapAreaAttributes = String.Empty;
 
        private string _postbackValue = String.Empty;
 
#endif
 
        #endregion
 
        #region Axis constructor and initialization
 
        /// <summary>
        /// Default constructor of Axis.
        /// </summary>
        public Axis()
            : base(null, GetName(AxisName.X))
        {
            Initialize(AxisName.X);
        }
 
        /// <summary>
        /// Axis constructor.
        /// </summary>
        /// <param name="chartArea">The chart area the axis belongs to.</param>
        /// <param name="axisTypeName">The type of the axis.</param>
        public Axis(ChartArea chartArea, AxisName axisTypeName)
            : base(chartArea, GetName(axisTypeName)) 
        {
            Initialize(axisTypeName);
        }
 
        /// <summary>
        /// Initialize axis class
        /// </summary>
        /// <param name="axisTypeName">Name of the axis type.</param>
        private void Initialize(AxisName axisTypeName)
        {
            // DT: Axis could be already created. Don't recreate new labelstyle and other objects.
            // Initialize axis labels
            if (labelStyle == null)
            {
                labelStyle = new LabelStyle(this);
            }
            if (_customLabels == null)
            {
                _customLabels = new CustomLabelsCollection(this);
            }
            if (_scaleView == null)
            {
                // Create axis data scaleView object
                _scaleView = new AxisScaleView(this);
            }
#if Microsoft_CONTROL
            if (scrollBar == null)
            {
                // Create axis croll bar class
                scrollBar = new AxisScrollBar(this);
            }
#endif // Microsoft_CONTROL
 
            this.axisType = axisTypeName;
 
            // Create grid & tick marks objects
            if (minorTickMark == null)
            {
                minorTickMark = new TickMark(this, false);
            }
            if (majorTickMark == null)
            {
                majorTickMark = new TickMark(this, true);
                majorTickMark.Interval = double.NaN;
                majorTickMark.IntervalOffset = double.NaN;
                majorTickMark.IntervalType = DateTimeIntervalType.NotSet;
                majorTickMark.IntervalOffsetType = DateTimeIntervalType.NotSet;
            }
            if (minorGrid == null)
            {
                minorGrid = new Grid(this, false);
            }
            if (majorGrid == null)
            {
                majorGrid = new Grid(this, true);
                majorGrid.Interval = double.NaN;
                majorGrid.IntervalOffset = double.NaN;
                majorGrid.IntervalType = DateTimeIntervalType.NotSet;
                majorGrid.IntervalOffsetType = DateTimeIntervalType.NotSet;
            }
            if (this._stripLines == null)
            {
                this._stripLines = new StripLinesCollection(this);
            }
 
            if (_titleFont == null)
            {
                _titleFont = _fontCache.DefaultFont;
            }
#if SUBAXES
			if(this.subAxes == null)
			{
				this.subAxes = new SubAxisCollection(this);
			}
#endif // SUBAXES
 
#if Microsoft_CONTROL

            // Initialize axis scroll bar class
            this.ScrollBar.Initialize();
 
#endif // Microsoft_CONTROL
 
            // Create collection of scale segments
            if (this.scaleSegments == null)
            {
                this.scaleSegments = new AxisScaleSegmentCollection(this);
            }
 
            // Create scale break style
            if (this.axisScaleBreakStyle == null)
            {
                this.axisScaleBreakStyle = new AxisScaleBreakStyle(this);
            }
        }
 
        /// <summary>
        /// Initialize axis class
        /// </summary>
        /// <param name="chartArea">Chart area that the axis belongs.</param>
        /// <param name="axisTypeName">Axis type.</param>
        internal void Initialize(ChartArea chartArea, AxisName axisTypeName)
        {
            this.Initialize(axisTypeName);
            this.Parent = chartArea;
            this.Name = GetName(axisTypeName);
        }
 
        /// <summary>
        /// Set Axis Name
        /// </summary>
        internal static string GetName(AxisName axisName)
        {
            // Set axis name.
            // NOTE: Strings below should neber be localized. Name properties in the chart are never localized 
            // and represent consisten object name in all locales.
            switch (axisName)
            {
                case (AxisName.X):
                    return "X axis";
                case (AxisName.Y):
                    return "Y (Value) axis";
                case (AxisName.X2):
                    return "Secondary X axis";
                case (AxisName.Y2):
                    return "Secondary Y (Value) axis";
            }
            return null;
        }
 
        #endregion
 
        #region Axis properies
 
        // Internal
        internal ChartArea ChartArea
        {
            get { return Parent as ChartArea; }
        }
 
        /// <summary>
        /// Text orientation.
        /// </summary>
        [
        SRCategory("CategoryAttributeTitle"),
        Bindable(true),
        DefaultValue(TextOrientation.Auto),
        SRDescription("DescriptionAttribute_TextOrientation"),
        NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public TextOrientation TextOrientation
        {
            get
            {
                return this._textOrientation;
            }
            set
            {
                this._textOrientation = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Returns sub-axis name.
        /// </summary>
        virtual internal string SubAxisName
        {
            get
            {
                return string.Empty;
            }
        }
 
#if SUBAXES

		/// <summary>
		/// Indicates if this axis object present the main or sub axis.
		/// </summary>
		virtual internal bool IsSubAxis
		{
			get
			{
				return false;
			}
		}
 
		private SubAxisCollection subAxes = null;
 
		/// <summary>
		/// Sub-axes collection.
		/// </summary>
		[
		SRCategory("CategoryAttributeSubAxes"),
		Bindable(true),
		SRDescription("DescriptionAttributeSubAxes"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
		PersistenceMode(PersistenceMode.InnerProperty),
#endif
        Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base)
		]
		virtual public SubAxisCollection SubAxes
		{
			get
			{
				return this.subAxes;
			}
		}
 
#endif // SUBAXES
 
        /// <summary>
        /// Gets or sets a flag which indicates whether interlaced strip lines will be displayed for the axis.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        DefaultValue(false),
        SRDescription("DescriptionAttributeInterlaced"),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute),
#endif
 NotifyParentPropertyAttribute(true),
        ]
        public bool IsInterlaced
        {
            get
            {
                return _isInterlaced;
            }
            set
            {
                _isInterlaced = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the color used to draw interlaced strip lines for the axis.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        DefaultValue(typeof(Color), ""),
        SRDescription("DescriptionAttributeInterlacedColor"),
        NotifyParentPropertyAttribute(true),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public Color InterlacedColor
        {
            get
            {
                return _interlacedColor;
            }
            set
            {
                _interlacedColor = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Axis name. This field is reserved for internal use only.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        Browsable(false),
        DefaultValue(""),
        SRDescription("DescriptionAttributeAxis_Name"),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute),
#endif
 DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
        SerializationVisibilityAttribute(SerializationVisibility.Hidden)
        ]
        public override string Name
        {
            get
            {
                return base.Name;
            }
            set
            {
                base.Name = value;
            }
        }
 
        /// <summary>
        /// Axis name. This field is reserved for internal use only.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        Browsable(false),
        DefaultValue(""),
        SRDescription("DescriptionAttributeType"),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute),
#endif
 DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
        SerializationVisibilityAttribute(SerializationVisibility.Hidden)
        ]
        virtual public AxisName AxisName
        {
            get
            {
                return axisType;
            }
        }
 
        /// <summary>
        /// Gets or sets the arrow style used for the axis.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        DefaultValue(AxisArrowStyle.None),
        NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeArrows"),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public AxisArrowStyle ArrowStyle
        {
            get
            {
                return _arrowStyle;
            }
            set
            {
                _arrowStyle = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the properties used for the major gridlines.
        /// </summary>
        [
        SRCategory("CategoryAttributeGridTickMarks"),
        Bindable(true),
        NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeMajorGrid"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
 PersistenceMode(PersistenceMode.InnerProperty),
#endif
 TypeConverter(typeof(NoNameExpandableObjectConverter))
        ]
        public Grid MajorGrid
        {
            get
            {
                return majorGrid;
            }
            set
            {
                majorGrid = value;
                majorGrid.Axis = this;
                majorGrid.majorGridTick = true;
 
                if (!majorGrid.intervalChanged)
                    majorGrid.Interval = double.NaN;
                if (!majorGrid.intervalOffsetChanged)
                    majorGrid.IntervalOffset = double.NaN;
                if (!majorGrid.intervalTypeChanged)
                    majorGrid.IntervalType = DateTimeIntervalType.NotSet;
                if (!majorGrid.intervalOffsetTypeChanged)
                    majorGrid.IntervalOffsetType = DateTimeIntervalType.NotSet;
 
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the properties used for the minor gridlines.
        /// </summary>
        [
        SRCategory("CategoryAttributeGridTickMarks"),
        Bindable(true),
        NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeMinorGrid"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
 PersistenceMode(PersistenceMode.InnerProperty),
#endif
 TypeConverter(typeof(NoNameExpandableObjectConverter))
        ]
        public Grid MinorGrid
        {
            get
            {
                return minorGrid;
            }
            set
            {
                minorGrid = value;
                minorGrid.Initialize(this, false);
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the properties used for the major tick marks.
        /// </summary>
        [
        SRCategory("CategoryAttributeGridTickMarks"),
        Bindable(true),
        NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeMajorTickMark"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
 PersistenceMode(PersistenceMode.InnerProperty),
#endif
 TypeConverter(typeof(NoNameExpandableObjectConverter))
        ]
        public TickMark MajorTickMark
        {
            get
            {
                return majorTickMark;
            }
            set
            {
                majorTickMark = value;
                majorTickMark.Axis = this;
                majorTickMark.majorGridTick = true;
 
                if (!majorTickMark.intervalChanged)
                    majorTickMark.Interval = double.NaN;
                if (!majorTickMark.intervalOffsetChanged)
                    majorTickMark.IntervalOffset = double.NaN;
                if (!majorTickMark.intervalTypeChanged)
                    majorTickMark.IntervalType = DateTimeIntervalType.NotSet;
                if (!majorTickMark.intervalOffsetTypeChanged)
                    majorTickMark.IntervalOffsetType = DateTimeIntervalType.NotSet;
 
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the properties used for the minor tick marks.
        /// </summary>
        [
        SRCategory("CategoryAttributeGridTickMarks"),
        Bindable(true),
        NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeMinorTickMark"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
 PersistenceMode(PersistenceMode.InnerProperty),
#endif
 TypeConverter(typeof(NoNameExpandableObjectConverter))
        ]
        public TickMark MinorTickMark
        {
            get
            {
                return minorTickMark;
            }
            set
            {
                minorTickMark = value;
                minorTickMark.Initialize(this, false);
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets a flag which indicates whether auto-fitting of labels is enabled.
        /// </summary>
        [
        SRCategory("CategoryAttributeLabels"),
        Bindable(true),
        DefaultValue(true),
        SRDescription("DescriptionAttributeLabelsAutoFit"),
        NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute),
#endif
 RefreshPropertiesAttribute(RefreshProperties.All)
        ]
        public bool IsLabelAutoFit
        {
            get
            {
                return _isLabelAutoFit;
            }
            set
            {
                _isLabelAutoFit = value;
                this.Invalidate();
            }
        }
 
 
 
		/// <summary>
        /// Gets or sets the minimum font size that can be used by 
        /// the label auto-fitting algorithm.
		/// </summary>
		[
		SRCategory("CategoryAttributeLabels"),
		Bindable(true),
		DefaultValue(6),
		SRDescription("DescriptionAttributeLabelsAutoFitMinFontSize"),
		NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
#endif
		RefreshPropertiesAttribute(RefreshProperties.All)
		]
		public int LabelAutoFitMinFontSize
		{
			get
			{
				return this.labelAutoFitMinFontSize;
			}
			set
			{
				// Font size cannot be less than 5
				if(value < 5)
				{
                    throw (new InvalidOperationException(SR.ExceptionAxisLabelsAutoFitMinFontSizeValueInvalid));
				}
 
				this.labelAutoFitMinFontSize = value;
				this.Invalidate();
			}
		}
 
		/// <summary>
        /// Gets or sets the maximum font size that can be used by 
        /// the label auto-fitting algorithm.
		/// </summary>
		[
		SRCategory("CategoryAttributeLabels"),
		Bindable(true),
		DefaultValue(10),
		SRDescription("DescriptionAttributeLabelsAutoFitMaxFontSize"),
		NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
		PersistenceMode(PersistenceMode.Attribute),
#endif
		RefreshPropertiesAttribute(RefreshProperties.All)
		]
		public int LabelAutoFitMaxFontSize
		{
			get
			{
				return this.labelAutoFitMaxFontSize;
			}
			set
			{
				// Font size cannot be less than 5
				if(value < 5)
				{
                    throw (new InvalidOperationException(SR.ExceptionAxisLabelsAutoFitMaxFontSizeInvalid));
				}
 
				this.labelAutoFitMaxFontSize = value;
				this.Invalidate();
			}
		}
 
 
 
        /// <summary>
        /// Gets or sets the auto-fitting style used for the labels. 
        /// IsLabelAutoFit must be set to true.
        /// </summary>
        [
        SRCategory("CategoryAttributeLabels"),
        Bindable(true),
        DefaultValue(LabelAutoFitStyles.DecreaseFont | LabelAutoFitStyles.IncreaseFont | LabelAutoFitStyles.LabelsAngleStep30 | LabelAutoFitStyles.StaggeredLabels | LabelAutoFitStyles.WordWrap),
        SRDescription("DescriptionAttributeLabelsAutoFitStyle"),
        NotifyParentPropertyAttribute(true),
        Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute),
#endif
]
        public LabelAutoFitStyles LabelAutoFitStyle
        {
            get
            {
                return this._labelAutoFitStyle;
            }
            set
            {
                this._labelAutoFitStyle = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets a flag which indicates whether
        /// tick marks and labels move with the axis when 
        /// the crossing value changes.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        DefaultValue(true),
        SRDescription("DescriptionAttributeMarksNextToAxis"),
        NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        virtual public bool IsMarksNextToAxis
        {
            get
            {
                return _isMarksNextToAxis;
            }
            set
            {
                _isMarksNextToAxis = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the axis title.
        /// </summary>
        [
        SRCategory("CategoryAttributeTitle"),
        Bindable(true),
        DefaultValue(""),
        SRDescription("DescriptionAttributeTitle6"),
        NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                _title = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the color of the axis title.
        /// </summary>
        [
        SRCategory("CategoryAttributeTitle"),
        Bindable(true),
        DefaultValue(typeof(Color), "Black"),
        SRDescription("DescriptionAttributeTitleColor"),
        NotifyParentPropertyAttribute(true),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public Color TitleForeColor
        {
            get
            {
                return _titleForeColor;
            }
            set
            {
                _titleForeColor = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the alignment of the axis title.
        /// </summary>
        [
        SRCategory("CategoryAttributeTitle"),
        Bindable(true),
        DefaultValue(typeof(StringAlignment), "Center"),
        SRDescription("DescriptionAttributeTitleAlignment"),
        NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public StringAlignment TitleAlignment
        {
            get
            {
                return _titleAlignment;
            }
            set
            {
                _titleAlignment = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the font used for the axis title.
        /// </summary>
        [
        SRCategory("CategoryAttributeTitle"),
        Bindable(true),
        DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
        SRDescription("DescriptionAttributeTitleFont"),
        NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public Font TitleFont
        {
            get
            {
                return _titleFont;
            }
            set
            {
                _titleFont = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the line color of the axis.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        DefaultValue(typeof(Color), "Black"),
        SRDescription("DescriptionAttributeLineColor"),
        NotifyParentPropertyAttribute(true),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public Color LineColor
        {
            get
            {
                return _lineColor;
            }
            set
            {
                _lineColor = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the line width of the axis.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        DefaultValue(1),
        SRDescription("DescriptionAttributeLineWidth"),
        NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public int LineWidth
        {
            get
            {
                return _lineWidth;
            }
            set
            {
                if (value < 0)
                {
                    throw (new ArgumentOutOfRangeException("value", SR.ExceptionAxisWidthIsNegative));
                }
                _lineWidth = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the line style of the axis.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        DefaultValue(ChartDashStyle.Solid),
        SRDescription("DescriptionAttributeLineDashStyle"),
        NotifyParentPropertyAttribute(true),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public ChartDashStyle LineDashStyle
        {
            get
            {
                return _lineDashStyle;
            }
            set
            {
                _lineDashStyle = value;
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// The collection of strip lines of the axis.
        /// </summary>
        [
        SRCategory("CategoryAttributeAppearance"),
        Bindable(true),
        SRDescription("DescriptionAttributeStripLines"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
 PersistenceMode(PersistenceMode.InnerProperty),
#endif
        Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base)
        ]
        public StripLinesCollection StripLines
        {
            get
            {
                return _stripLines;
            }
        }
 
 
        /// <summary>
        /// Gets or sets the maximum size (in percentage) of the axis used in the automatic layout algorithm.
        /// </summary>
        /// <remarks>
        /// This property determines the maximum size of the axis, measured as a percentage of the chart area.
        /// </remarks>
        [
        SRCategory("CategoryAttributeLabels"),
        DefaultValue(75f),
        SRDescription("DescriptionAttributeAxis_MaxAutoSize"),
        ]
        public float MaximumAutoSize
        {
            get
            {
                return this._maximumAutoSize;
            }
            set
            {
                if (value < 0f || value > 100f)
                {
                    throw (new ArgumentOutOfRangeException("value", SR.ExceptionValueMustBeInRange("MaximumAutoSize", "0", "100")));
                }
                this._maximumAutoSize = value;
                this.Invalidate();
            }
        }
        #endregion
 
        #region	IMapAreaAttributes Properties implementation
 
		/// <summary>
		/// Tooltip of the axis.
		/// </summary>
		[
		SRCategory("CategoryAttributeMapArea"),
		Bindable(true),
		SRDescription("DescriptionAttributeToolTip"),
		DefaultValue(""),
		]
		public string ToolTip
		{
			set
			{
				this._toolTip = value;
			}
			get
			{
				return this._toolTip;
			}
		}
 
#if !Microsoft_CONTROL
 
		/// <summary>
		/// URL target of the axis.
		/// </summary>
		[
		SRCategory("CategoryAttributeMapArea"),
		Bindable(true),
		SRDescription("DescriptionAttributeUrl"),
		DefaultValue(""),
		PersistenceMode(PersistenceMode.Attribute),
        Editor(Editors.UrlValueEditor.Editor, Editors.UrlValueEditor.Base)
		]
		public string Url
		{
			set
			{
				this._url = value;
			}
			get
			{
                return this._url;
			}
		}
 
 
		/// <summary>
		/// Gets or sets the map area attributes.
		/// </summary>
		[
		SRCategory("CategoryAttributeMapArea"),
		Bindable(true),
		SRDescription("DescriptionAttributeMapAreaAttributes"),
		DefaultValue(""),
		PersistenceMode(PersistenceMode.Attribute)
		]
		public string MapAreaAttributes
		{
			set
			{
				this._mapAreaAttributes = value;
			}
			get
			{
                return this._mapAreaAttributes;
			}
		}
 
        /// <summary>
        /// Gets or sets the postback value which can be processed on click event.
        /// </summary>
        /// <value>The value which is passed to click event as argument.</value>
        [DefaultValue("")]
        [SRCategory(SR.Keys.CategoryAttributeMapArea)]
        [SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
        public string PostBackValue
        {
            get
            {
                return this._postbackValue;
            }
            set
            {
                this._postbackValue = value;
            }
        }
 
 
#endif // !Microsoft_CONTROL
 
 
 
        #endregion
 
        #region Axis Interavl properies
 
        /// <summary>
        /// Axis interval size.
        /// </summary>
        [
        SRCategory("CategoryAttributeInterval"),
        Bindable(true),
        DefaultValue(0.0),
        SRDescription("DescriptionAttributeInterval4"),
        RefreshPropertiesAttribute(RefreshProperties.All),
        TypeConverter(typeof(AxisIntervalValueConverter)),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute),
#endif
]
        public double Interval
        {
            get
            {
                return interval;
            }
            set
            {
                // Axis interval properties must be set
                if (double.IsNaN(value))
                {
                    interval = 0;
                }
                else
                {
                    interval = value;
                }
 
                // Reset initial values
                majorGrid.interval = tempMajorGridInterval;
                majorTickMark.interval = tempMajorTickMarkInterval;
                minorGrid.interval = tempMinorGridInterval;
                minorTickMark.interval = tempMinorTickMarkInterval;
                labelStyle.interval = tempLabelInterval;
 
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Axis interval offset.
        /// </summary>
        [
        SRCategory("CategoryAttributeInterval"),
        Bindable(true),
        DefaultValue(0.0),
        SRDescription("DescriptionAttributeIntervalOffset6"),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute),
#endif
 RefreshPropertiesAttribute(RefreshProperties.All),
        TypeConverter(typeof(AxisIntervalValueConverter))
        ]
        public double IntervalOffset
        {
            get
            {
                return _intervalOffset;
            }
            set
            {
                // Axis interval properties must be set
                if (double.IsNaN(value))
                {
                    _intervalOffset = 0;
                }
                else
                {
                    _intervalOffset = value;
                }
 
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Axis interval type.
        /// </summary>
        [
        SRCategory("CategoryAttributeInterval"),
        Bindable(true),
        DefaultValue(DateTimeIntervalType.Auto),
        SRDescription("DescriptionAttributeIntervalType4"),
        RefreshPropertiesAttribute(RefreshProperties.All),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public DateTimeIntervalType IntervalType
        {
            get
            {
                return intervalType;
            }
            set
            {
                // Axis interval properties must be set
                if (value == DateTimeIntervalType.NotSet)
                {
                    intervalType = DateTimeIntervalType.Auto;
                }
                else
                {
                    intervalType = value;
                }
 
                // Reset initial values
                majorGrid.intervalType = tempGridIntervalType;
                majorTickMark.intervalType = tempTickMarkIntervalType;
                labelStyle.intervalType = tempLabelIntervalType;
 
                this.Invalidate();
            }
        }
 
        /// <summary>
        /// Axis interval offset type.
        /// </summary>
        [
        SRCategory("CategoryAttributeInterval"),
        Bindable(true),
        DefaultValue(DateTimeIntervalType.Auto),
        SRDescription("DescriptionAttributeIntervalOffsetType4"),
        RefreshPropertiesAttribute(RefreshProperties.All),
#if !Microsoft_CONTROL
 PersistenceMode(PersistenceMode.Attribute)
#endif
]
        public DateTimeIntervalType IntervalOffsetType
        {
            get
            {
                return intervalOffsetType;
            }
            set
            {
                // Axis interval properties must be set
                if (value == DateTimeIntervalType.NotSet)
                {
                    intervalOffsetType = DateTimeIntervalType.Auto;
                }
                else
                {
                    intervalOffsetType = value;
                }
 
                this.Invalidate();
            }
        }
 
        #endregion
 
        #region Axis painting methods
 
        /// <summary>
        /// Checks if Common.Chart axis title is drawn vertically.
        /// Note: From the drawing perspective stacked text orientation is not vertical.
        /// </summary>
        /// <returns>True if text is vertical.</returns>
        private bool IsTextVertical
        {
            get
            {
                TextOrientation currentTextOrientation = this.GetTextOrientation();
                return currentTextOrientation == TextOrientation.Rotated90 || currentTextOrientation == TextOrientation.Rotated270;
            }
        }
 
        /// <summary>
        /// Returns axis title text orientation. If set to Auto automatically determines the
        /// orientation based on the axis position.
        /// </summary>
        /// <returns>Current text orientation.</returns>
        private TextOrientation GetTextOrientation()
        {
            if (this.TextOrientation == TextOrientation.Auto)
            {
                if (this.AxisPosition == AxisPosition.Left)
                {
                    return TextOrientation.Rotated270;
                }
                else if (this.AxisPosition == AxisPosition.Right)
                {
                    return TextOrientation.Rotated90;
                }
                return TextOrientation.Horizontal;
            }
            return this.TextOrientation;
        }
 
        /// <summary>
        /// Paint Axis elements on the back of the 3D scene.
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics object</param>
        internal void PrePaint(ChartGraphics graph)
        {
            if (enabled != false)
            {
                // draw axis hot region
                DrawAxisLineHotRegion(graph, true);
 
                // Paint Major Tick Marks
                majorTickMark.Paint(graph, true);
 
                // Paint Minor Tick Marks
                minorTickMark.Paint(graph, true);
 
                // Draw axis line
                DrawAxisLine(graph, true);
 
                // Paint Labels
                labelStyle.Paint(graph, true);
            }
 
#if SUBAXES
			// Process all sub-axis
			if(!ChartArea.Area3DStyle.Enable3D && 
				!ChartArea.chartAreaIsCurcular)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.PrePaint( graph );
				}
			}
#endif // SUBAXES
        }
 
        /// <summary>
        /// Paint Axis
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics object</param>
        internal void Paint(ChartGraphics graph)
        {
            // Only Y axis is drawn in the circular Common.Chart area
            if (ChartArea != null && ChartArea.chartAreaIsCurcular)
            {
                // Y circular axes
                if (this.axisType == AxisName.Y && enabled != false)
                {
                    ICircularChartType chartType = ChartArea.GetCircularChartType();
                    if (chartType != null)
                    {
                        Matrix oldMatrix = graph.Transform;
                        float[] axesLocation = chartType.GetYAxisLocations(ChartArea);
                        bool drawLabels = true;
                        foreach (float curentSector in axesLocation)
                        {
                            // Set graphics rotation matrix
                            Matrix newMatrix = oldMatrix.Clone();
                            newMatrix.RotateAt(
                                curentSector,
                                graph.GetAbsolutePoint(ChartArea.circularCenter));
                            graph.Transform = newMatrix;
 
                            // draw axis hot region
                            DrawAxisLineHotRegion(graph, false);
 
                            // Paint Minor Tick Marks
                            minorTickMark.Paint(graph, false);
 
                            // Paint Major Tick Marks
                            majorTickMark.Paint(graph, false);
 
                            // Draw axis line
                            DrawAxisLine(graph, false);
 
                            // Only first Y axis has labels
                            if (drawLabels)
                            {
                                drawLabels = false;
 
                                // Save current font angle 
                                int currentAngle = labelStyle.Angle;
 
                                // Set labels text angle
                                if (labelStyle.Angle == 0)
                                {
                                    if (curentSector >= 45f && curentSector <= 180f)
                                    {
                                        labelStyle.angle = -90;
                                    }
                                    else if (curentSector > 180f && curentSector <= 315f)
                                    {
                                        labelStyle.angle = 90;
                                    }
                                }
 
                                // Draw labels 
                                labelStyle.Paint(graph, false);
 
                                // Restore font angle 
                                labelStyle.angle = currentAngle;
                            }
                        }
 
                        graph.Transform = oldMatrix;
                    }
                }
 
                // X circular axes
                if (this.axisType == AxisName.X && enabled != false)
                {
                    labelStyle.PaintCircular(graph);
                }
 
                DrawAxisTitle(graph);
 
                return;
            }
 
            // If axis is disabled draw only Title
            if (enabled != false)
            {
 
                // draw axis hot region
                DrawAxisLineHotRegion(graph, false);
 
                // Paint Minor Tick Marks
                minorTickMark.Paint(graph, false);
 
                // Paint Major Tick Marks
                majorTickMark.Paint(graph, false);
 
                // Draw axis line
                DrawAxisLine(graph, false);
 
                // Paint Labels
                labelStyle.Paint(graph, false);
 
#if Microsoft_CONTROL

                // Scroll bar is supoorted only in 2D charts
                if (ChartArea != null && ChartArea.Area3DStyle.Enable3D == false)
                {
                    // Draw axis scroll bar
                    ScrollBar.Paint(graph);
                }
#endif // Microsoft_CONTROL
 
            }
 
            // Draw axis title
            this.DrawAxisTitle(graph);
 
#if SUBAXES
			// Process all sub-axis
			if(ChartArea.IsSubAxesSupported)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.Paint( graph );
				}
			}
#endif // SUBAXES
 
            // Reset temp axis offset for side-by-side charts like column
            this.ResetTempAxisOffset();
        }
 
 
 
		/// <summary>
		/// Paint Axis element when segmented axis scale feature is used.
		/// </summary>
		/// <param name="graph">Reference to the Chart Graphics object</param>
		internal void PaintOnSegmentedScalePassOne( ChartGraphics graph )
		{
			// If axis is disabled draw only Title
			if( enabled != false )
			{
				// Paint Minor Tick Marks
				minorTickMark.Paint( graph, false );
 
				// Paint Major Tick Marks
				majorTickMark.Paint( graph, false );
            }
 
#if SUBAXES
			// Process all sub-axis
			if(ChartArea.IsSubAxesSupported)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.PaintOnSegmentedScalePassOne( graph );
				}
			}
#endif // SUBAXES
 
        }
 
		/// <summary>
		/// Paint Axis element when segmented axis scale feature is used.
		/// </summary>
		/// <param name="graph">Reference to the Chart Graphics object</param>
		internal void PaintOnSegmentedScalePassTwo( ChartGraphics graph )
		{
			// If axis is disabled draw only Title
			if( enabled != false )
			{
				// Draw axis line
				DrawAxisLine( graph, false );
 
				// Paint Labels
				labelStyle.Paint( graph, false);
			}
 
			// Draw axis title
			this.DrawAxisTitle( graph );
		
			// Reset temp axis offset for side-by-side charts like column
			this.ResetTempAxisOffset();
 
#if SUBAXES
			// Process all sub-axis
			if(ChartArea.IsSubAxesSupported)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.PaintOnSegmentedScalePassTwo( graph );
				}
			}
#endif // SUBAXES
 
        }
				
        /// <summary>
        /// Draw axis title
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics object</param>
        private void DrawAxisTitle(ChartGraphics graph)
        {
            if (!this.enabled)
                return;
 
            // Draw axis title
            if (this.Title.Length > 0)
            {
                Matrix oldTransform = null;
 
                // Draw title in 3D
                if (ChartArea.Area3DStyle.Enable3D && !ChartArea.chartAreaIsCurcular)
                {
                    DrawAxis3DTitle(graph);
                    return;
                }
 
                string axisTitle = this.Title;
 
                //******************************************************
                //** Check axis position
                //******************************************************
                float axisPosition = (float)this.GetAxisPosition();
                if (this.AxisPosition == AxisPosition.Bottom)
                {
                    if (!this.GetIsMarksNextToAxis())
                    {
                        axisPosition = ChartArea.PlotAreaPosition.Bottom;
                    }
                    axisPosition = ChartArea.PlotAreaPosition.Bottom - axisPosition;
                }
                else if (this.AxisPosition == AxisPosition.Top)
                {
                    if (!this.GetIsMarksNextToAxis())
                    {
                        axisPosition = ChartArea.PlotAreaPosition.Y;
                    }
                    axisPosition = axisPosition - ChartArea.PlotAreaPosition.Y;
                }
                else if (this.AxisPosition == AxisPosition.Right)
                {
                    if (!this.GetIsMarksNextToAxis())
                    {
                        axisPosition = ChartArea.PlotAreaPosition.Right;
                    }
                    axisPosition = ChartArea.PlotAreaPosition.Right - axisPosition;
                }
                else if (this.AxisPosition == AxisPosition.Left)
                {
                    if (!this.GetIsMarksNextToAxis())
                    {
                        axisPosition = ChartArea.PlotAreaPosition.X;
                    }
                    axisPosition = axisPosition - ChartArea.PlotAreaPosition.X;
                }
 
                //******************************************************
                //** Adjust axis elements size with axis position
                //******************************************************
                // Calculate total size of axis elements
                float axisSize = this.markSize + this.labelSize;
                axisSize -= axisPosition;
                if (axisSize < 0)
                {
                    axisSize = 0;
                }
                // Set title alignment
                using (StringFormat format = new StringFormat())
                {
                    format.Alignment = this.TitleAlignment;
                    format.Trimming = StringTrimming.EllipsisCharacter;
                    // VSTS #144398
                    // We need to have the StringFormatFlags set to FitBlackBox as othwerwise axis titles using Fonts like 
                    // "Algerian" or "Forte" are completly clipped (= not drawn) due to the fact that MeasureString returns 
                    // a bounding rectangle that is too small.
                    format.FormatFlags |= StringFormatFlags.FitBlackBox;
 
                    // Calculate title rectangle
                    _titlePosition = ChartArea.PlotAreaPosition.ToRectangleF();
                    float titleSizeWithoutSpacing = this.titleSize - elementSpacing;
                    if (this.AxisPosition == AxisPosition.Left)
                    {
                        _titlePosition.X = ChartArea.PlotAreaPosition.X - titleSizeWithoutSpacing - axisSize;
                        _titlePosition.Y = ChartArea.PlotAreaPosition.Y;
 
                        if (!this.IsTextVertical)
                        {
                            SizeF axisTitleSize = new SizeF(titleSizeWithoutSpacing, ChartArea.PlotAreaPosition.Height);
                            _titlePosition.Width = axisTitleSize.Width;
                            _titlePosition.Height = axisTitleSize.Height;
 
                            format.Alignment = StringAlignment.Center;
                            if (this.TitleAlignment == StringAlignment.Far)
                            {
                                format.LineAlignment = StringAlignment.Near;
                            }
                            else if (this.TitleAlignment == StringAlignment.Near)
                            {
                                format.LineAlignment = StringAlignment.Far;
                            }
                            else
                            {
                                format.LineAlignment = StringAlignment.Center;
                            }
                        }
                        else
                        {
                            SizeF axisTitleSize = graph.GetAbsoluteSize(new SizeF(titleSizeWithoutSpacing, ChartArea.PlotAreaPosition.Height));
                            axisTitleSize = graph.GetRelativeSize(new SizeF(axisTitleSize.Height, axisTitleSize.Width));
 
							_titlePosition.Width = axisTitleSize.Width;
							_titlePosition.Height = axisTitleSize.Height;
 
                            _titlePosition.Y += ChartArea.PlotAreaPosition.Height / 2f - _titlePosition.Height / 2f;
							_titlePosition.X += titleSizeWithoutSpacing / 2f - _titlePosition.Width / 2f;
 
                            // Set graphics rotation transformation
                            oldTransform = this.SetRotationTransformation(graph, _titlePosition);
 
                            // Set alignment
                            format.LineAlignment = StringAlignment.Center;
                        }
                    }
                    else if (this.AxisPosition == AxisPosition.Right)
                    {
                        _titlePosition.X = ChartArea.PlotAreaPosition.Right + axisSize;
                        _titlePosition.Y = ChartArea.PlotAreaPosition.Y;
 
                        if (!this.IsTextVertical)
                        {
                            SizeF axisTitleSize = new SizeF(titleSizeWithoutSpacing, ChartArea.PlotAreaPosition.Height);
                            _titlePosition.Width = axisTitleSize.Width;
                            _titlePosition.Height = axisTitleSize.Height;
 
                            format.Alignment = StringAlignment.Center;
                            if (this.TitleAlignment == StringAlignment.Far)
                            {
                                format.LineAlignment = StringAlignment.Near;
                            }
                            else if (this.TitleAlignment == StringAlignment.Near)
                            {
                                format.LineAlignment = StringAlignment.Far;
                            }
                            else
                            {
                                format.LineAlignment = StringAlignment.Center;
                            }
                        }
                        else
                        {
                            SizeF axisTitleSize = graph.GetAbsoluteSize(new SizeF(titleSizeWithoutSpacing, ChartArea.PlotAreaPosition.Height));
                            axisTitleSize = graph.GetRelativeSize(new SizeF(axisTitleSize.Height, axisTitleSize.Width));
 
							_titlePosition.Width = axisTitleSize.Width;
							_titlePosition.Height = axisTitleSize.Height;
							
                            _titlePosition.Y += ChartArea.PlotAreaPosition.Height / 2f - _titlePosition.Height / 2f;
							_titlePosition.X += titleSizeWithoutSpacing / 2f - _titlePosition.Width / 2f;
 
                            // Set graphics rotation transformation
                            oldTransform = this.SetRotationTransformation(graph, _titlePosition);
 
                            // Set alignment
                            format.LineAlignment = StringAlignment.Center;
                        }
                    }
                    else if (this.AxisPosition == AxisPosition.Top)
                    {
                        _titlePosition.Y = ChartArea.PlotAreaPosition.Y - titleSizeWithoutSpacing - axisSize;
                        _titlePosition.Height = titleSizeWithoutSpacing;
                        _titlePosition.X = ChartArea.PlotAreaPosition.X;
                        _titlePosition.Width = ChartArea.PlotAreaPosition.Width;
 
                        if (this.IsTextVertical)
                        {
                            // Set graphics rotation transformation
                            oldTransform = this.SetRotationTransformation(graph, _titlePosition);
                        }
 
                        // Set alignment
                        format.LineAlignment = StringAlignment.Center;
                    }
                    else if (this.AxisPosition == AxisPosition.Bottom)
                    {
                        _titlePosition.Y = ChartArea.PlotAreaPosition.Bottom + axisSize;
                        _titlePosition.Height = titleSizeWithoutSpacing;
                        _titlePosition.X = ChartArea.PlotAreaPosition.X;
                        _titlePosition.Width = ChartArea.PlotAreaPosition.Width;
 
                        if (this.IsTextVertical)
                        {
                            // Set graphics rotation transformation
                            oldTransform = this.SetRotationTransformation(graph, _titlePosition);
                        }
 
                        // Set alignment
                        format.LineAlignment = StringAlignment.Center;
                    }
 
#if DEBUG
                    // TESTING CODE: Shows labels rectangle position.
					//				RectangleF rr = graph.GetAbsoluteRectangle(_titlePosition);
					//				graph.DrawRectangle(Pens.Blue, rr.X, rr.Y, rr.Width, rr.Height);
#endif // DEBUG
 
                    // Draw title
                    using (Brush brush = new SolidBrush(this.TitleForeColor))
                    {
                        graph.DrawStringRel(
                            axisTitle.Replace("\\n", "\n"),
                            this.TitleFont,
                            brush,
                            _titlePosition,
                            format,
                            this.GetTextOrientation());
                    }
                }
 
                // Process selection regions
                if (this.Common.ProcessModeRegions)
                {
                    // NOTE: Solves Issue #4423
                    // Transform title position coordinates using curent Graphics matrix
                    RectangleF transformedTitlePosition = graph.GetAbsoluteRectangle(_titlePosition);
                    PointF[] rectPoints = new PointF[] { 
						new PointF(transformedTitlePosition.X, transformedTitlePosition.Y),
						new PointF(transformedTitlePosition.Right, transformedTitlePosition.Bottom) };
                    graph.Transform.TransformPoints(rectPoints);
                    transformedTitlePosition = new RectangleF(
                        rectPoints[0].X,
                        rectPoints[0].Y,
                        rectPoints[1].X - rectPoints[0].X,
                        rectPoints[1].Y - rectPoints[0].Y);
                    if (transformedTitlePosition.Width < 0)
                    {
                        transformedTitlePosition.Width = Math.Abs(transformedTitlePosition.Width);
                        transformedTitlePosition.X -= transformedTitlePosition.Width;
                    }
                    if (transformedTitlePosition.Height < 0)
                    {
                        transformedTitlePosition.Height = Math.Abs(transformedTitlePosition.Height);
                        transformedTitlePosition.Y -= transformedTitlePosition.Height;
                    }
 
                    // Add hot region 
                    this.Common.HotRegionsList.AddHotRegion(
                        transformedTitlePosition, this, ChartElementType.AxisTitle, false, false);
                }
 
                // Restore old transformation
                if (oldTransform != null)
                {
                    graph.Transform = oldTransform;
                }
            }
        }
 
        /// <summary>
        /// Helper method which sets 90 or -90 degrees transformation in the middle of the 
        /// specified rectangle. It is used to draw title text rotated 90 or 270 degrees.
        /// </summary>
        /// <param name="graph">Chart graphics to apply transformation for.</param>
        /// <param name="titlePosition">Title position.</param>
        /// <returns>Old graphics transformation matrix.</returns>
        private Matrix SetRotationTransformation(ChartGraphics graph, RectangleF titlePosition)
        {
            // Save old graphics transformation
            Matrix oldTransform = graph.Transform.Clone();
 
            // Rotate left tile 90 degrees at center
            PointF center = PointF.Empty;
            center.X = titlePosition.X + titlePosition.Width / 2F;
            center.Y = titlePosition.Y + titlePosition.Height / 2F;
 
            // Create and set new transformation matrix
            float angle = (this.GetTextOrientation() == TextOrientation.Rotated90) ? 90f : -90f;
            Matrix newMatrix = graph.Transform.Clone();
            newMatrix.RotateAt(angle, graph.GetAbsolutePoint(center));
            graph.Transform = newMatrix;
 
            return oldTransform;
        }
            
 
        /// <summary>
        /// Draws a radial line in circular Common.Chart area.
        /// </summary>
        /// <param name="obj">Object requesting the painting.</param>
        /// <param name="graph">Graphics path.</param>
        /// <param name="color">Line color.</param>
        /// <param name="width">Line width.</param>
        /// <param name="style">Line style.</param>
        /// <param name="position">X axis circular position.</param>
        internal void DrawRadialLine(
            object obj,
            ChartGraphics graph,
            Color color,
            int width,
            ChartDashStyle style,
            double position)
        {
            // Create circle position rectangle
            RectangleF rect = ChartArea.PlotAreaPosition.ToRectangleF();
            rect = graph.GetAbsoluteRectangle(rect);
 
            // Make sure the rectangle width equals rectangle height for the circle
            if (rect.Width != rect.Height)
            {
                if (rect.Width > rect.Height)
                {
                    rect.X += (rect.Width - rect.Height) / 2f;
                    rect.Width = rect.Height;
                }
                else
                {
                    rect.Y += (rect.Height - rect.Width) / 2f;
                    rect.Height = rect.Width;
                }
            }
 
            // Convert axis position to angle
            float angle = ChartArea.CircularPositionToAngle(position);
 
            // Set clipping region to the polygon
            Region oldRegion = null;
            if (ChartArea.CircularUsePolygons)
            {
                oldRegion = graph.Clip;
                graph.Clip = new Region(graph.GetPolygonCirclePath(rect, ChartArea.CircularSectorsNumber));
            }
 
            // Get center point
            PointF centerPoint = graph.GetAbsolutePoint(ChartArea.circularCenter);
 
            // Set graphics rotation matrix
            Matrix oldMatrix = graph.Transform;
            Matrix newMatrix = oldMatrix.Clone();
            newMatrix.RotateAt(
                angle,
                centerPoint);
            graph.Transform = newMatrix;
 
            // Draw Line
            PointF endPoint = new PointF(rect.X + rect.Width / 2f, rect.Y);
            graph.DrawLineAbs(color, width, style, centerPoint, endPoint);
 
            // Process selection regions
            if (this.Common.ProcessModeRegions)
            {
                using (GraphicsPath path = new GraphicsPath())
                {
                    path.AddLine(centerPoint, endPoint);
                    path.Transform(newMatrix);
                    try
                    {
                        using (Pen pen = new Pen(Color.Black, width + 2))
                        {
                            path.Widen(pen);
                            this.Common.HotRegionsList.AddHotRegion(path, false, ChartElementType.Gridlines, obj);
                        }
                    }
                    catch (OutOfMemoryException)
                    {
                        // GraphicsPath.Widen incorrectly throws OutOfMemoryException
                        // catching here and reacting by not widening
                    }
                    catch (ArgumentException)
                    {
                    }
                }
            }
 
            // Restore graphics
            graph.Transform = oldMatrix;
            newMatrix.Dispose();
 
            // Restore clip region
            if (ChartArea.CircularUsePolygons)
            {
                graph.Clip = oldRegion;
            }
 
        }
 
        /// <summary>
        /// Draws a circular line in circular Common.Chart area.
        /// </summary>
        /// <param name="obj">Object requesting the painting.</param>
        /// <param name="graph">Graphics path.</param>
        /// <param name="color">Line color.</param>
        /// <param name="width">Line width.</param>
        /// <param name="style">Line style.</param>
        /// <param name="position">Line position.</param>
        internal void DrawCircularLine(
            object obj,
            ChartGraphics graph,
            Color color,
            int width,
            ChartDashStyle style,
            float position
            )
        {
            // Create circle position rectangle
            RectangleF rect = ChartArea.PlotAreaPosition.ToRectangleF();
            rect = graph.GetAbsoluteRectangle(rect);
 
            // Make sure the rectangle width equals rectangle height for the circle
            if (rect.Width != rect.Height)
            {
                if (rect.Width > rect.Height)
                {
                    rect.X += (rect.Width - rect.Height) / 2f;
                    rect.Width = rect.Height;
                }
                else
                {
                    rect.Y += (rect.Height - rect.Width) / 2f;
                    rect.Height = rect.Width;
                }
            }
 
            // Inflate rectangle
            PointF absPoint = graph.GetAbsolutePoint(new PointF(position, position));
            float rectInflate = absPoint.Y - rect.Top;
            rect.Inflate(-rectInflate, -rectInflate);
 
            // Create circle pen
            Pen circlePen = new Pen(color, width);
            circlePen.DashStyle = graph.GetPenStyle(style);
 
            // Draw circle
            if (ChartArea.CircularUsePolygons)
            {
                // Draw eaqula sides polygon
                graph.DrawCircleAbs(circlePen, null, rect, ChartArea.CircularSectorsNumber, false);
            }
            else
            {
                graph.DrawEllipse(circlePen, rect);
            }
 
            // Process selection regions
            if (this.Common.ProcessModeRegions)
            {
                // Bounding rectangle must be more than 1 pixel by 1 pixel
                if (rect.Width >= 1f && rect.Height > 1)
                {
                    GraphicsPath path = null;
                    try
                    {
                        if (ChartArea.CircularUsePolygons)
                        {
                            path = graph.GetPolygonCirclePath(rect, ChartArea.CircularSectorsNumber);
                        }
                        else
                        {
                            path = new GraphicsPath();
                            path.AddEllipse(rect);
                        }
                        circlePen.Width += 2;
                        path.Widen(circlePen);
                        this.Common.HotRegionsList.AddHotRegion(path, false, ChartElementType.Gridlines, obj);
                    }
                    catch (OutOfMemoryException)
                    {
                        // GraphicsPath.Widen incorrectly throws OutOfMemoryException
                        // catching here and reacting by not widening
                    }
                    catch (ArgumentException)
                    {
                    }
                    finally
                    {
                        path.Dispose();
                    }
                }
            }
 
        }
 
        /// <summary>
        /// Draw axis title in 3D.
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics object</param>
        private void DrawAxis3DTitle(ChartGraphics graph)
        {
            // Do not draw title if axis is not enabled
            if (!this.enabled)
            {
                return;
            }
 
            string axisTitle = this.Title;
 
            // Draw axis title
            PointF rotationCenter = PointF.Empty;
            int angle = 0;
 
            // Set title alignment
            using (StringFormat format = new StringFormat())
            {
                format.Alignment = this.TitleAlignment;
                format.Trimming = StringTrimming.EllipsisCharacter;
                format.FormatFlags |= StringFormatFlags.LineLimit;
 
                // Measure title size for non-centered aligment
                SizeF realTitleSize = graph.MeasureString(axisTitle.Replace("\\n", "\n"), this.TitleFont, new SizeF(10000f, 10000f), format, this.GetTextOrientation());
                SizeF axisTitleSize = SizeF.Empty;
                if (format.Alignment != StringAlignment.Center)
                {
                    axisTitleSize = realTitleSize;
                    if (this.IsTextVertical)
                    {
                        // Switch height and width for vertical axis
                        float tempValue = axisTitleSize.Height;
                        axisTitleSize.Height = axisTitleSize.Width;
                        axisTitleSize.Width = tempValue;
                    }
 
                    // Get relative size
                    axisTitleSize = graph.GetRelativeSize(axisTitleSize);
 
                    // Change format aligment for the reversed mode
                    if (ChartArea.ReverseSeriesOrder)
                    {
                        if (format.Alignment == StringAlignment.Near)
                        {
                            format.Alignment = StringAlignment.Far;
                        }
                        else
                        {
                            format.Alignment = StringAlignment.Near;
                        }
                    }
                }
 
                // Set text rotation angle based on the text orientation
                if (this.GetTextOrientation() == TextOrientation.Rotated90)
                {
                    angle = 90;
                }
                else if (this.GetTextOrientation() == TextOrientation.Rotated270)
                {
                    angle = -90;
                }
 
                // Calculate title center point on the axis 
                if (this.AxisPosition == AxisPosition.Left)
                {
                    rotationCenter = new PointF(ChartArea.PlotAreaPosition.X, ChartArea.PlotAreaPosition.Y + ChartArea.PlotAreaPosition.Height / 2f);
                    if (format.Alignment == StringAlignment.Near)
                    {
                        rotationCenter.Y = ChartArea.PlotAreaPosition.Bottom - axisTitleSize.Height / 2f;
                    }
                    else if (format.Alignment == StringAlignment.Far)
                    {
                        rotationCenter.Y = ChartArea.PlotAreaPosition.Y + axisTitleSize.Height / 2f;
                    }
                }
                else if (this.AxisPosition == AxisPosition.Right)
                {
                    rotationCenter = new PointF(ChartArea.PlotAreaPosition.Right, ChartArea.PlotAreaPosition.Y + ChartArea.PlotAreaPosition.Height / 2f);
                    if (format.Alignment == StringAlignment.Near)
                    {
                        rotationCenter.Y = ChartArea.PlotAreaPosition.Bottom - axisTitleSize.Height / 2f;
                    }
                    else if (format.Alignment == StringAlignment.Far)
                    {
                        rotationCenter.Y = ChartArea.PlotAreaPosition.Y + axisTitleSize.Height / 2f;
                    }
                }
                else if (this.AxisPosition == AxisPosition.Top)
                {
                    rotationCenter = new PointF(ChartArea.PlotAreaPosition.X + ChartArea.PlotAreaPosition.Width / 2f, ChartArea.PlotAreaPosition.Y);
                    if (format.Alignment == StringAlignment.Near)
                    {
                        rotationCenter.X = ChartArea.PlotAreaPosition.X + axisTitleSize.Width / 2f;
                    }
                    else if (format.Alignment == StringAlignment.Far)
                    {
                        rotationCenter.X = ChartArea.PlotAreaPosition.Right - axisTitleSize.Width / 2f;
                    }
                }
                else if (this.AxisPosition == AxisPosition.Bottom)
                {
                    rotationCenter = new PointF(ChartArea.PlotAreaPosition.X + ChartArea.PlotAreaPosition.Width / 2f, ChartArea.PlotAreaPosition.Bottom);
                    if (format.Alignment == StringAlignment.Near)
                    {
                        rotationCenter.X = ChartArea.PlotAreaPosition.X + axisTitleSize.Width / 2f;
                    }
                    else if (format.Alignment == StringAlignment.Far)
                    {
                        rotationCenter.X = ChartArea.PlotAreaPosition.Right - axisTitleSize.Width / 2f;
                    }
                }
 
                // Transform center of title coordinates and calculate axis angle
                bool isOnEdge = false;
                float zPosition = this.GetMarksZPosition(out isOnEdge);
                Point3D[] rotationCenterPoints = null;
                float angleAxis = 0;
                if (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom)
                {
                    rotationCenterPoints = new Point3D[] { 
					new Point3D(rotationCenter.X, rotationCenter.Y, zPosition),
					new Point3D(rotationCenter.X - 20f, rotationCenter.Y, zPosition) };
 
                    // Transform coordinates of text rotation point
                    ChartArea.matrix3D.TransformPoints(rotationCenterPoints);
                    rotationCenter = rotationCenterPoints[0].PointF;
 
                    // Get absolute coordinates 
                    rotationCenterPoints[0].PointF = graph.GetAbsolutePoint(rotationCenterPoints[0].PointF);
                    rotationCenterPoints[1].PointF = graph.GetAbsolutePoint(rotationCenterPoints[1].PointF);
 
                    // Calculate X axis angle
                    angleAxis = (float)Math.Atan(
                        (rotationCenterPoints[1].Y - rotationCenterPoints[0].Y) /
                        (rotationCenterPoints[1].X - rotationCenterPoints[0].X));
                }
                else
                {
                    rotationCenterPoints = new Point3D[] { 
					new Point3D(rotationCenter.X, rotationCenter.Y, zPosition),
					new Point3D(rotationCenter.X, rotationCenter.Y - 20f, zPosition) };
 
                    // Transform coordinates of text rotation point
                    ChartArea.matrix3D.TransformPoints(rotationCenterPoints);
                    rotationCenter = rotationCenterPoints[0].PointF;
 
                    // Get absolute coordinates 
                    rotationCenterPoints[0].PointF = graph.GetAbsolutePoint(rotationCenterPoints[0].PointF);
                    rotationCenterPoints[1].PointF = graph.GetAbsolutePoint(rotationCenterPoints[1].PointF);
 
                    // Calculate Y axis angle
                    if (rotationCenterPoints[1].Y != rotationCenterPoints[0].Y)
                    {
                        angleAxis = -(float)Math.Atan(
                            (rotationCenterPoints[1].X - rotationCenterPoints[0].X) /
                            (rotationCenterPoints[1].Y - rotationCenterPoints[0].Y));
                    }
                }
                angle += (int)Math.Round(angleAxis * 180f / (float)Math.PI);
 
 
                // Calculate title center offset from the axis line
                float offset = this.labelSize + this.markSize + this.titleSize / 2f;
                float dX = 0f, dY = 0f;
 
 
                // Adjust center of title with labels, marker and title size
                if (this.AxisPosition == AxisPosition.Left)
                {
                    dX = (float)(offset * Math.Cos(angleAxis));
                    rotationCenter.X -= dX;
                }
                else if (this.AxisPosition == AxisPosition.Right)
                {
                    dX = (float)(offset * Math.Cos(angleAxis));
                    rotationCenter.X += dX;
                }
                else if (this.AxisPosition == AxisPosition.Top)
                {
                    dY = (float)(offset * Math.Cos(angleAxis));
                    dX = (float)(offset * Math.Sin(angleAxis));
                    rotationCenter.Y -= dY;
                    if (dY > 0)
                    {
                        rotationCenter.X += dX;
                    }
                    else
                    {
                        rotationCenter.X -= dX;
                    }
                }
                else if (this.AxisPosition == AxisPosition.Bottom)
                {
                    dY = (float)(offset * Math.Cos(angleAxis));
                    dX = (float)(offset * Math.Sin(angleAxis));
                    rotationCenter.Y += dY;
                    if (dY > 0)
                    {
                        rotationCenter.X -= dX;
                    }
                    else
                    {
                        rotationCenter.X += dX;
                    }
                }
 
 
                // Always align text in the center
                format.LineAlignment = StringAlignment.Center;
                format.Alignment = StringAlignment.Center;
                // SQL VSTS Fix #259954, Dev10: 591135 Windows 7 crashes on empty transformation.
                if (rotationCenter.IsEmpty || float.IsNaN(rotationCenter.X) || float.IsNaN(rotationCenter.Y))
                {
                    return;
                }
 
                // Draw 3D title
                using (Brush brush = new SolidBrush(this.TitleForeColor))
                {
                    graph.DrawStringRel(
                        axisTitle.Replace("\\n", "\n"),
                        this.TitleFont,
                        brush,
                        rotationCenter,
                        format,
                        angle,
                        this.GetTextOrientation());
                }
 
                // Add hot region
                if (Common.ProcessModeRegions)
                {
                    using (GraphicsPath hotPath = graph.GetTranformedTextRectPath(rotationCenter, realTitleSize, angle))
                    {
                        this.Common.HotRegionsList.AddHotRegion(hotPath, false, ChartElementType.AxisTitle, this);
                    }
                }
            }
 
        }
 
        /// <summary>
        /// Select Axis line
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics</param>
        /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
        internal void DrawAxisLine(ChartGraphics graph, bool backElements)
        {
            Axis opositeAxis;
            ArrowOrientation arrowOrientation = ArrowOrientation.Top;
            PointF first = Point.Empty;
            PointF second = Point.Empty;
 
            // Set the position of axis
            switch (AxisPosition)
            {
 
                case AxisPosition.Left:
 
                    first.X = (float)GetAxisPosition();
                    first.Y = PlotAreaPosition.Bottom;
                    second.X = (float)GetAxisPosition();
                    second.Y = PlotAreaPosition.Y;
                    if (isReversed)
                        arrowOrientation = ArrowOrientation.Bottom;
                    else
                        arrowOrientation = ArrowOrientation.Top;
 
                    break;
 
                case AxisPosition.Right:
 
                    first.X = (float)GetAxisPosition();
                    first.Y = PlotAreaPosition.Bottom;
                    second.X = (float)GetAxisPosition();
                    second.Y = PlotAreaPosition.Y;
                    if (isReversed)
                        arrowOrientation = ArrowOrientation.Bottom;
                    else
                        arrowOrientation = ArrowOrientation.Top;
 
                    break;
 
                case AxisPosition.Bottom:
 
                    first.X = PlotAreaPosition.X;
                    first.Y = (float)GetAxisPosition();
                    second.X = PlotAreaPosition.Right;
                    second.Y = (float)GetAxisPosition();
                    if (isReversed)
                        arrowOrientation = ArrowOrientation.Left;
                    else
                        arrowOrientation = ArrowOrientation.Right;
 
                    break;
 
                case AxisPosition.Top:
 
                    first.X = PlotAreaPosition.X;
                    first.Y = (float)GetAxisPosition();
                    second.X = PlotAreaPosition.Right;
                    second.Y = (float)GetAxisPosition();
                    if (isReversed)
                        arrowOrientation = ArrowOrientation.Left;
                    else
                        arrowOrientation = ArrowOrientation.Right;
 
                    break;
 
            }
 
            // Update axis line position for circular area
            if (ChartArea.chartAreaIsCurcular)
            {
                first.Y = PlotAreaPosition.Y + PlotAreaPosition.Height / 2f;
            }
 
            
            if (Common.ProcessModePaint)
            {
                if (!ChartArea.Area3DStyle.Enable3D || ChartArea.chartAreaIsCurcular)
                {
 
					// Start Svg/Flash Selection mode
					graph.StartHotRegion( this._url, _toolTip );
 
                    // Draw the line
                    graph.DrawLineRel(_lineColor, _lineWidth, _lineDashStyle, first, second);
 
					// End Svg/Flash Selection mode
					graph.EndHotRegion( );
 
                    // Opposite axis. Arrow uses this axis to find 
                    // a shift from Common.Chart area border. This shift 
                    // depend on Tick mark size.
                    switch (arrowOrientation)
                    {
                        case ArrowOrientation.Left:
                            opositeAxis = ChartArea.AxisX;
                            break;
                        case ArrowOrientation.Right:
                            opositeAxis = ChartArea.AxisX2;
                            break;
                        case ArrowOrientation.Top:
                            opositeAxis = ChartArea.AxisY2;
                            break;
                        case ArrowOrientation.Bottom:
                            opositeAxis = ChartArea.AxisY;
                            break;
                        default:
                            opositeAxis = ChartArea.AxisX;
                            break;
                    }
 
                    // Draw arrow
                    PointF arrowPosition;
                    if (isReversed)
                        arrowPosition = first;
                    else
                        arrowPosition = second;
 
                    // Draw Arrow
                    graph.DrawArrowRel(arrowPosition, arrowOrientation, _arrowStyle, _lineColor, _lineWidth, _lineDashStyle, opositeAxis.majorTickMark.Size, _lineWidth);
                }
                else
                {
                    Draw3DAxisLine(graph, first, second, (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom), backElements);
                }
            }
 
        }
 
 
        /// <summary>
        /// Draws the axis line hot region.
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="backElements">set to <c>true</c> if we draw back elements.</param>
        private void DrawAxisLineHotRegion(ChartGraphics graph, bool backElements)
        {
            if (Common.ProcessModeRegions)
            {
                //VSTS #229835: During the 3D rendering the axis is drawn twice: 
                //1. In PrePaint() both axis and backelements (labels) are drawn.
                //2. In Paint() the axis is redrawn without labels and as a result it creates a second hot region which covered the labels' hotregions. 
                //In order to avoid this we have to suppress the hotregion drawing in the Paint using the backElements flag (it's false during the Paint)
                //The circular charts and 2D charts are drawn only once in Paint() so we draw the hot regions.
                if (backElements || !ChartArea.Area3DStyle.Enable3D || ChartArea.chartAreaIsCurcular)
                {
                    DrawAxisLineHotRegion(graph);
                }
            }
 
        }
 
        /// <summary>
        /// Adds the axis hot region
        /// </summary>
        /// <param name="graph">The chart graphics instance.</param>
        private void DrawAxisLineHotRegion(ChartGraphics graph)
        {
            using (GraphicsPath path = new GraphicsPath())
            {
                // Find the topLeft(first) and bottomRight(second) points of the hotregion rectangle
                PointF first = PointF.Empty;
                PointF second = PointF.Empty;
                float axisPosition = (float)GetAxisPosition();
 
                switch (this.AxisPosition)
                {
                    case AxisPosition.Left:
                        first.X = axisPosition - (labelSize + markSize);
                        first.Y = PlotAreaPosition.Y;
                        second.X = axisPosition;
                        second.Y = PlotAreaPosition.Bottom;
                        break;
 
                    case AxisPosition.Right:
                        first.X = axisPosition;
                        first.Y = PlotAreaPosition.Y;
                        second.X = axisPosition + labelSize + markSize;
                        second.Y = PlotAreaPosition.Bottom;
                        break;
 
                    case AxisPosition.Bottom:
                        first.X = PlotAreaPosition.X;
                        first.Y = axisPosition;
                        second.X = PlotAreaPosition.Right;
                        second.Y = axisPosition + labelSize + markSize;
                        break;
 
                    case AxisPosition.Top:
                        first.X = PlotAreaPosition.X;
                        first.Y = axisPosition - (labelSize + markSize);
                        second.X = PlotAreaPosition.Right;
                        second.Y = axisPosition;
                        break;
                }
 
                // Update axis line position for circular area
                if (ChartArea.chartAreaIsCurcular)
                {
                    second.Y = PlotAreaPosition.Y + PlotAreaPosition.Height / 2f;
                }
                
                // Create rectangle and inflate it
                RectangleF rect = new RectangleF(first.X, first.Y, second.X - first.X, second.Y - first.Y);
                SizeF size = graph.GetRelativeSize(new SizeF(3, 3));
 
                if (AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom)
                {
                    rect.Inflate(2, size.Height);
                }
                else
                {
                    rect.Inflate(size.Width, 2);
                }
 
                // Get the rectangle points
                PointF[] points = new PointF[] {
                    new PointF(rect.Left, rect.Top),
                    new PointF(rect.Right, rect.Top), 
                    new PointF(rect.Right, rect.Bottom), 
                    new PointF(rect.Left, rect.Bottom)};
 
                // If we are dealing with the 3D - transform the rectangle
                if (ChartArea.Area3DStyle.Enable3D && !ChartArea.chartAreaIsCurcular)
                {
                    Boolean axisOnEdge = false;
                    float zPositon = GetMarksZPosition(out axisOnEdge);
 
                    // Convert points to 3D
                    Point3D[] points3D = new Point3D[points.Length];
                    for (int i = 0; i < points.Length; i++)
                    {
                        points3D[i] = new Point3D(points[i].X, points[i].Y, zPositon);
                    }
 
                    // Transform
                    ChartArea.matrix3D.TransformPoints(points3D);
 
                    // Convert to 2D
                    for (int i = 0; i < points3D.Length; i++)
                    {
                        points[i] = points3D[i].PointF;
                    }
                }
 
                // Transform points to absolute cooordinates
                for (int i = 0; i < points.Length; i++)
                {
                    points[i] = graph.GetAbsolutePoint(points[i]);
                }
 
                // Add the points to the path
                path.AddPolygon(points);
 
 
#if Microsoft_CONTROL
				Common.HotRegionsList.AddHotRegion( 
					graph, 
					path, 
					false, 
					this._toolTip,
					string.Empty,
					string.Empty,
					string.Empty,
					this,
					ChartElementType.Axis);
#else
                Common.HotRegionsList.AddHotRegion(
                    graph,
                    path,
                    false,
                    this._toolTip,
                    this._url,
                    this._mapAreaAttributes,
                    this.PostBackValue,
                    this,
                    ChartElementType.Axis);
#endif 
            
            }
        }
 
 
        /// <summary>
        /// Draws axis line in 3D space.
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics object.</param>
        /// <param name="point1">First line point.</param>
        /// <param name="point2">Second line point.</param>
        /// <param name="horizontal">Indicates that tick mark line is horizontal</param>
        /// <param name="backElements">Only back elements of axis should be drawn.</param>
        private void Draw3DAxisLine(
            ChartGraphics graph,
            PointF point1,
            PointF point2,
            bool horizontal,
            bool backElements
            )
        {
            // Check if axis is positioned on the plot area adge
            bool onEdge = this.IsAxisOnAreaEdge;
 
            // Check if axis tick marks are drawn inside plotting area
            bool tickMarksOnEdge = onEdge;
            if (tickMarksOnEdge &&
                this.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis ||
                this.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea ||
                this.MinorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis ||
                this.MinorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
            {
                tickMarksOnEdge = false;
            }
 
            // Make sure first point of axis coordinates has smaller values
            if ((horizontal && point1.X > point2.X) ||
                (!horizontal && point1.Y > point2.Y))
            {
                PointF tempPoint = new PointF(point1.X, point1.Y);
                point1.X = point2.X;
                point1.Y = point2.Y;
                point2 = tempPoint;
            }
 
            // Check if the front/back wall is on the top drawing layer
            float zPositon = ChartArea.IsMainSceneWallOnFront() ? ChartArea.areaSceneDepth : 0f;
            SurfaceNames surfName = ChartArea.IsMainSceneWallOnFront() ? SurfaceNames.Front : SurfaceNames.Back;
            if (ChartArea.ShouldDrawOnSurface(SurfaceNames.Back, backElements, tickMarksOnEdge))
            {
 
				// Start Svg Selection mode
				graph.StartHotRegion( this._url, _toolTip );
 
                // Draw axis line on the back/front wall
                graph.Draw3DLine(
                    ChartArea.matrix3D,
                    _lineColor, _lineWidth, _lineDashStyle,
                    new Point3D(point1.X, point1.Y, zPositon),
                    new Point3D(point2.X, point2.Y, zPositon),
                    Common,
                    this,
                    ChartElementType.Nothing
                    );
 
				// End Svg Selection mode
				graph.EndHotRegion();
 
            }
 
            // Check if the back wall is on the top drawing layer
            zPositon = ChartArea.IsMainSceneWallOnFront() ? 0f : ChartArea.areaSceneDepth;
            surfName = ChartArea.IsMainSceneWallOnFront() ? SurfaceNames.Back : SurfaceNames.Front;
            if (ChartArea.ShouldDrawOnSurface(surfName, backElements, tickMarksOnEdge))
            {
                // Draw axis line on the front wall
                if (!onEdge ||
                    (this.AxisPosition == AxisPosition.Bottom && ChartArea.IsBottomSceneWallVisible()) ||
                    (this.AxisPosition == AxisPosition.Left && ChartArea.IsSideSceneWallOnLeft()) ||
                    (this.AxisPosition == AxisPosition.Right && !ChartArea.IsSideSceneWallOnLeft()))
                {
 
					// Start Svg Selection mode
					graph.StartHotRegion( this._url, _toolTip );
 
                    graph.Draw3DLine(
                        ChartArea.matrix3D,
                        _lineColor, _lineWidth, _lineDashStyle,
                        new Point3D(point1.X, point1.Y, zPositon),
                        new Point3D(point2.X, point2.Y, zPositon),
                        Common,
                        this,
                        ChartElementType.Nothing
                        );
 
					// End Svg Selection mode
					graph.EndHotRegion();
 
                }
            }
 
            // Check if the left/top wall is on the top drawing layer
            SurfaceNames surfaceName = (this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? SurfaceNames.Top : SurfaceNames.Left;
            if (ChartArea.ShouldDrawOnSurface(surfaceName, backElements, tickMarksOnEdge))
            {
                // Draw axis line on the left/top side walls
                if (!onEdge ||
                    (this.AxisPosition == AxisPosition.Bottom && (ChartArea.IsBottomSceneWallVisible() || ChartArea.IsSideSceneWallOnLeft())) ||
                    (this.AxisPosition == AxisPosition.Left && ChartArea.IsSideSceneWallOnLeft()) ||
                    (this.AxisPosition == AxisPosition.Right && !ChartArea.IsSideSceneWallOnLeft()) ||
                    (this.AxisPosition == AxisPosition.Top && ChartArea.IsSideSceneWallOnLeft()))
                {
 
					// Start Svg Selection mode
					graph.StartHotRegion( this._url, _toolTip );
 
                    graph.Draw3DLine(
                        ChartArea.matrix3D,
                        _lineColor, _lineWidth, _lineDashStyle,
                        new Point3D(point1.X, point1.Y, ChartArea.areaSceneDepth),
                        new Point3D(point1.X, point1.Y, 0f),
                        Common,
                        this,
                        ChartElementType.Nothing
                    );
 
					// End Svg Selection mode
					graph.EndHotRegion( );
 
                }
            }
 
            // Check if the right/bottom wall is on the top drawing layer
            surfaceName = (this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? SurfaceNames.Bottom : SurfaceNames.Right;
            if (ChartArea.ShouldDrawOnSurface(surfaceName, backElements, tickMarksOnEdge))
            {
                // Draw axis line on the bottom/right side walls
                if (!onEdge ||
                    (this.AxisPosition == AxisPosition.Bottom && (ChartArea.IsBottomSceneWallVisible() || !ChartArea.IsSideSceneWallOnLeft())) ||
                    (this.AxisPosition == AxisPosition.Left && (ChartArea.IsSideSceneWallOnLeft() || ChartArea.IsBottomSceneWallVisible())) ||
                    (this.AxisPosition == AxisPosition.Right && (!ChartArea.IsSideSceneWallOnLeft() || ChartArea.IsBottomSceneWallVisible())) ||
                    (this.AxisPosition == AxisPosition.Top && !ChartArea.IsSideSceneWallOnLeft())
                    )
                {
 
					// Start Svg Selection mode
					graph.StartHotRegion( this._url, _toolTip );
 
                    graph.Draw3DLine(
                        ChartArea.matrix3D,
                        _lineColor, _lineWidth, _lineDashStyle,
                        new Point3D(point2.X, point2.Y, ChartArea.areaSceneDepth),
                        new Point3D(point2.X, point2.Y, 0f),
                        Common,
                        this,
                        ChartElementType.Nothing
                        );
 
					// End Svg Selection mode
					graph.EndHotRegion();
 
                }
            }
 
        }
 
        /// <summary>
        /// Gets Z position of axis tick marks and labels.
        /// </summary>
        /// <param name="axisOnEdge">Returns true if axis is on the edge.</param>
        /// <returns>Marks Z position.</returns>
        internal float GetMarksZPosition(out bool axisOnEdge)
        {
            axisOnEdge = this.IsAxisOnAreaEdge;
            if (!this.GetIsMarksNextToAxis())
            {
                // Marks are forced to be on the area edge
                axisOnEdge = true;
            }
            float wallZPosition = 0f;
            if (this.AxisPosition == AxisPosition.Bottom && (ChartArea.IsBottomSceneWallVisible() || !axisOnEdge))
            {
                wallZPosition = ChartArea.areaSceneDepth;
            }
            if (this.AxisPosition == AxisPosition.Left && (ChartArea.IsSideSceneWallOnLeft() || !axisOnEdge))
            {
                wallZPosition = ChartArea.areaSceneDepth;
            }
            if (this.AxisPosition == AxisPosition.Right && (!ChartArea.IsSideSceneWallOnLeft() || !axisOnEdge))
            {
                wallZPosition = ChartArea.areaSceneDepth;
            }
            if (this.AxisPosition == AxisPosition.Top && !axisOnEdge)
            {
                wallZPosition = ChartArea.areaSceneDepth;
            }
 
            // Check if front wall is shown
            if (ChartArea.IsMainSceneWallOnFront())
            {
                // Switch Z position of tick mark
                wallZPosition = (wallZPosition == 0f) ? ChartArea.areaSceneDepth : 0f;
            }
 
            return wallZPosition;
        }
 
        /// <summary>
        /// Paint Axis Grid lines
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics object</param>
        internal void PaintGrids(ChartGraphics graph)
        {
            object obj;
 
            PaintGrids(graph, out obj);
 
        }
 
        /// <summary>
        /// Paint Axis Grid lines or 
        /// hit test function for grid lines
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics object</param>
        /// <param name="obj">Returns selected grid object</param>
        internal void PaintGrids(ChartGraphics graph, out object obj)
        {
            obj = null;
 
#if SUBAXES
			// Paint grids of sub-axis
			if(!ChartArea.Area3DStyle.Enable3D && 
				!ChartArea.chartAreaIsCurcular)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.PaintGrids( graph, out obj);
				}
			}
#endif // SUBAXES
 
            // Axis is disabled
            if (enabled == false)
                return;
 
            // Paint Minor grid lines
            minorGrid.Paint(graph);
 
            // Paint Major grid lines
            majorGrid.Paint(graph);
        }
 
        /// <summary>
        /// Paint Axis Strip lines
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics object</param>
        /// <param name="drawLinesOnly">Indicates if Lines or Stripes should be drawn.</param>
        internal void PaintStrips(ChartGraphics graph, bool drawLinesOnly)
        {
            object obj;
            PaintStrips(graph, false, 0, 0, out obj, drawLinesOnly);
        }
 
        /// <summary>
        /// Paint Axis Strip lines or 
        /// hit test function for Strip lines
        /// </summary>
        /// <param name="graph">Reference to the Chart Graphics object</param>
        /// <param name="selectionMode">The selection mode is active</param>
        /// <param name="x">X coordinate</param>
        /// <param name="y">Y coordinate</param>
        /// <param name="obj">Returns selected grid object</param>
        /// <param name="drawLinesOnly">Indicates if Lines or Stripes should be drawn.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "y"),
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "x"), 
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "selectionMode")]
        internal void PaintStrips(ChartGraphics graph, bool selectionMode, int x, int y, out object obj, bool drawLinesOnly)
        {
            obj = null;
 
#if SUBAXES
			// Paint strips of sub-axis
			if(ChartArea.IsSubAxesSupported)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.PaintStrips( graph, selectionMode, x, y, out obj, drawLinesOnly);
				}
			}
#endif // SUBAXES
 
            // Axis is disabled
            if (enabled == false)
                return;
 
            // Add axis isInterlaced strip lines into the collection
            bool interlacedStripAdded = AddInterlacedStrip();
 
            // Draw axis strips and lines
            foreach (StripLine strip in this.StripLines)
            {
                strip.Paint(graph, this.Common, drawLinesOnly);
            }
 
            // Remove axis isInterlaced strip line from the collection after drawing
            if (interlacedStripAdded)
            {
                // Remove isInterlaced strips which always is the first strip line
                this.StripLines.RemoveAt(0);
            }
 
        }
 
        /// <summary>
        /// Helper function which adds temp. strip lines into the collection
        /// to display isInterlaced lines in axis.
        /// </summary>
        private bool AddInterlacedStrip()
        {
            bool addStrip = false;
            if (this.IsInterlaced)
            {
                StripLine stripLine = new StripLine();
                stripLine.interlaced = true;
                // VSTS fix of 164115 IsInterlaced StripLines with no border are rendered with black border, regression of VSTS 136763
                stripLine.BorderColor = Color.Empty;
 
                // Get interval from grid lines, tick marks or labels
                if (this.MajorGrid.Enabled && this.MajorGrid.GetInterval() != 0.0)
                {
                    addStrip = true;
                    stripLine.Interval = this.MajorGrid.GetInterval() * 2.0;
                    stripLine.IntervalType = this.MajorGrid.GetIntervalType();
                    stripLine.IntervalOffset = this.MajorGrid.GetIntervalOffset();
                    stripLine.IntervalOffsetType = this.MajorGrid.GetIntervalOffsetType();
                    stripLine.StripWidth = this.MajorGrid.GetInterval();
                    stripLine.StripWidthType = this.MajorGrid.GetIntervalType();
                }
                else if (this.MajorTickMark.Enabled && this.MajorTickMark.GetInterval() != 0.0)
                {
                    addStrip = true;
                    stripLine.Interval = this.MajorTickMark.GetInterval() * 2.0;
                    stripLine.IntervalType = this.MajorTickMark.GetIntervalType();
                    stripLine.IntervalOffset = this.MajorTickMark.GetIntervalOffset();
                    stripLine.IntervalOffsetType = this.MajorTickMark.GetIntervalOffsetType();
                    stripLine.StripWidth = this.MajorTickMark.GetInterval();
                    stripLine.StripWidthType = this.MajorTickMark.GetIntervalType();
                }
                else if (this.LabelStyle.Enabled && this.LabelStyle.GetInterval() != 0.0)
                {
                    addStrip = true;
                    stripLine.Interval = this.LabelStyle.GetInterval() * 2.0;
                    stripLine.IntervalType = this.LabelStyle.GetIntervalType();
                    stripLine.IntervalOffset = this.LabelStyle.GetIntervalOffset();
                    stripLine.IntervalOffsetType = this.LabelStyle.GetIntervalOffsetType();
                    stripLine.StripWidth = this.LabelStyle.GetInterval();
                    stripLine.StripWidthType = this.LabelStyle.GetIntervalType();
                }
 
                // Insert item into the strips collection
                if (addStrip)
                {
                    // Define stip color
                    if (this.InterlacedColor != Color.Empty)
                    {
                        stripLine.BackColor = this.InterlacedColor;
                    }
                    else
                    {
                        // If isInterlaced strips color is not set - use darker color of the area
                        if (ChartArea.BackColor == Color.Empty)
                        {
                            stripLine.BackColor = (ChartArea.Area3DStyle.Enable3D) ? Color.DarkGray : Color.LightGray;
                        }
                        else if (ChartArea.BackColor == Color.Transparent)
                        {
                            if (Common.Chart.BackColor != Color.Transparent && Common.Chart.BackColor != Color.Black)
                            {
                                stripLine.BackColor = ChartGraphics.GetGradientColor(Common.Chart.BackColor, Color.Black, 0.2);
                            }
                            else
                            {
                                stripLine.BackColor = Color.LightGray;
                            }
                        }
                        else
                        {
                            stripLine.BackColor = ChartGraphics.GetGradientColor(ChartArea.BackColor, Color.Black, 0.2);
                        }
                    }
 
                    // Insert strip
                    this.StripLines.Insert(0, stripLine);
                }
            }
 
            return addStrip;
        }
 
        #endregion
 
        #region Axis parameters recalculation and resizing methods
 
        /// <summary>
        /// This method will calculate the maximum and minimum values 
        /// using interval on the X axis automatically. It will make a gap between 
        /// data points and border of the Common.Chart area.
        /// Note that this method can only be called for primary or secondary X axes.
        /// </summary>
        public void RoundAxisValues()
        {
            this.roundedXValues = true;
        }
 
        /// <summary>
        /// RecalculateAxesScale axis.
        /// </summary>
        /// <param name="position">Plotting area position.</param>
        internal void ReCalc(ElementPosition position)
        {
            PlotAreaPosition = position;
 
#if SUBAXES

			// Recalculate all sub-axis
			foreach(SubAxis subAxis in this.SubAxes)
			{
				subAxis.ReCalc( position );
			}
#endif // SUBAXES
        }
 
        /// <summary>
        /// This method store Axis values as minimum, maximum, 
        /// crossing, etc. Axis auto algorithm changes these 
        /// values and they have to be set to default values 
        /// after painting.
        /// </summary>
        internal void StoreAxisValues()
        {
            tempLabels = new CustomLabelsCollection(this);
            foreach (CustomLabel label in CustomLabels)
            {
                tempLabels.Add(label.Clone());
            }
 
            paintMode = true;
 
            // This field synchronies the Storing and 
            // resetting of temporary values
            if (_storeValuesEnabled)
            {
 
                tempMaximum = maximum;
                tempMinimum = minimum;
                tempCrossing = crossing;
                tempAutoMinimum = _autoMinimum;
                tempAutoMaximum = _autoMaximum;
 
                tempMajorGridInterval = majorGrid.interval;
                tempMajorTickMarkInterval = majorTickMark.interval;
 
                tempMinorGridInterval = minorGrid.interval;
                tempMinorTickMarkInterval = minorTickMark.interval;
 
 
                tempGridIntervalType = majorGrid.intervalType;
                tempTickMarkIntervalType = majorTickMark.intervalType;
 
 
                tempLabelInterval = labelStyle.interval;
                tempLabelIntervalType = labelStyle.intervalType;
 
                // Remember original ScaleView Position
                this._originalViewPosition = this.ScaleView.Position;
 
                // This field synchronies the Storing and 
                // resetting of temporary values
                _storeValuesEnabled = false;
            }
 
#if SUBAXES

			// Store values of all sub-axis
			if(ChartArea.IsSubAxesSupported)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.StoreAxisValues( );
				}
			}
#endif // SUBAXES
 
        }
 
 
        /// <summary>
        /// This method reset Axis values as minimum, maximum, 
        /// crossing, etc. Axis auto algorithm changes these 
        /// values and they have to be set to default values 
        /// after painting.
        /// </summary>
        internal void ResetAxisValues()
        {
            // Paint mode is finished
            paintMode = false;
 
#if Microsoft_CONTROL
			if(Common.Chart == null)
			{
#if SUBAXES
				else if(this is SubAxis)
				{
					if( ((SubAxis)this).parentAxis != null)
					{
						this.Common = ((SubAxis)this).parentAxis.Common;
						Common.Chart = ((SubAxis)this).parentAxis.Common.Chart;
					}
				}
#endif // SUBAXES
            }
			if(Common.Chart != null && Common.Chart.Site != null && Common.Chart.Site.DesignMode)
			{
				ResetAutoValues();
			}
#else
            ResetAutoValues();
#endif
 
            // Reset back original custom labels
            if (tempLabels != null)
            {
                CustomLabels.Clear();
                foreach (CustomLabel label in tempLabels)
                {
                    CustomLabels.Add(label.Clone());
                }
 
                tempLabels = null;
            }
 
#if SUBAXES

			// Reset values of all sub-axis
			if(ChartArea.IsSubAxesSupported)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.ResetAxisValues( );
				}
			}
#endif // SUBAXES
        }
 
 
        /// <summary>
        /// Reset auto calculated axis values
        /// </summary>
        internal void ResetAutoValues()
        {
            refreshMinMaxFromData = true;
            maximum = tempMaximum;
            minimum = tempMinimum;
            crossing = tempCrossing;
            _autoMinimum = tempAutoMinimum;
            _autoMaximum = tempAutoMaximum;
 
            majorGrid.interval = tempMajorGridInterval;
            majorTickMark.interval = tempMajorTickMarkInterval;
 
            minorGrid.interval = tempMinorGridInterval;
            minorTickMark.interval = tempMinorTickMarkInterval;
 
 
            labelStyle.interval = tempLabelInterval;
            majorGrid.intervalType = tempGridIntervalType;
            majorTickMark.intervalType = tempTickMarkIntervalType;
            labelStyle.intervalType = tempLabelIntervalType;
 
            // Restore original ScaleView Position
            if (Common.Chart != null)
            {
                if (!Common.Chart.serializing)
                {
                    this.ScaleView.Position = this._originalViewPosition;
                }
            }
 
            // This field synchronies the Storing and 
            // resetting of temporary values
            _storeValuesEnabled = true;
 
#if SUBAXES

			// Reset auto values of all sub-axis
			if(ChartArea.IsSubAxesSupported)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.ResetAutoValues( );
				}
			}
#endif // SUBAXES
 
        }
 
        /// <summary>
        /// Calculate size of the axis elements like title, labels and marks.
        /// </summary>
        /// <param name="chartGraph">Chart graphics object.</param>
        /// <param name="chartAreaPosition">The Chart area position.</param>
        /// <param name="plotArea">Plotting area size.</param>
        /// <param name="axesNumber">Number of axis of the same orientation.</param>
        /// <param name="autoPlotPosition">Indicates that inner plot position is automatic.</param>
        virtual internal void Resize(
            ChartGraphics chartGraph,
            ElementPosition chartAreaPosition,
            RectangleF plotArea,
            float axesNumber,
            bool autoPlotPosition)
        {
#if SUBAXES
			// Resize all sub-axis
			if(ChartArea.IsSubAxesSupported)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.Resize(chartGraph, chartAreaPosition, plotArea, axesNumber, autoPlotPosition);
				}
			}
#endif // SUBAXES
 
 
#if Microsoft_CONTROL
            // Disable Common.Chart invalidation
            bool oldDisableInvalidates = Common.Chart.disableInvalidates;
			Common.Chart.disableInvalidates = true;
#endif //Microsoft_CONTROL
 
            // Set Common.Chart area position
            PlotAreaPosition = chartAreaPosition;
 
            // Initialize plot area size
            PlotAreaPosition.FromRectangleF(plotArea);
 
            //******************************************************
            //** Calculate axis title size
            //******************************************************
            this.titleSize = 0F;
            if (this.Title.Length > 0)
            {
                // Measure axis title
                SizeF titleStringSize = chartGraph.MeasureStringRel(this.Title.Replace("\\n", "\n"), this.TitleFont, new SizeF(10000f, 10000f), StringFormat.GenericTypographic, this.GetTextOrientation());
 
                // Switch Width & Heigth for vertical axes
                // If axis is horizontal
                float maxTitlesize = 0;
                if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                {
                    maxTitlesize = (plotArea.Height / 100F) * (Axis.maxAxisTitleSize / axesNumber);
                    if (this.IsTextVertical)
                    {
                        this.titleSize = Math.Min(titleStringSize.Width, maxTitlesize);
                    }
                    else
                    {
                        this.titleSize = Math.Min(titleStringSize.Height, maxTitlesize);
                    }
                }
                // If axis is vertical
                else
                {
					titleStringSize = chartGraph.GetAbsoluteSize(titleStringSize);
					titleStringSize = chartGraph.GetRelativeSize(new SizeF(titleStringSize.Height, titleStringSize.Width));
					maxTitlesize = (plotArea.Width / 100F) * (Axis.maxAxisTitleSize / axesNumber);
                    if (this.IsTextVertical)
                    {
						this.titleSize = Math.Min(titleStringSize.Width, maxTitlesize);
                    }
                    else
                    {
                        this.titleSize = Math.Min(titleStringSize.Height, maxTitlesize);
                    }
                }
            }
            if (this.titleSize > 0)
            {
                this.titleSize += elementSpacing;
            }
 
            //*********************************************************
            //** Get arrow size of the opposite axis
            //*********************************************************
            float arrowSize = 0F;
            SizeF arrowSizePrimary = SizeF.Empty;
            SizeF arrowSizeSecondary = SizeF.Empty;
            ArrowOrientation arrowOrientation = ArrowOrientation.Bottom;
            if (this.axisType == AxisName.X || this.axisType == AxisName.X2)
            {
                if (ChartArea.AxisY.ArrowStyle != AxisArrowStyle.None)
                {
                    arrowSizePrimary = ChartArea.AxisY.GetArrowSize(out arrowOrientation);
                    if (!IsArrowInAxis(arrowOrientation, this.AxisPosition))
                    {
                        arrowSizePrimary = SizeF.Empty;
                    }
                }
 
                if (ChartArea.AxisY2.ArrowStyle != AxisArrowStyle.None)
                {
                    arrowSizeSecondary = ChartArea.AxisY2.GetArrowSize(out arrowOrientation);
                    if (!IsArrowInAxis(arrowOrientation, this.AxisPosition))
                    {
                        arrowSizeSecondary = SizeF.Empty;
                    }
                }
            }
            else
            {
                if (ChartArea.AxisX.ArrowStyle != AxisArrowStyle.None)
                {
                    arrowSizePrimary = ChartArea.AxisX.GetArrowSize(out arrowOrientation);
                    if (!IsArrowInAxis(arrowOrientation, this.AxisPosition))
                    {
                        arrowSizePrimary = SizeF.Empty;
                    }
                }
 
                if (ChartArea.AxisX2.ArrowStyle != AxisArrowStyle.None)
                {
                    arrowSizeSecondary = ChartArea.AxisX2.GetArrowSize(out arrowOrientation);
                    if (!IsArrowInAxis(arrowOrientation, this.AxisPosition))
                    {
                        arrowSizeSecondary = SizeF.Empty;
                    }
                }
            }
 
            // If axis is horizontal
            if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
            {
                arrowSize = Math.Max(arrowSizePrimary.Height, arrowSizeSecondary.Height);
            }
            // If axis is vertical
            else
            {
                arrowSize = Math.Max(arrowSizePrimary.Width, arrowSizeSecondary.Width);
            }
 
            //*********************************************************
            //** Calculate axis tick marks, axis thickness, arrow size
            //** and scroll bar size
            //*********************************************************
            this.markSize = 0F;
 
            // Get major and minor tick marks sizes
            float majorTickSize = 0;
            if (this.MajorTickMark.Enabled && this.MajorTickMark.TickMarkStyle != TickMarkStyle.None)
            {
                if (this.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
                {
                    majorTickSize = 0F;
                }
                else if (this.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis)
                {
                    majorTickSize = this.MajorTickMark.Size / 2F;
                }
                else if (this.MajorTickMark.TickMarkStyle == TickMarkStyle.OutsideArea)
                {
                    majorTickSize = this.MajorTickMark.Size;
                }
            }
 
            float minorTickSize = 0;
            if (this.MinorTickMark.Enabled && this.MinorTickMark.TickMarkStyle != TickMarkStyle.None && this.MinorTickMark.GetInterval() != 0)
            {
                if (this.MinorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
                {
                    minorTickSize = 0F;
                }
                else if (this.MinorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis)
                {
                    minorTickSize = this.MinorTickMark.Size / 2F;
                }
                else if (this.MinorTickMark.TickMarkStyle == TickMarkStyle.OutsideArea)
                {
                    minorTickSize = this.MinorTickMark.Size;
                }
            }
 
            this.markSize += (float)Math.Max(majorTickSize, minorTickSize);
 
 
            // Add axis line size
            SizeF borderSize = chartGraph.GetRelativeSize(new SizeF(this.LineWidth, this.LineWidth));
 
            // If axis is horizontal
            if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
            {
                this.markSize += borderSize.Height / 2f;
                this.markSize = Math.Min(this.markSize, (plotArea.Height / 100F) * (Axis.maxAxisMarkSize / axesNumber));
            }
            // If axis is vertical
            else
            {
                this.markSize += borderSize.Width / 2f;
                this.markSize = Math.Min(this.markSize, (plotArea.Width / 100F) * (Axis.maxAxisMarkSize / axesNumber));
            }
 
            // Add axis scroll bar size (if it's visible)
            this.scrollBarSize = 0f;
 
#if Microsoft_CONTROL

            if (this.ScrollBar.IsVisible &&
                (this.IsAxisOnAreaEdge || !this.IsMarksNextToAxis))
            {
                if (this.ScrollBar.IsPositionedInside)
                {
                    this.markSize += (float)this.ScrollBar.GetScrollBarRelativeSize();
                }
                else
                {
                    this.scrollBarSize = (float)this.ScrollBar.GetScrollBarRelativeSize();
                }
            }
 
#endif // Microsoft_CONTROL
 
 
            //*********************************************************
            //** Adjust mark size using area scene wall width
            //*********************************************************
            if (ChartArea.Area3DStyle.Enable3D &&
                !ChartArea.chartAreaIsCurcular &&
                ChartArea.BackColor != Color.Transparent &&
                ChartArea.Area3DStyle.WallWidth > 0)
            {
                SizeF areaWallSize = chartGraph.GetRelativeSize(new SizeF(ChartArea.Area3DStyle.WallWidth, ChartArea.Area3DStyle.WallWidth));
                if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                {
                    this.markSize += areaWallSize.Height;
                }
                else
                {
                    this.markSize += areaWallSize.Width;
                }
 
                // Ignore Max marks size for the 3D wall size.
                //this.markSize = Math.Min(this.markSize, (plotArea.Width / 100F) * (Axis.maxAxisMarkSize / axesNumber));
            }
 
            //*********************************************************
            //** Adjust title size and mark size using arrow size
            //*********************************************************
            if (arrowSize > (this.markSize + this.scrollBarSize + this.titleSize))
            {
                this.markSize = Math.Max(this.markSize, arrowSize - (this.markSize + this.scrollBarSize + this.titleSize));
                this.markSize = Math.Min(this.markSize, (plotArea.Width / 100F) * (Axis.maxAxisMarkSize / axesNumber));
            }
 
            //*********************************************************
            //** Calculate max label size
            //*********************************************************
            float maxLabelSize = 0;
 
            if (!autoPlotPosition)
            {
                if (this.GetIsMarksNextToAxis())
                {
                    if (this.AxisPosition == AxisPosition.Top)
                        maxLabelSize = (float)GetAxisPosition() - ChartArea.Position.Y;
                    else if (this.AxisPosition == AxisPosition.Bottom)
                        maxLabelSize = ChartArea.Position.Bottom - (float)GetAxisPosition();
                    if (this.AxisPosition == AxisPosition.Left)
                        maxLabelSize = (float)GetAxisPosition() - ChartArea.Position.X;
                    else if (this.AxisPosition == AxisPosition.Right)
                        maxLabelSize = ChartArea.Position.Right - (float)GetAxisPosition();
                }
                else
                {
                    if (this.AxisPosition == AxisPosition.Top)
                        maxLabelSize = plotArea.Y - ChartArea.Position.Y;
                    else if (this.AxisPosition == AxisPosition.Bottom)
                        maxLabelSize = ChartArea.Position.Bottom - plotArea.Bottom;
                    if (this.AxisPosition == AxisPosition.Left)
                        maxLabelSize = plotArea.X - ChartArea.Position.X;
                    else if (this.AxisPosition == AxisPosition.Right)
                        maxLabelSize = ChartArea.Position.Right - plotArea.Right;
                }
 
                maxLabelSize *= 2F;
            }
            else
            {
                if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                    maxLabelSize = plotArea.Height * (_maximumAutoSize / 100f);
                else
                    maxLabelSize = plotArea.Width * (_maximumAutoSize / 100f);
            }
 
 
 
            //******************************************************
            //** First try to select the interval that will 
            //** generate best fit labels.
            //******************************************************
 
 
 
			// Make sure the variable interval mode is enabled and
			// no custom label interval used.
			if( this.Enabled != AxisEnabled.False &&
				this.LabelStyle.Enabled &&
				this.IsVariableLabelCountModeEnabled() )
			{
				// Increase font by several points when height of the font is the most important
				// dimension. Use original size whenwidth is the most important size.
				float extraSize = 3f;
				if( (this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) && 
					(this.LabelStyle.Angle == 90 || this.LabelStyle.Angle == -90) )
				{
					extraSize = 0f;
				}
				if( (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom) && 
					(this.LabelStyle.Angle == 180 || this.LabelStyle.Angle == 0) )
				{
					extraSize = 0f;
				}
 
				// If 3D Common.Chart is used make the measurements with font several point larger
				if(ChartArea.Area3DStyle.Enable3D)
				{
					extraSize += 1f;
				}
 
				this.autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(this.LabelStyle.Font.FontFamily, 
					this.LabelStyle.Font.Size + extraSize, 
					this.LabelStyle.Font.Style, 
					GraphicsUnit.Point);
 
				// Reset angle and stagged flag used in the auto-fitting algorithm
				this.autoLabelAngle = this.LabelStyle.Angle;
				this.autoLabelOffset = (this.LabelStyle.IsStaggered) ? 1 : 0;
 
				// Adjust interval
				this.AdjustIntervalToFitLabels(chartGraph, autoPlotPosition, false);
			}
 
 
 
            //******************************************************
            //** Automatically calculate the best font size, angle 
            //** and try to use offset labels.
            //******************************************************
            // Reset all automatic label properties
            autoLabelFont = null;
            autoLabelAngle = -1000;
            autoLabelOffset = -1;
 
            // For circular Common.Chart area process auto-fitting for Y Axis only
            if (this.IsLabelAutoFit &&
                this.LabelAutoFitStyle != LabelAutoFitStyles.None &&
                !ChartArea.chartAreaIsCurcular)
            {
                bool fitDone = false;
                bool noWordWrap = false;
 
                // Set default font angle and labels offset flag
                autoLabelAngle = 0;
                autoLabelOffset = 0;
 
                // Original labels collection
                CustomLabelsCollection originalLabels = null;
 
                // Pick up maximum font size
                float size = 8f;
				size = (float)Math.Max(this.LabelAutoFitMaxFontSize, this.LabelAutoFitMinFontSize);
				_minLabelFontSize = Math.Min(this.LabelAutoFitMinFontSize, this.LabelAutoFitMaxFontSize);
				_aveLabelFontSize = _minLabelFontSize + Math.Abs(size - _minLabelFontSize)/2f;
 
 
                // Check if common font size should be used
                if (ChartArea.IsSameFontSizeForAllAxes)
                {
                    size = (float)Math.Min(size, ChartArea.axesAutoFontSize);
                }
 
                //Set new font
                autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(this.LabelStyle.Font.FontFamily,
                    size,
                    this.LabelStyle.Font.Style,
					GraphicsUnit.Point
                );
 
                // Check if we allowed to increase font size while auto-fitting
                if ((this.LabelAutoFitStyle & LabelAutoFitStyles.IncreaseFont) != LabelAutoFitStyles.IncreaseFont)
                {
                    // Use axis labels font as starting point
                    autoLabelFont = this.LabelStyle.Font;
                }
 
                // Loop while labels do not fit
                float spacer = 0f;
                while (!fitDone)
                {
                    //******************************************************
                    //** Check if labels fit
                    //******************************************************
 
                    // Check if grouping labels fit should be checked
                    bool checkLabelsFirstRowOnly = true;
                    if ((this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
                    {
                        // Only check grouping labels if we can reduce fonts size
                        checkLabelsFirstRowOnly = false;
                    }
 
                    // Check labels fit
                    fitDone = CheckLabelsFit(
                        chartGraph,
                        this.markSize + this.scrollBarSize + this.titleSize + spacer,
                        autoPlotPosition,
                        checkLabelsFirstRowOnly,
                        false);
 
                    //******************************************************
                    //** Adjust labels text properties to fit
                    //******************************************************
                    if (!fitDone)
                    {
                        // If font is bigger than average try to make it smaller
                        if (autoLabelFont.SizeInPoints >= _aveLabelFontSize &&
                            (this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
                        {
                            //Clean up the old font
                            autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
                                autoLabelFont.FontFamily,
                                autoLabelFont.SizeInPoints - 0.5f,
                                autoLabelFont.Style,
                                GraphicsUnit.Point);
                        }
 
                            // Try to use offset labels (2D charts and non-circular arae only!!!)
                        else if (!ChartArea.Area3DStyle.Enable3D &&
                            !ChartArea.chartAreaIsCurcular &&
                            originalLabels == null &&
                            autoLabelAngle == 0 &&
                            autoLabelOffset == 0 &&
                            (this.LabelAutoFitStyle & LabelAutoFitStyles.StaggeredLabels) == LabelAutoFitStyles.StaggeredLabels)
                        {
                            autoLabelOffset = 1;
                        }
 
                            // Try to insert new line characters in labels text
                        else if (!noWordWrap &&
                            (this.LabelAutoFitStyle & LabelAutoFitStyles.WordWrap) == LabelAutoFitStyles.WordWrap)
                        {
                            bool changed = false;
                            autoLabelOffset = 0;
 
                            // Check if backup copy of the original lables was made
                            if (originalLabels == null)
                            {
                                // Copy current labels collection
                                originalLabels = new CustomLabelsCollection(this);
                                foreach (CustomLabel label in this.CustomLabels)
                                {
                                    originalLabels.Add(label.Clone());
                                }
                            }
 
                            // Try to insert new line character into the longest label
                            changed = WordWrapLongestLabel(this.CustomLabels);
 
                            // Word wrapping do not solve the labels overlapping issue
                            if (!changed)
                            {
                                noWordWrap = true;
 
                                // Restore original labels
                                if (originalLabels != null)
                                {
                                    this.CustomLabels.Clear();
                                    foreach (CustomLabel label in originalLabels)
                                    {
                                        this.CustomLabels.Add(label.Clone());
                                    }
 
                                    originalLabels = null;
                                }
 
                                if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                                {
                                    if ((spacer == 0 ||
                                        spacer == 30f ||
                                        spacer == 20f) &&
                                        ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep30) == LabelAutoFitStyles.LabelsAngleStep30 ||
                                        (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep45) == LabelAutoFitStyles.LabelsAngleStep45 ||
                                        (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep90) == LabelAutoFitStyles.LabelsAngleStep90))
                                    {
                                        // Try to use 90 degrees angle
                                        autoLabelAngle = 90;
                                        noWordWrap = false;
 
                                        // Usually 55% of Common.Chart area size is allowed for labels
                                        // Reduce that space.
                                        if (spacer == 0f)
                                        {
                                            // 30
                                            spacer = 30f;
                                        }
                                        else if (spacer == 30f)
                                        {
                                            // 20
                                            spacer = 20f;
                                        }
                                        else if (spacer == 20f)
                                        {
                                            // 5
                                            spacer = 5f;
                                        }
                                        else
                                        {
                                            autoLabelAngle = 0;
                                            noWordWrap = true;
                                        }
 
                                    }
                                    else
                                    {
                                        spacer = 0f;
                                    }
                                }
                            }
                        }
 
                            // Try to change font angle
                        else if (autoLabelAngle != 90 &&
                            ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep30) == LabelAutoFitStyles.LabelsAngleStep30 ||
                            (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep45) == LabelAutoFitStyles.LabelsAngleStep45 ||
                            (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep90) == LabelAutoFitStyles.LabelsAngleStep90))
                        {
                            spacer = 0f;
                            autoLabelOffset = 0;
 
                            if ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep30) == LabelAutoFitStyles.LabelsAngleStep30)
                            {
                                // Increase angle by 45 degrees in 2D and 45 in 3D
                                autoLabelAngle += (ChartArea.Area3DStyle.Enable3D) ? 45 : 30;
                            }
                            else if ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep45) == LabelAutoFitStyles.LabelsAngleStep45)
                            {
                                // Increase angle by 45 degrees
                                autoLabelAngle += 45;
                            }
                            else if ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep90) == LabelAutoFitStyles.LabelsAngleStep90)
                            {
                                // Increase angle by 90 degrees
                                autoLabelAngle += 90;
                            }
                        }
 
                            // Try to reduce font again
                        else if (autoLabelFont.SizeInPoints > _minLabelFontSize &&
                            (this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
                        {
                            //Clean up the old font
                            autoLabelAngle = 0;
                            autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
                                autoLabelFont.FontFamily,
                                autoLabelFont.SizeInPoints - 0.5f,
                                autoLabelFont.Style,
                                GraphicsUnit.Point);
                        }
 
                            // Failed to fit
                        else
                        {
                            // Use last font
                            if ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep30) == LabelAutoFitStyles.LabelsAngleStep30 ||
                                (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep45) == LabelAutoFitStyles.LabelsAngleStep45 ||
                                (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep90) == LabelAutoFitStyles.LabelsAngleStep90)
                            {
                                // Reset angle
                                if (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom)
                                {
                                    autoLabelAngle = 90;
                                }
                                else
                                {
                                    autoLabelAngle = 0;
                                }
                            }
                            if ((this.LabelAutoFitStyle & LabelAutoFitStyles.StaggeredLabels) == LabelAutoFitStyles.StaggeredLabels)
                            {
                                // Reset offset labels
                                autoLabelOffset = 0;
                            }
                            fitDone = true;
                        }
                    }
                    else if (ChartArea.Area3DStyle.Enable3D &&
                        !ChartArea.chartAreaIsCurcular &&
                        autoLabelFont.SizeInPoints > _minLabelFontSize)
                    {
                        // Reduce auto-fit font by 1 for the 3D charts
                        autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
                            autoLabelFont.FontFamily,
                            autoLabelFont.SizeInPoints - 0.5f,
                            autoLabelFont.Style,
                            GraphicsUnit.Point);
                    }
                }
 
				// Change the auto-fit angle for top and bottom axes from 90 to -90
				if(this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
				{
					if(autoLabelAngle == 90)
					{
						autoLabelAngle = -90;
					}
				}
            }
 
            //*********************************************************
            //** Calculate overall labels size
            //*********************************************************
            this.labelSize = 0;
 
            // if labels are not enabled their size needs to remain zero
            if (this.LabelStyle.Enabled)
            {
                //******************************************************
                //** Calculate axis second labels row size
                //******************************************************
                this.labelSize = (maxAxisElementsSize) - this.markSize - this.scrollBarSize - this.titleSize;
                if (this.labelSize > 0)
                {
                    this.groupingLabelSizes = GetRequiredGroupLabelSize(chartGraph, (maxLabelSize / 100F) * maxAxisLabelRow2Size);
                    this.totlaGroupingLabelsSize = GetGroupLablesToatalSize();
                }
 
                //******************************************************
                //** Calculate axis labels size
                //******************************************************
                this.labelSize -= this.totlaGroupingLabelsSize;
                if (this.labelSize > 0)
                {
                    // If axis is horizontal
                    if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                    {
                        this.labelSize = elementSpacing + GetRequiredLabelSize(chartGraph,
                            (maxLabelSize / 100F) * (maxAxisElementsSize - this.markSize - this.scrollBarSize - this.titleSize), out this.unRotatedLabelSize);
                    }
                    // If axis is horizontal
                    else
                    {
                        this.labelSize = elementSpacing + GetRequiredLabelSize(chartGraph,
                            (maxLabelSize / 100F) * (maxAxisElementsSize - this.markSize - this.scrollBarSize - this.titleSize), out this.unRotatedLabelSize);
                    }
 
                    if (!this.LabelStyle.Enabled)
                    {
                        this.labelSize -= elementSpacing;
                    }
                }
                else
                {
                    this.labelSize = 0;
                }
 
                this.labelSize += this.totlaGroupingLabelsSize;
            }
 
#if SUBAXES
			// Calculate offsets for all sub axes
			if(!ChartArea.Area3DStyle.Enable3D && 
				!ChartArea.chartAreaIsCurcular)
			{
				float currentOffset = this.markSize + this.labelSize + this.titleSize + this.scrollBarSize;
				foreach(SubAxis subAxis in this.SubAxes)
				{
					if(subAxis.Enabled != AxisEnabled.False)
					{
						currentOffset += (float)subAxis.LocationOffset;
						subAxis.offsetFromParent = currentOffset;
						currentOffset += subAxis.markSize + subAxis.labelSize + subAxis.titleSize;
					}
				}
			}
#endif // SUBAXES
 
 
#if Microsoft_CONTROL
            // Restore previous invalidation flag
			Common.Chart.disableInvalidates = oldDisableInvalidates;
#endif //Microsoft_CONTROL
        }
 
		/// <summary>
		/// Calculates axis interval so that labels will fit most efficiently.
		/// </summary>
		/// <param name="chartGraph">Chart graphics.</param>
		/// <param name="autoPlotPosition">True if plot position is auto calculated.</param>
		/// <param name="onlyIncreaseInterval">True if interval should only be increased.</param>
		private void AdjustIntervalToFitLabels(ChartGraphics chartGraph, bool autoPlotPosition, bool onlyIncreaseInterval)
		{
			// Calculates axis interval so that labels will fit most efficiently.
			if(this.ScaleSegments.Count == 0)
			{
				this.AdjustIntervalToFitLabels(chartGraph, autoPlotPosition, null, onlyIncreaseInterval);
			}
			else
			{
				// Allow values to go outside the segment boundary
				this.ScaleSegments.AllowOutOfScaleValues = true;
 
				// Adjust interval of each segment first
				foreach(AxisScaleSegment axisScaleSegment in this.ScaleSegments)
				{
					this.AdjustIntervalToFitLabels(chartGraph, autoPlotPosition, axisScaleSegment, onlyIncreaseInterval);
				}
 
				// Fill labels using new segment intervals
				bool removeLabels = true;
				int segmentIndex = 0;
				ArrayList removedLabels = new ArrayList();
				ArrayList removedLabelsIndexes = new ArrayList();
				foreach(AxisScaleSegment scaleSegment in this.ScaleSegments)
				{
					scaleSegment.SetTempAxisScaleAndInterval();
					this.FillLabels(removeLabels);
					removeLabels = false;
					scaleSegment.RestoreAxisScaleAndInterval();
 
					// Remove last label of all segmenst except of the last
					if(segmentIndex < this.ScaleSegments.Count - 1 &&
						this.CustomLabels.Count > 0)
					{
						// Remove label and save it in the list
						removedLabels.Add(this.CustomLabels[this.CustomLabels.Count - 1]);
						removedLabelsIndexes.Add(this.CustomLabels.Count - 1);
						this.CustomLabels.RemoveAt(this.CustomLabels.Count - 1);
					}
 
					++segmentIndex;
				}
 
				// Check all previously removed last labels of each segment if there 
				// is enough space to fit them
				int reInsertedLabelsCount = 0;
				int labelIndex = 0;
				foreach(CustomLabel label in removedLabels)
				{
					// Re-insert the label
					int labelInsertIndex = (int)removedLabelsIndexes[labelIndex] + reInsertedLabelsCount;
					if(labelIndex < this.CustomLabels.Count)
					{
						this.CustomLabels.Insert(labelInsertIndex, label);
					}
					else
					{
						this.CustomLabels.Add(label);
					}
 
					// Check labels fit. Only horizontal or vertical fit is checked depending 
					// on the axis orientation.
					ArrayList labelPositions = new ArrayList();
					bool fitDone = CheckLabelsFit(
						chartGraph, 
						this.markSize + this.scrollBarSize + this.titleSize, 
						autoPlotPosition,
						true,
						false,
						(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? false : true,
						(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? true : false,
						labelPositions);
 
					// If labels fit check if any of the label positions overlap
					if(fitDone)
					{
						for(int index = 0; fitDone && index < labelPositions.Count; index++)
						{
							RectangleF rect1 = (RectangleF)labelPositions[index];
							for(int index2 = index + 1; fitDone && index2 < labelPositions.Count; index2++)
							{
								RectangleF rect2 = (RectangleF)labelPositions[index2];
								if(rect1.IntersectsWith(rect2))
								{
									fitDone = false;
								}
							}
						}
					}
 
					// If labels do not fit or overlapp - remove completly
					if(!fitDone)
					{
						this.CustomLabels.RemoveAt(labelInsertIndex);
					}
					else
					{
						++reInsertedLabelsCount;
					}
 
					++labelIndex;
				}
 
				// Make sure now values are rounded on segment boundary
				this.ScaleSegments.AllowOutOfScaleValues = false;
			}
		}
 
		/// <summary>
		/// Checks if variable count labels mode is enabled.
		/// </summary>
		/// <returns>True if variable count labels mode is enabled.</returns>
		private bool IsVariableLabelCountModeEnabled()
		{
			// Make sure the variable interval mode is enabled and
			// no custom label interval used.
			if( (this.IntervalAutoMode == IntervalAutoMode.VariableCount || this.ScaleSegments.Count > 0) &&
				!this.IsLogarithmic &&
				(this.tempLabelInterval <= 0.0 || (double.IsNaN(this.tempLabelInterval) && this.Interval <= 0.0)) )
			{
				// This feature is not supported for charts that do not
				// require X and Y axes (Pie, Radar, ...)
				if(!ChartArea.requireAxes)
				{
					return false;
				}
                // This feature is not supported if the axis doesn't have data range 
                if (Double.IsNaN(this.minimum) || Double.IsNaN(this.maximum))
                {
                    return false;
                }
				// Check if custom labels are used in the first row
				bool customLabels = false;
				foreach(CustomLabel label in this.CustomLabels)
				{
					if(label.customLabel && label.RowIndex == 0)
					{
						customLabels = true;
						break;
					}
				}
 
				// Proceed only if no custom labels are used in the first row
				if(!customLabels)
				{
					return true;
				}
			}
 
			return false;
		}
 
		/// <summary>
		/// Calculates axis interval so that labels will fit most efficiently.
		/// </summary>
		/// <param name="chartGraph">Chart graphics.</param>
		/// <param name="autoPlotPosition">True if plot position is auto calculated.</param>
		/// <param name="axisScaleSegment">Axis scale segment to process.</param>
		/// <param name="onlyIncreaseInterval">True if interval should only be increased.</param>
		private void AdjustIntervalToFitLabels(
			ChartGraphics chartGraph, 
			bool autoPlotPosition, 
			AxisScaleSegment axisScaleSegment,
			bool onlyIncreaseInterval)
		{
			// Re-fill the labels just for the scale segment provided
			if(axisScaleSegment != null)
			{
				// Re-fill new axis labels
				if(this.tempLabels != null)
				{
					this.CustomLabels.Clear();
					foreach( CustomLabel label in this.tempLabels )
					{
						this.CustomLabels.Add(label.Clone());
					}
				}
 
				// Fill labels just for the segment
				axisScaleSegment.SetTempAxisScaleAndInterval();
				this.FillLabels( true );
				axisScaleSegment.RestoreAxisScaleAndInterval();
			}
 
			// Calculate minimum interval size
			double minIntervalSzie = double.NaN;
			ArrayList axisSeries = AxisScaleBreakStyle.GetAxisSeries(this);
			foreach(Series series in axisSeries)
			{
				if(this.axisType == AxisName.X || this.axisType == AxisName.X2)
				{
					if(ChartHelper.IndexedSeries(series))
					{
						minIntervalSzie = 1.0;
					}
					else if(series.XValueType == ChartValueType.String || 
						series.XValueType == ChartValueType.Int32 || 
						series.XValueType == ChartValueType.UInt32 || 
						series.XValueType == ChartValueType.UInt64 ||
						series.XValueType == ChartValueType.Int64 )
					{
						minIntervalSzie = 1.0;
					}
				}
				else
				{
					if(series.YValueType == ChartValueType.String || 
						series.YValueType == ChartValueType.Int32 || 
						series.YValueType == ChartValueType.UInt32 || 
						series.YValueType == ChartValueType.UInt64 ||
						series.YValueType == ChartValueType.Int64 )
					{
						minIntervalSzie = 1.0;
					}
				}
			}
 
 
			// Iterate while interval is not found
			bool firstIteration = true;
			bool increaseNumberOfLabels = true;
			double currentInterval = (axisScaleSegment == null) ? this.labelStyle.GetInterval() : axisScaleSegment.Interval;
			DateTimeIntervalType currentIntervalType = (axisScaleSegment == null) ? this.labelStyle.GetIntervalType() : axisScaleSegment.IntervalType;
			DateTimeIntervalType lastFitIntervalType = currentIntervalType;
			double lastFitInterval = currentInterval;
			ArrayList lastFitLabels = new ArrayList();
			bool intervalFound = false;
			int iterationNumber = 0;
			while(!intervalFound && iterationNumber <= 1000)
			{
				bool fillNewLabels = true;
#if DEBUG
				if(iterationNumber >= 999)
				{
                    throw (new InvalidOperationException(SR.ExceptionAxisDynamicIntervalCalculationFailed));
				}
#endif // DEBUG
 
				// Check labels fit. Only horizontal or vertical fit is checked depending 
				// on the axis orientation.
				bool fitDone = CheckLabelsFit(
					chartGraph, 
					this.markSize + this.scrollBarSize + this.titleSize, 
					autoPlotPosition,
					true,
					false,
					(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? false : true,
					(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? true : false,
					null);
 
				// Check if we need to increase or reduce number of labels
				if(firstIteration)
				{
					firstIteration = false;
					increaseNumberOfLabels = (fitDone) ? true : false;
 
					// Check if we can decrease the interva;
					if(onlyIncreaseInterval && increaseNumberOfLabels)
					{
						intervalFound = true;
						continue;
					}
				}
 
				// Find new interval. Value 0.0 means that interval cannot be
				// reduced/increased any more and current interval should be used
				double newInterval = 0.0;
				DateTimeIntervalType newIntervalType = DateTimeIntervalType.Number;
				if(increaseNumberOfLabels)
				{
					if(fitDone)
					{
						// Make a copy of last interval and labels collection that previously fit
						lastFitInterval = currentInterval;
						lastFitIntervalType = currentIntervalType;
						lastFitLabels.Clear();
						foreach(CustomLabel label in this.CustomLabels)
						{
							lastFitLabels.Add(label);
						}
 
						newIntervalType = currentIntervalType;
						newInterval = this.ReduceLabelInterval(
							currentInterval, 
							minIntervalSzie, 
							ref newIntervalType);
					}
					else
					{
						newInterval = lastFitInterval;
						newIntervalType = lastFitIntervalType;
						intervalFound = true;
 
						// Reuse previously saved labels
						fillNewLabels = false;
						this.CustomLabels.Clear();
						foreach(CustomLabel label in lastFitLabels)
						{
							this.CustomLabels.Add(label);
						}
 
					}
				}
				else
				{
					if(!fitDone && this.CustomLabels.Count > 1)
					{
						newIntervalType = currentIntervalType;
						newInterval = this.IncreaseLabelInterval(
							currentInterval, 
							ref newIntervalType);
					}
					else
					{
						intervalFound = true;
					}
				}
 
				// Set new interval
				if(newInterval != 0.0)
				{
					currentInterval = newInterval;
					currentIntervalType = newIntervalType;
 
					if(axisScaleSegment == null)
					{
						this.SetIntervalAndType(newInterval, newIntervalType);
					}
					else
					{
						axisScaleSegment.Interval = newInterval;
						axisScaleSegment.IntervalType = newIntervalType;
					}
 
					// Re-fill new axis labels
					if(fillNewLabels)
					{
						if(this.tempLabels != null)
						{
							this.CustomLabels.Clear();
							foreach( CustomLabel label in this.tempLabels )
							{
								CustomLabels.Add(label.Clone());
							}
						}
					
						if(axisScaleSegment == null)
						{
							this.FillLabels(true);
						}
						else
						{
							axisScaleSegment.SetTempAxisScaleAndInterval();
							this.FillLabels( true );
							axisScaleSegment.RestoreAxisScaleAndInterval();
						}
					}
				}
				else
				{
					intervalFound = true;
				}
			
				++iterationNumber;
			}
		}
 
		/// <summary>
		/// Reduces current label interval, so that more labels can fit.
		/// </summary>
		/// <param name="oldInterval">An interval to reduce.</param>
		/// <param name="minInterval">Minimum interval size.</param>
        /// <param name="axisIntervalType">Interval type.</param>
		/// <returns>New interval or 0.0 if interval cannot be reduced.</returns>
		private double ReduceLabelInterval(
			double oldInterval, 
			double minInterval,
			ref DateTimeIntervalType axisIntervalType)
		{
			double newInterval = oldInterval;
 
			// Calculate rounded interval value
			double range = this.maximum - this.minimum;
			int iterationIndex = 0;
			if( axisIntervalType == DateTimeIntervalType.Auto ||
				axisIntervalType == DateTimeIntervalType.NotSet ||
				axisIntervalType == DateTimeIntervalType.Number)
			{
				// Process numeric scale
				double devider = 2.0;
				do
				{
#if DEBUG
					if(iterationIndex >= 99)
					{
                        throw (new InvalidOperationException(SR.ExceptionAxisIntervalDecreasingFailed));
					}
#endif // DEBUG
 
					newInterval = CalcInterval( range / (range / (newInterval / devider)) );
					if(newInterval == oldInterval)
					{
						devider *= 2.0;
					}
 
					++iterationIndex;
				} while(newInterval == oldInterval && iterationIndex <= 100);
			}
			else
			{
				// Process date scale
				if(oldInterval > 1.0 || oldInterval < 1.0)
				{
					if( axisIntervalType == DateTimeIntervalType.Minutes || 
						axisIntervalType == DateTimeIntervalType.Seconds)
					{
						if(oldInterval >= 60)
						{
							newInterval = Math.Round(oldInterval / 2.0);
						}
						else if(oldInterval >= 30.0)
						{
							newInterval = 15.0;
						}
						else if(oldInterval >= 15.0)
						{
							newInterval = 5.0;
						}
						else if(oldInterval >= 5.0)
						{
							newInterval = 1.0;
						}
					}
					else
					{
						newInterval = Math.Round(oldInterval / 2.0);
					}
					if(newInterval < 1.0)
					{
						newInterval = 1.0;
					}
				}
				if(oldInterval == 1.0)
				{
					if(axisIntervalType == DateTimeIntervalType.Years)
					{
						newInterval = 6.0;
						axisIntervalType = DateTimeIntervalType.Months;
					}
					else if(axisIntervalType == DateTimeIntervalType.Months)
					{
						newInterval = 2.0;
						axisIntervalType = DateTimeIntervalType.Weeks;
					}
					else if(axisIntervalType == DateTimeIntervalType.Weeks)
					{
						newInterval = 2.0;
						axisIntervalType = DateTimeIntervalType.Days;
					}
					else if(axisIntervalType == DateTimeIntervalType.Days)
					{
						newInterval = 12.0;
						axisIntervalType = DateTimeIntervalType.Hours;
					}
					else if(axisIntervalType == DateTimeIntervalType.Hours)
					{
						newInterval = 30.0;
						axisIntervalType = DateTimeIntervalType.Minutes;
					}
					else if(axisIntervalType == DateTimeIntervalType.Minutes)
					{
						newInterval = 30.0;
						axisIntervalType = DateTimeIntervalType.Seconds;
					}
					else if(axisIntervalType == DateTimeIntervalType.Seconds)
					{
						newInterval = 100.0;
						axisIntervalType = DateTimeIntervalType.Milliseconds;
					}
				}
			}
 
 
			// Make sure interal is not less than min interval specified
			if(!double.IsNaN(minInterval) && newInterval < minInterval)
			{
				newInterval = 0.0;
			}
 
			return newInterval;
		}
 
		/// <summary>
		/// Increases current label interval, so that less labels fit.
		/// </summary>
		/// <param name="oldInterval">An interval to increase.</param>
        /// <param name="axisIntervalType">Interval type.</param>
		/// <returns>New interval or 0.0 if interval cannot be increased.</returns>
		private double IncreaseLabelInterval(
			double oldInterval,  
			ref DateTimeIntervalType axisIntervalType)
		{
			double newInterval = oldInterval;
			
			// Calculate rounded interval value
			double range = this.maximum - this.minimum;
			int iterationIndex = 0;
			if( axisIntervalType == DateTimeIntervalType.Auto ||
				axisIntervalType == DateTimeIntervalType.NotSet ||
				axisIntervalType == DateTimeIntervalType.Number)
			{
				// Process numeric scale
				double devider = 2.0;
				do
				{
#if DEBUG
					if(iterationIndex >= 99)
					{
                        throw (new InvalidOperationException(SR.ExceptionAxisIntervalIncreasingFailed));
					}
#endif // DEBUG
 
					newInterval = CalcInterval( range / (range / (newInterval * devider)) );
					if(newInterval == oldInterval)
					{
						devider *= 2.0;
					}
					++iterationIndex;
				} while(newInterval == oldInterval && iterationIndex <= 100);
			}
			else
			{
				// Process date scale
				newInterval = oldInterval * 2.0;
				if(axisIntervalType == DateTimeIntervalType.Years)
				{
					// Do nothing for years
				}
				else if(axisIntervalType == DateTimeIntervalType.Months)
				{
					if(newInterval >= 12.0)
					{
						newInterval = 1.0;
						axisIntervalType = DateTimeIntervalType.Years;
					}
				}
				else if(axisIntervalType == DateTimeIntervalType.Weeks)
				{
					if(newInterval >= 4.0)
					{
						newInterval = 1.0;
						axisIntervalType = DateTimeIntervalType.Months;
					}
				}
				else if(axisIntervalType == DateTimeIntervalType.Days)
				{
					if(newInterval >= 7.0)
					{
						newInterval = 1.0;
						axisIntervalType = DateTimeIntervalType.Weeks;
					}
				}
				else if(axisIntervalType == DateTimeIntervalType.Hours)
				{
					if(newInterval >= 60.0)
					{
						newInterval = 1.0;
						axisIntervalType = DateTimeIntervalType.Days;
					}
				}
				else if(axisIntervalType == DateTimeIntervalType.Minutes)
				{
					if(newInterval >= 60.0)
					{
						newInterval = 1.0;
						axisIntervalType = DateTimeIntervalType.Hours;
					}
				}
				else if(axisIntervalType == DateTimeIntervalType.Seconds)
				{
					if(newInterval >= 60.0)
					{
						newInterval = 1.0;
						axisIntervalType = DateTimeIntervalType.Minutes;
					}
				}
				else if(axisIntervalType == DateTimeIntervalType.Milliseconds)
				{
					if(newInterval >= 1000.0)
					{
						newInterval = 1.0;
						axisIntervalType = DateTimeIntervalType.Seconds;
					}
				}
			}
 
			return newInterval;
		}
 
        /// <summary>
        /// Finds the longest labels with the space and inserts the new line character.
        /// </summary>
        /// <param name="labels">Labels collection.</param>
        /// <returns>True if collection was modified.</returns>
        private bool WordWrapLongestLabel(CustomLabelsCollection labels)
        {
            bool changed = false;
 
            // Each label may contain several lines of text.
            // Create a list that contains an array of text for each label.
            ArrayList labelTextRows = new ArrayList(labels.Count);
            foreach (CustomLabel label in labels)
            {
                labelTextRows.Add(label.Text.Split('\n'));
            }
 
            // Find the longest label with a space
            int longestLabelSize = 5;
            int longestLabelIndex = -1;
            int longestLabelRowIndex = -1;
            int index = 0;
            foreach (string[] textRows in labelTextRows)
            {
                for (int rowIndex = 0; rowIndex < textRows.Length; rowIndex++)
                {
                    if (textRows[rowIndex].Length > longestLabelSize && textRows[rowIndex].Trim().IndexOf(' ') > 0)
                    {
                        longestLabelSize = textRows[rowIndex].Length;
                        longestLabelIndex = index;
                        longestLabelRowIndex = rowIndex;
                    }
                }
                ++index;
            }
 
            // Longest label with a space was found
            if (longestLabelIndex >= 0 && longestLabelRowIndex >= 0)
            {
                // Try to find a space and replace it with a new line
                string newText = ((string[])labelTextRows[longestLabelIndex])[longestLabelRowIndex];
                for (index = 0; index < (newText.Length) / 2 - 1; index++)
                {
                    if (newText[(newText.Length) / 2 - index] == ' ')
                    {
                        newText =
                            newText.Substring(0, (newText.Length) / 2 - index) +
                            "\n" +
                            newText.Substring((newText.Length) / 2 - index + 1);
                        changed = true;
                    }
                    else if (newText[(newText.Length) / 2 + index] == ' ')
                    {
                        newText =
                            newText.Substring(0, (newText.Length) / 2 + index) +
                            "\n" +
                            newText.Substring((newText.Length) / 2 + index + 1);
                        changed = true;
                    }
 
                    if (changed)
                    {
                        ((string[])labelTextRows[longestLabelIndex])[longestLabelRowIndex] = newText;
                        break;
                    }
                }
 
                // Update label text
                if (changed)
                {
                    // Construct label text from multiple rows separated by "\n"
                    CustomLabel label = labels[longestLabelIndex];
                    label.Text = string.Empty;
                    for (int rowIndex = 0; rowIndex < ((string[])labelTextRows[longestLabelIndex]).Length; rowIndex++)
                    {
                        if (rowIndex > 0)
                        {
                            label.Text += "\n";
                        }
                        label.Text += ((string[])labelTextRows[longestLabelIndex])[rowIndex];
                    }
                }
            }
 
            return changed;
        }
 
        /// <summary>
        /// Calculates the auto-fit font for the circular Common.Chart area axis labels.
        /// </summary>
        /// <param name="graph">Chart graphics object.</param>
        /// <param name="axisList">List of sector labels.</param>
        /// <param name="labelsStyle">Circular labels style.</param>
        /// <param name="plotAreaRectAbs">Plotting area position.</param>
        /// <param name="areaRectAbs">Chart area position.</param>
        /// <param name="labelsSizeEstimate">Estimated size of labels.</param>
        internal void GetCircularAxisLabelsAutoFitFont(
            ChartGraphics graph,
            ArrayList axisList,
            CircularAxisLabelsStyle labelsStyle,
            RectangleF plotAreaRectAbs,
            RectangleF areaRectAbs,
            float labelsSizeEstimate)
        {
            // X axis settings defines if auto-fit font should be calculated
            if (!this.IsLabelAutoFit ||
                this.LabelAutoFitStyle == LabelAutoFitStyles.None ||
                !this.LabelStyle.Enabled)
            {
                return;
            }
 
			// Set minimum font size
			_minLabelFontSize = Math.Min(this.LabelAutoFitMinFontSize, this.LabelAutoFitMaxFontSize);
 
            // Create new auto-fit font
            this.autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
                this.LabelStyle.Font.FontFamily,
				Math.Max(this.LabelAutoFitMaxFontSize, this.LabelAutoFitMinFontSize),
                this.LabelStyle.Font.Style,
				GraphicsUnit.Point);
 
            // Check if we allowed to increase font size while auto-fitting
            if ((this.LabelAutoFitStyle & LabelAutoFitStyles.IncreaseFont) != LabelAutoFitStyles.IncreaseFont)
            {
                // Use axis labels font as starting point
                this.autoLabelFont = this.LabelStyle.Font;
            }
 
            // Loop while labels do not fit
            bool fitDone = false;
            while (!fitDone)
            {
                //******************************************************
                //** Check if labels fit
                //******************************************************
                fitDone = CheckCircularLabelsFit(
                    graph,
                    axisList,
                    labelsStyle,
                    plotAreaRectAbs,
                    areaRectAbs,
                    labelsSizeEstimate);
 
                //******************************************************
                //** Adjust labels text properties to fit
                //******************************************************
                if (!fitDone)
                {
                    // Try to reduce font size
                    if (autoLabelFont.SizeInPoints > _minLabelFontSize &&
                        (this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
                    {
                        autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
                            autoLabelFont.FontFamily, 
                            autoLabelFont.SizeInPoints - 1, 
                            autoLabelFont.Style, 
                            GraphicsUnit.Point);
 
                    }
 
                    // Failed to fit
                    else
                    {
                        // Use last font with no angles
                        autoLabelAngle = 0;
                        autoLabelOffset = 0;
                        fitDone = true;
                    }
                }
            }
        }
 
        /// <summary>
        /// Checks id circular axis labels fits using current auto-fit font.
        /// </summary>
        /// <param name="graph">Chart graphics object.</param>
        /// <param name="axisList">List of sector labels.</param>
        /// <param name="labelsStyle">Circular labels style.</param>
        /// <param name="plotAreaRectAbs">Plotting area position.</param>
        /// <param name="areaRectAbs">Chart area position.</param>
        /// <param name="labelsSizeEstimate">Estimated size of labels.</param>
        /// <returns>True if labels fit.</returns>
        internal bool CheckCircularLabelsFit(
            ChartGraphics graph,
            ArrayList axisList,
            CircularAxisLabelsStyle labelsStyle,
            RectangleF plotAreaRectAbs,
            RectangleF areaRectAbs,
            float labelsSizeEstimate)
        {
            bool labelsFit = true;
 
            // Get absolute center of the area
            PointF areaCenterAbs = graph.GetAbsolutePoint(ChartArea.circularCenter);
 
            // Get absolute markers size and spacing
            float spacing = graph.GetAbsolutePoint(new PointF(0, this.markSize + Axis.elementSpacing)).Y;
 
            //*****************************************************************
            //** Loop through all axis labels
            //*****************************************************************
            RectangleF prevLabelPosition = RectangleF.Empty;
            float prevLabelSideAngle = float.NaN;
            foreach (CircularChartAreaAxis axis in axisList)
            {
                //*****************************************************************
                //** Measure label text
                //*****************************************************************
                SizeF textSize = graph.MeasureString(
                    axis.Title.Replace("\\n", "\n"),
                    this.autoLabelFont);
 
                //*****************************************************************
                //** Get circular style label position.
                //*****************************************************************
                if (labelsStyle == CircularAxisLabelsStyle.Circular ||
                    labelsStyle == CircularAxisLabelsStyle.Radial)
                {
                    // Swith text size for the radial style
                    if (labelsStyle == CircularAxisLabelsStyle.Radial)
                    {
                        float tempValue = textSize.Width;
                        textSize.Width = textSize.Height;
                        textSize.Height = tempValue;
                    }
 
                    //*****************************************************************
                    //** Check overlapping with previous label
                    //*****************************************************************
 
                    // Get radius of plot area
                    float plotAreaRadius = areaCenterAbs.Y - plotAreaRectAbs.Y;
                    plotAreaRadius -= labelsSizeEstimate;
                    plotAreaRadius += spacing;
 
                    // Calculate angle on the side of the label
                    float leftSideAngle = (float)(Math.Atan((textSize.Width / 2f) / plotAreaRadius) * 180f / Math.PI);
                    float rightSideAngle = axis.AxisPosition + leftSideAngle;
                    leftSideAngle = axis.AxisPosition - leftSideAngle;
 
                    // Check if label overlap the previous label
                    if (!float.IsNaN(prevLabelSideAngle))
                    {
                        if (prevLabelSideAngle > leftSideAngle)
                        {
                            // Labels overlap
                            labelsFit = false;
                            break;
                        }
                    }
 
                    // Remember label side angle
                    prevLabelSideAngle = rightSideAngle - 1;
 
 
                    //*****************************************************************
                    //** Check if label is inside the Common.Chart area
                    //*****************************************************************
 
                    // Find the most outside point of the label
                    PointF outsidePoint = new PointF(areaCenterAbs.X, plotAreaRectAbs.Y);
                    outsidePoint.Y += labelsSizeEstimate;
                    outsidePoint.Y -= textSize.Height;
                    outsidePoint.Y -= spacing;
 
                    PointF[] rotatedPoint = new PointF[] { outsidePoint };
                    Matrix newMatrix = new Matrix();
                    newMatrix.RotateAt(axis.AxisPosition, areaCenterAbs);
                    newMatrix.TransformPoints(rotatedPoint);
 
                    // Check if rotated point is inside Common.Chart area
                    if (!areaRectAbs.Contains(rotatedPoint[0]))
                    {
                        // Label is not inside Common.Chart area
                        labelsFit = false;
                        break;
                    }
 
                }
 
                //*****************************************************************
                //** Get horizontal style label position.
                //*****************************************************************
                else if (labelsStyle == CircularAxisLabelsStyle.Horizontal)
                {
                    // Get text angle
                    float textAngle = axis.AxisPosition;
                    if (textAngle > 180f)
                    {
                        textAngle -= 180f;
                    }
 
                    // Get label rotated position
                    PointF[] labelPosition = new PointF[] { new PointF(areaCenterAbs.X, plotAreaRectAbs.Y) };
                    labelPosition[0].Y += labelsSizeEstimate;
                    labelPosition[0].Y -= spacing;
                    Matrix newMatrix = new Matrix();
                    newMatrix.RotateAt(textAngle, areaCenterAbs);
                    newMatrix.TransformPoints(labelPosition);
 
                    // Calculate label position
                    RectangleF curLabelPosition = new RectangleF(
                        labelPosition[0].X,
                        labelPosition[0].Y - textSize.Height / 2f,
                        textSize.Width,
                        textSize.Height);
                    if (textAngle < 5f)
                    {
                        curLabelPosition.X = labelPosition[0].X - textSize.Width / 2f;
                        curLabelPosition.Y = labelPosition[0].Y - textSize.Height;
                    }
                    if (textAngle > 175f)
                    {
                        curLabelPosition.X = labelPosition[0].X - textSize.Width / 2f;
                        curLabelPosition.Y = labelPosition[0].Y;
                    }
 
                    // Decrease label rectangle
                    curLabelPosition.Inflate(0f, -curLabelPosition.Height * 0.15f);
 
                    // Check if label position goes outside of the Common.Chart area.
                    if (!areaRectAbs.Contains(curLabelPosition))
                    {
                        // Label is not inside Common.Chart area
                        labelsFit = false;
                        break;
                    }
 
                    // Check if label position overlap previous label position.
                    if (!prevLabelPosition.IsEmpty && curLabelPosition.IntersectsWith(prevLabelPosition))
                    {
                        // Label intersects with previous label
                        labelsFit = false;
                        break;
                    }
 
                    // Set previous point position 
                    prevLabelPosition = curLabelPosition;
                }
            }
 
            return labelsFit;
        }
 
        #endregion
 
        #region Axis labels auto-fitting methods
 
        /// <summary>
        /// Adjust labels font size at second pass of auto fitting.
        /// </summary>
        /// <param name="chartGraph">Chart graphics object.</param>
        /// <param name="autoPlotPosition">Indicates that inner plot position is automatic.</param>
        internal void AdjustLabelFontAtSecondPass(ChartGraphics chartGraph, bool autoPlotPosition)
        {
#if SUBAXES
			// Process all sub-axis
			if(!ChartArea.Area3DStyle.Enable3D && 
				!ChartArea.chartAreaIsCurcular)
			{
				foreach(SubAxis subAxis in this.SubAxes)
				{
					subAxis.AdjustLabelFontAtSecondPass(chartGraph, autoPlotPosition);
				}
			}
#endif //SUBAXES
 
 
            //******************************************************
            //** First try to select the interval that will 
            //** generate best fit labels.
            //******************************************************
 
 
 
			// Make sure the variable interval mode is enabled
			if( this.Enabled != AxisEnabled.False &&
				this.LabelStyle.Enabled &&
				this.IsVariableLabelCountModeEnabled() )
			{
				// Set font for labels fitting
				if(this.autoLabelFont == null) 
				{
					this.autoLabelFont = this.LabelStyle.Font;
				}
 
				// Reset angle and stagged flag used in the auto-fitting algorithm
				if(this.autoLabelAngle < 0)
				{
					this.autoLabelAngle = this.LabelStyle.Angle;
				}
				if(this.autoLabelOffset < 0)
				{
					this.autoLabelOffset = (this.LabelStyle.IsStaggered) ? 1 : 0;
				}
 
				// Check labels fit
				bool fitDone = CheckLabelsFit(
					chartGraph, 
					this.markSize + this.scrollBarSize + this.titleSize, 
					autoPlotPosition,
					true,
					true,
					(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? false : true,
					(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? true : false,
					null);
 
				// If there is a problem fitting labels try to reduce number of labels by
				// increasing of the interval.
				if(!fitDone)
				{
					// Adjust interval
					this.AdjustIntervalToFitLabels(chartGraph, autoPlotPosition, true);
				}
			}
 
 
 
 
            //******************************************************
            //** If labels auto-fit is on try reducing font size.
            //******************************************************
 
            totlaGroupingLabelsSizeAdjustment = 0f;
            if (this.IsLabelAutoFit &&
                this.LabelAutoFitStyle != LabelAutoFitStyles.None &&
                this.Enabled != AxisEnabled.False)
            {
                bool fitDone = false;
 
                if (autoLabelFont == null)
                {
                    autoLabelFont = this.LabelStyle.Font;
                }
 
                // Loop while labels do not fit
                float oldLabelSecondRowSize = totlaGroupingLabelsSize;
                while (!fitDone)
                {
                    //******************************************************
                    //** Check if labels fit
                    //******************************************************
                    fitDone = CheckLabelsFit(
                        chartGraph,
                        this.markSize + this.scrollBarSize + this.titleSize,
                        autoPlotPosition,
                        true,
                        true);
 
                    //******************************************************
                    //** Adjust labels text properties to fit
                    //******************************************************
                    if (!fitDone)
                    {
                        // Try to reduce font
                        if (autoLabelFont.SizeInPoints > _minLabelFontSize)
                        {
                            // Reduce auto fit font
                            if (ChartArea != null && ChartArea.IsSameFontSizeForAllAxes)
                            {
                                // Same font for all axes
                                foreach (Axis currentAxis in ChartArea.Axes)
                                {
                                    if (currentAxis.enabled && currentAxis.IsLabelAutoFit && currentAxis.autoLabelFont != null)
                                    {
                                        currentAxis.autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
                                            currentAxis.autoLabelFont.FontFamily,
                                            autoLabelFont.SizeInPoints - 1,
                                            currentAxis.autoLabelFont.Style,
                                            GraphicsUnit.Point);
                                    }
                                }
                            }
                            else if ((this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
                            {
                                autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
                                    autoLabelFont.FontFamily,
                                    autoLabelFont.SizeInPoints - 1,
                                    autoLabelFont.Style,
                                    GraphicsUnit.Point);
                            }
                            else
                            {
                                // Failed to fit
                                fitDone = true;
                            }
                        }
                        else
                        {
                            // Failed to fit
                            fitDone = true;
                        }
                    }
                }
 
                this.totlaGroupingLabelsSizeAdjustment = oldLabelSecondRowSize - totlaGroupingLabelsSize;
            }
        }
 
        /// <summary>
        /// Check if axis is logarithmic
        /// </summary>
        /// <param name="yValue">Y value from data</param>
        /// <returns>Corected Y value if axis is logarithmic</returns>
        internal double GetLogValue(double yValue)
        {
            // Check if axis is logarithmic
            if (this.IsLogarithmic)
            {
                yValue = Math.Log(yValue, this.logarithmBase);
            }
 
            return yValue;
        }
 
        /// <summary>
        /// Checks if labels fit using current auto fit properties
        /// </summary>
        /// <param name="chartGraph">Chart graphics object.</param>
        /// <param name="otherElementsSize">Axis title and marks size.</param>
        /// <param name="autoPlotPosition">Indicates auto calculation of plotting area.</param>
        /// <param name="checkLabelsFirstRowOnly">Labels fit is checked during the second pass.</param>
        /// <param name="secondPass">Indicates second pass of labels fitting.</param>
        /// <returns>True if labels fit.</returns>
        private bool CheckLabelsFit(
            ChartGraphics chartGraph,
            float otherElementsSize,
            bool autoPlotPosition,
            bool checkLabelsFirstRowOnly,
            bool secondPass)
        {
            return this.CheckLabelsFit(
                chartGraph,
                otherElementsSize,
                autoPlotPosition,
                checkLabelsFirstRowOnly,
                secondPass,
                true,
                true,
                null);
        }
 
        /// <summary>
        /// Checks if labels fit using current auto fit properties
        /// </summary>
        /// <param name="chartGraph">Chart graphics object.</param>
        /// <param name="otherElementsSize">Axis title and marks size.</param>
        /// <param name="autoPlotPosition">Indicates auto calculation of plotting area.</param>
        /// <param name="checkLabelsFirstRowOnly">Labels fit is checked during the second pass.</param>
        /// <param name="secondPass">Indicates second pass of labels fitting.</param>
        /// <param name="checkWidth">True if width should be checked.</param>
        /// <param name="checkHeight">True if height should be checked.</param>
        /// <param name="labelPositions">Returns an array of label positions.</param>
        /// <returns>True if labels fit.</returns>
        private bool CheckLabelsFit(
            ChartGraphics chartGraph,
            float otherElementsSize,
            bool autoPlotPosition,
            bool checkLabelsFirstRowOnly,
            bool secondPass,
            bool checkWidth,
            bool checkHeight,
            ArrayList labelPositions)
        {
            // Reset list of label positions
            if (labelPositions != null)
            {
                labelPositions.Clear();
            }
 
            // Label string drawing format			
            using (StringFormat format = new StringFormat())
            {
                format.FormatFlags |= StringFormatFlags.LineLimit;
                format.Trimming = StringTrimming.EllipsisCharacter;
 
                // Initialize all labels position rectangle
                RectangleF rect = RectangleF.Empty;
 
                // Calculate max label size
                float maxLabelSize = 0;
                if (!autoPlotPosition)
                {
                    if (this.GetIsMarksNextToAxis())
                    {
                        if (this.AxisPosition == AxisPosition.Top)
                            maxLabelSize = (float)GetAxisPosition() - ChartArea.Position.Y;
                        else if (this.AxisPosition == AxisPosition.Bottom)
                            maxLabelSize = ChartArea.Position.Bottom - (float)GetAxisPosition();
                        if (this.AxisPosition == AxisPosition.Left)
                            maxLabelSize = (float)GetAxisPosition() - ChartArea.Position.X;
                        else if (this.AxisPosition == AxisPosition.Right)
                            maxLabelSize = ChartArea.Position.Right - (float)GetAxisPosition();
                    }
                    else
                    {
                        if (this.AxisPosition == AxisPosition.Top)
                            maxLabelSize = this.PlotAreaPosition.Y - ChartArea.Position.Y;
                        else if (this.AxisPosition == AxisPosition.Bottom)
                            maxLabelSize = ChartArea.Position.Bottom - this.PlotAreaPosition.Bottom;
                        if (this.AxisPosition == AxisPosition.Left)
                            maxLabelSize = this.PlotAreaPosition.X - ChartArea.Position.X;
                        else if (this.AxisPosition == AxisPosition.Right)
                            maxLabelSize = ChartArea.Position.Right - this.PlotAreaPosition.Right;
                    }
                    maxLabelSize *= 2F;
                }
                else
                {
                    if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                        maxLabelSize = ChartArea.Position.Height;
                    else
                        maxLabelSize = ChartArea.Position.Width;
                }
 
                // Loop through all grouping labels (all except first row)
                this.totlaGroupingLabelsSize = 0;
 
 
                // Get number of groups
                int groupLabelLevelCount = GetGroupLabelLevelCount();
 
                // Check ig grouping labels exist
                if (groupLabelLevelCount > 0)
                {
                    groupingLabelSizes = new float[groupLabelLevelCount];
 
                    // Loop through each level of grouping labels
                    bool fitResult = true;
                    for (int groupLevelIndex = 1; groupLevelIndex <= groupLabelLevelCount; groupLevelIndex++)
                    {
                        groupingLabelSizes[groupLevelIndex - 1] = 0f;
 
                        // Loop through all labels in the level
                        foreach (CustomLabel label in this.CustomLabels)
                        {
                            // Skip if label middle point is outside current scaleView
                            if (label.RowIndex == 0)
                            {
                                double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
                                if (middlePoint < this.ViewMinimum || middlePoint > this.ViewMaximum)
                                {
                                    continue;
                                }
                            }
 
                            if (label.RowIndex == groupLevelIndex)
                            {
                                // Calculate label rect
                                double fromPosition = this.GetLinearPosition(label.FromPosition);
                                double toPosition = this.GetLinearPosition(label.ToPosition);
                                if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                                {
                                    rect.Height = (maxLabelSize / 100F) * maxAxisLabelRow2Size / groupLabelLevelCount;
                                    rect.X = (float)Math.Min(fromPosition, toPosition);
                                    rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
                                }
                                else
                                {
                                    rect.Width = (maxLabelSize / 100F) * maxAxisLabelRow2Size / groupLabelLevelCount;
                                    rect.Y = (float)Math.Min(fromPosition, toPosition);
                                    rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
                                }
 
                                // Measure string
                                SizeF axisLabelSize = chartGraph.MeasureStringRel(label.Text.Replace("\\n", "\n"), autoLabelFont);
 
                                // Add image size
                                if (label.Image.Length > 0)
                                {
                                    SizeF imageAbsSize = new SizeF();
 
                                    if (this.Common.ImageLoader.GetAdjustedImageSize(label.Image, chartGraph.Graphics, ref imageAbsSize))
                                    {
                                        SizeF imageRelSize = chartGraph.GetRelativeSize(imageAbsSize);
                                        axisLabelSize.Width += imageRelSize.Width;
                                        axisLabelSize.Height = Math.Max(axisLabelSize.Height, imageRelSize.Height);
                                    }
                                }
 
                                // Add extra spacing for the box marking of the label
                                if (label.LabelMark == LabelMarkStyle.Box)
                                {
                                    // Get relative size from pixels and add it to the label size
                                    SizeF spacerSize = chartGraph.GetRelativeSize(new SizeF(4, 4));
                                    axisLabelSize.Width += spacerSize.Width;
                                    axisLabelSize.Height += spacerSize.Height;
                                }
 
                                // Calculate max height of the second row of labels
                                if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                                {
                                    groupingLabelSizes[groupLevelIndex - 1] = (float)Math.Max(groupingLabelSizes[groupLevelIndex - 1], axisLabelSize.Height);
                                }
                                else
                                {
                                    axisLabelSize.Width = chartGraph.GetAbsoluteSize(new SizeF(axisLabelSize.Height, axisLabelSize.Height)).Height;
                                    axisLabelSize.Width = chartGraph.GetRelativeSize(new SizeF(axisLabelSize.Width, axisLabelSize.Width)).Width;
                                    groupingLabelSizes[groupLevelIndex - 1] = (float)Math.Max(groupingLabelSizes[groupLevelIndex - 1], axisLabelSize.Width);
                                }
 
                                // Check if string fits
                                if (Math.Round(axisLabelSize.Width) >= Math.Round(rect.Width) &&
                                    checkWidth)
                                {
                                    fitResult = false;
                                }
                                if (Math.Round(axisLabelSize.Height) >= Math.Round(rect.Height) &&
                                    checkHeight)
                                {
                                    fitResult = false;
                                }
                            }
                        }
                    }
 
                    this.totlaGroupingLabelsSize = this.GetGroupLablesToatalSize();
                    if (!fitResult && !checkLabelsFirstRowOnly)
                    {
                        return false;
                    }
 
                }
 
                // Loop through all labels in the first row
                float angle = autoLabelAngle;
                int labelIndex = 0;
                foreach (CustomLabel label in this.CustomLabels)
                {
                    // Skip if label middle point is outside current scaleView
                    if (label.RowIndex == 0)
                    {
                        double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
                        if (middlePoint < this.ViewMinimum || middlePoint > this.ViewMaximum)
                        {
                            continue;
                        }
                    }
 
                    if (label.RowIndex == 0)
                    {
 
                        // Force which scale segment to use when calculating label position
                        if (labelPositions != null)
                        {
                            this.ScaleSegments.EnforceSegment(this.ScaleSegments.FindScaleSegmentForAxisValue((label.FromPosition + label.ToPosition) / 2.0));
                        }
 
 
                        // Set label From and To coordinates
                        double fromPosition = this.GetLinearPosition(label.FromPosition);
                        double toPosition = this.GetLinearPosition(label.ToPosition);
 
 
                        // Reset scale segment to use when calculating label position
                        if (labelPositions != null)
                        {
                            this.ScaleSegments.EnforceSegment(null);
                        }
 
 
                        // Calculate single label position
                        rect.X = this.PlotAreaPosition.X;
                        rect.Y = (float)Math.Min(fromPosition, toPosition);
                        rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
 
                        float maxElementSize = maxAxisElementsSize;
                        if (maxAxisElementsSize - this.totlaGroupingLabelsSize > 55)
                        {
                            maxElementSize = 55 + this.totlaGroupingLabelsSize;
                        }
                        if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                        {
                            rect.Width = (maxLabelSize / 100F) *
                                (maxElementSize - this.totlaGroupingLabelsSize - otherElementsSize - elementSpacing);
                        }
                        else
                        {
                            rect.Width = (maxLabelSize / 100F) *
                                (maxElementSize - this.totlaGroupingLabelsSize - otherElementsSize - elementSpacing);
                        }
 
                        // Adjust label From/To position if labels are displayed with offset
                        if (autoLabelOffset == 1)
                        {
                            rect.Y -= rect.Height / 2F;
                            rect.Height *= 2F;
                            rect.Width /= 2F;
                        }
 
                        // If horizontal axis
                        if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                        {
                            // Switch rectangle sizes
                            float val = rect.Height;
                            rect.Height = rect.Width;
                            rect.Width = val;
 
                            // Set vertical font for measuring
                            if (angle != 0)
                            {
                                format.FormatFlags |= StringFormatFlags.DirectionVertical;
                            }
                        }
                        else
                        {
                            // Set vertical font for measuring
                            if (angle == 90 || angle == -90)
                            {
                                angle = 0;
                                format.FormatFlags |= StringFormatFlags.DirectionVertical;
                            }
                        }
 
                        // Measure label text size. Add the 'I' character to allow a little bit of spacing between labels.
                        SizeF axisLabelSize = chartGraph.MeasureStringRel(
                            label.Text.Replace("\\n", "\n") + "W",
                            autoLabelFont,
                            (secondPass) ? rect.Size : ChartArea.Position.ToRectangleF().Size,
                            format);
 
                        // Width and height maybe zeros if rect is too small to fit the text and
                        // the LineLimit format flag is set. 
                        if (label.Text.Length > 0 &&
                            (axisLabelSize.Width == 0f ||
                            axisLabelSize.Height == 0f))
                        {
                            // Measure string without the LineLimit flag
                            format.FormatFlags ^= StringFormatFlags.LineLimit;
                            axisLabelSize = chartGraph.MeasureStringRel(
                                label.Text.Replace("\\n", "\n"),
                                autoLabelFont,
                                (secondPass) ? rect.Size : ChartArea.Position.ToRectangleF().Size,
                                format);
                            format.FormatFlags |= StringFormatFlags.LineLimit;
                        }
 
 
                        // Add image size
                        if (label.Image.Length > 0)
                        {
                            SizeF imageAbsSize = new SizeF();
 
                            if(this.Common.ImageLoader.GetAdjustedImageSize(label.Image, chartGraph.Graphics, ref imageAbsSize))
                            {
                                SizeF imageRelSize = chartGraph.GetRelativeSize(imageAbsSize);
                                if ((format.FormatFlags & StringFormatFlags.DirectionVertical) == StringFormatFlags.DirectionVertical)
                                {
                                    axisLabelSize.Height += imageRelSize.Height;
                                    axisLabelSize.Width = Math.Max(axisLabelSize.Width, imageRelSize.Width);
                                }
                                else
                                {
                                    axisLabelSize.Width += imageRelSize.Width;
                                    axisLabelSize.Height = Math.Max(axisLabelSize.Height, imageRelSize.Height);
                                }
                            }
                        }
 
                        // Add extra spacing for the box marking of the label
                        if (label.LabelMark == LabelMarkStyle.Box)
                        {
                            // Get relative size from pixels and add it to the label size
                            SizeF spacerSize = chartGraph.GetRelativeSize(new SizeF(4, 4));
                            axisLabelSize.Width += spacerSize.Width;
                            axisLabelSize.Height += spacerSize.Height;
                        }
 
 
                        // Calculate size using label angle
                        float width = axisLabelSize.Width;
                        float height = axisLabelSize.Height;
                        if (angle != 0)
                        {
                            // Decrease label rectangle width by 3%
                            rect.Width *= 0.97f;
 
                            if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                            {
                                width = (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
                                width += (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
 
                                height = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
                                height += (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
                            }
                            else
                            {
                                width = (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
                                width += (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
 
                                height = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
                                height += (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
                            }
                        }
 
                        // Save label position
                        if (labelPositions != null)
                        {
                            RectangleF labelPosition = rect;
                            if (angle == 0F || angle == 90F || angle == -90F)
                            {
                                if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                                {
                                    labelPosition.X = labelPosition.X + labelPosition.Width / 2f - width / 2f;
                                    labelPosition.Width = width;
                                }
                                else
                                {
                                    labelPosition.Y = labelPosition.Y + labelPosition.Height / 2f - height / 2f;
                                    labelPosition.Height = height;
                                }
                            }
                            labelPositions.Add(labelPosition);
                        }
 
                        // Check if string fits
                        if (angle == 0F)
                        {
                            if (width >= rect.Width && checkWidth)
                            {
                                return false;
                            }
                            if (height >= rect.Height && checkHeight)
                            {
                                return false;
                            }
                        }
                        if (angle == 90F || angle == -90F)
                        {
                            if (width >= rect.Width && checkWidth)
                            {
                                return false;
                            }
                            if (height >= rect.Height && checkHeight)
                            {
                                return false;
                            }
                        }
                        else
                        {
                            if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                            {
                                if (width >= rect.Width * 2F && checkWidth)
                                {
                                    return false;
                                }
                                if (height >= rect.Height * 2F && checkHeight)
                                {
                                    return false;
                                }
                            }
                            else
                            {
                                if (width >= rect.Width * 2F && checkWidth)
                                {
                                    return false;
                                }
                                if (height >= rect.Height * 2F && checkHeight)
                                {
                                    return false;
                                }
                            }
                        }
 
                        ++labelIndex;
                    }
                }
            }
 
            return true;
        }
 
        /// <summary>
        /// Calculates the best size for labels area.
        /// </summary>
        /// <param name="chartGraph">Chart graphics object.</param>
        /// <param name="maxLabelSize">Maximum labels area size.</param>
        /// <param name="resultSize">Label size without angle = 0.</param>
        private float GetRequiredLabelSize(ChartGraphics chartGraph, float maxLabelSize, out float resultSize)
        {
            float resultRotatedSize = 0F;
            resultSize = 0F;
            float angle = (autoLabelAngle < -90) ? this.LabelStyle.Angle : autoLabelAngle;
            labelNearOffset = float.MaxValue;
            labelFarOffset = float.MinValue;
 
            // Label string drawing format			
            using (StringFormat format = new StringFormat())
            {
                format.FormatFlags |= StringFormatFlags.LineLimit;
                format.Trimming = StringTrimming.EllipsisCharacter;
 
                // Initialize all labels position rectangle
                RectangleF rectLabels = ChartArea.Position.ToRectangleF();
 
                // Loop through all labels in the first row
                foreach (CustomLabel label in this.CustomLabels)
                {
                    // Skip if label middle point is outside current scaleView
                    if (label.RowIndex == 0)
                    {
                        decimal middlePoint = (decimal)(label.FromPosition + label.ToPosition) / (decimal)2.0;
                        if (middlePoint < (decimal)this.ViewMinimum || middlePoint > (decimal)this.ViewMaximum)
                        {
                            continue;
                        }
                    }
                    if (label.RowIndex == 0)
                    {
                        // Calculate single label position
                        RectangleF rect = rectLabels;
                        rect.Width = maxLabelSize;
 
                        // Set label From and To coordinates
                        double fromPosition = this.GetLinearPosition(label.FromPosition);
                        double toPosition = this.GetLinearPosition(label.ToPosition);
                        rect.Y = (float)Math.Min(fromPosition, toPosition);
                        rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
 
                        // Adjust label From/To position if labels are displayed with offset
                        if ((autoLabelOffset == -1) ? this.LabelStyle.IsStaggered : (autoLabelOffset == 1))
                        {
                            rect.Y -= rect.Height / 2F;
                            rect.Height *= 2F;
                        }
 
                        // If horizontal axis
                        if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                        {
                            // Switch rectangle sizes
                            float val = rect.Height;
                            rect.Height = rect.Width;
                            rect.Width = val;
 
                            // Set vertical font for measuring
                            if (angle != 0)
                            {
                                format.FormatFlags |= StringFormatFlags.DirectionVertical;
                            }
                        }
                        else
                        {
                            // Set vertical font for measuring
                            if (angle == 90 || angle == -90)
                            {
                                angle = 0;
                                format.FormatFlags |= StringFormatFlags.DirectionVertical;
                            }
                        }
 
                        // Measure label text size
                        rect.Width = (float)Math.Ceiling(rect.Width);
                        rect.Height = (float)Math.Ceiling(rect.Height);
                        SizeF axisLabelSize = chartGraph.MeasureStringRel(label.Text.Replace("\\n", "\n"),
                            (autoLabelFont != null) ? autoLabelFont : this.LabelStyle.Font,
                            rect.Size,
                            format);
 
                        // Width and height maybe zeros if rect is too small to fit the text and
                        // the LineLimit format flag is set. 
                        if (axisLabelSize.Width == 0f || axisLabelSize.Height == 0f)
                        {
                            // Measure string without the LineLimit flag
                            format.FormatFlags ^= StringFormatFlags.LineLimit;
                            axisLabelSize = chartGraph.MeasureStringRel(label.Text.Replace("\\n", "\n"),
                                (autoLabelFont != null) ? autoLabelFont : this.LabelStyle.Font,
                                rect.Size,
                                format);
                            format.FormatFlags |= StringFormatFlags.LineLimit;
                        }
 
 
                        // Add image size
                        if (label.Image.Length > 0)
                        {
                            SizeF imageAbsSize = new SizeF();
 
                            if (this.Common.ImageLoader.GetAdjustedImageSize(label.Image, chartGraph.Graphics, ref imageAbsSize))
                            {
                                SizeF imageRelSize = chartGraph.GetRelativeSize(imageAbsSize);
                                
                                if ((format.FormatFlags & StringFormatFlags.DirectionVertical) == StringFormatFlags.DirectionVertical)
                                {
                                    axisLabelSize.Height += imageRelSize.Height;
                                    axisLabelSize.Width = Math.Max(axisLabelSize.Width, imageRelSize.Width);
                                }
                                else
                                {
                                    axisLabelSize.Width += imageRelSize.Width;
                                    axisLabelSize.Height = Math.Max(axisLabelSize.Height, imageRelSize.Height);
                                }
                            }
                        }
 
                        // Add extra spacing for the box marking of the label
                        if (label.LabelMark == LabelMarkStyle.Box)
                        {
                            // Get relative size from pixels and add it to the label size
                            SizeF spacerSize = chartGraph.GetRelativeSize(new SizeF(4, 4));
                            axisLabelSize.Width += spacerSize.Width;
                            axisLabelSize.Height += spacerSize.Height;
                        }
 
 
                        // Calculate size using label angle
                        float width = axisLabelSize.Width;
                        float height = axisLabelSize.Height;
                        if (angle != 0)
                        {
                            width = (float)Math.Cos((90 - Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
                            width += (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
 
                            height = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
                            height += (float)Math.Sin((90 - Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
                        }
 
                        width = (float)Math.Ceiling(width) * 1.05f;
                        height = (float)Math.Ceiling(height) * 1.05f;
                        axisLabelSize.Width = (float)Math.Ceiling(axisLabelSize.Width) * 1.05f;
                        axisLabelSize.Height = (float)Math.Ceiling(axisLabelSize.Height) * 1.05f;
 
 
                        // If axis is horizontal
                        if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                        {
                            if (angle == 90 || angle == -90 || angle == 0)
                            {
                                resultSize = Math.Max(resultSize, axisLabelSize.Height);
                                resultRotatedSize = Math.Max(resultRotatedSize, axisLabelSize.Height);
 
                                // Calculate the over hang of labels on the side
                                labelNearOffset = (float)Math.Min(labelNearOffset, (fromPosition + toPosition) / 2f - axisLabelSize.Width / 2f);
                                labelFarOffset = (float)Math.Max(labelFarOffset, (fromPosition + toPosition) / 2f + axisLabelSize.Width / 2f);
 
                            }
                            else
                            {
                                resultSize = Math.Max(resultSize, axisLabelSize.Height);
                                resultRotatedSize = Math.Max(resultRotatedSize, height);
 
                                // Calculate the over hang of labels on the side
                                if (angle > 0)
                                {
                                    labelFarOffset = (float)Math.Max(labelFarOffset, (fromPosition + toPosition) / 2f + width * 1.1f);
                                }
                                else
                                {
                                    labelNearOffset = (float)Math.Min(labelNearOffset, (fromPosition + toPosition) / 2f - width * 1.1f);
                                }
                            }
                        }
                        // If axis is vertical
                        else
                        {
                            if (angle == 90 || angle == -90 || angle == 0)
                            {
                                resultSize = Math.Max(resultSize, axisLabelSize.Width);
                                resultRotatedSize = Math.Max(resultRotatedSize, axisLabelSize.Width);
 
                                // Calculate the over hang of labels on the side
                                labelNearOffset = (float)Math.Min(labelNearOffset, (fromPosition + toPosition) / 2f - axisLabelSize.Height / 2f);
                                labelFarOffset = (float)Math.Max(labelFarOffset, (fromPosition + toPosition) / 2f + axisLabelSize.Height / 2f);
                            }
                            else
                            {
                                resultSize = Math.Max(resultSize, axisLabelSize.Width);
                                resultRotatedSize = Math.Max(resultRotatedSize, width);
 
                                // Calculate the over hang of labels on the side
                                if (angle > 0)
                                {
                                    labelFarOffset = (float)Math.Max(labelFarOffset, (fromPosition + toPosition) / 2f + height * 1.1f);
                                }
                                else
                                {
                                    labelNearOffset = (float)Math.Min(labelNearOffset, (fromPosition + toPosition) / 2f - height * 1.1f);
                                }
                            }
                        }
 
                        // Check if we exceed the maximum value
                        if (resultSize > maxLabelSize)
                        {
                            resultSize = maxLabelSize;
                        }
                    }
                }
            }
 
            // Adjust results if labels are displayed with offset
            if ((autoLabelOffset == -1) ? this.LabelStyle.IsStaggered : (autoLabelOffset == 1))
            {
                resultSize *= 2F;
                resultRotatedSize *= 2F;
 
                // Check if we exceed the maximum value
                if (resultSize > maxLabelSize)
                {
                    resultSize = maxLabelSize;
                    resultRotatedSize = maxLabelSize;
                }
            }
 
            // Adjust labels size for the 3D Common.Chart
            if (ChartArea.Area3DStyle.Enable3D && !ChartArea.chartAreaIsCurcular)
            {
                // Increase labels size
                resultSize *= 1.1f;
                resultRotatedSize *= 1.1f;
            }
 
            return resultRotatedSize;
        }
 
        /// <summary>
        /// Gets total size of all grouping labels.
        /// </summary>
        /// <returns>Total size of all grouping labels.</returns>
        internal float GetGroupLablesToatalSize()
        {
            float size = 0f;
            if (this.groupingLabelSizes != null && this.groupingLabelSizes.Length > 0)
            {
                foreach (float val in this.groupingLabelSizes)
                {
                    size += val;
                }
            }
 
            return size;
        }
 
        /// <summary>
        /// Gets number of levels of the grouping labels.
        /// </summary>
        /// <returns>Number of levels of the grouping labels.</returns>
        internal int GetGroupLabelLevelCount()
        {
            int groupLabelLevel = 0;
            foreach (CustomLabel label in this.CustomLabels)
            {
                if (label.RowIndex > 0)
                {
                    groupLabelLevel = Math.Max(groupLabelLevel, label.RowIndex);
                }
            }
 
            return groupLabelLevel;
        }
 
        /// <summary>
        /// Calculates the best size for axis labels for all rows except first one (grouping labels).
        /// </summary>
        /// <param name="chartGraph">Chart graphics object.</param>
        /// <param name="maxLabelSize">Maximum labels area size.</param>
        /// <returns>Array of grouping label sizes for each level.</returns>
        private float[] GetRequiredGroupLabelSize(ChartGraphics chartGraph, float maxLabelSize)
        {
            float[] resultSize = null;
 
            // Get number of groups
            int groupLabelLevelCount = GetGroupLabelLevelCount();
 
            // Check ig grouping labels exist
            if (groupLabelLevelCount > 0)
            {
                // Create result array
                resultSize = new float[groupLabelLevelCount];
 
                // Loop through each level of grouping labels
                for (int groupLevelIndex = 1; groupLevelIndex <= groupLabelLevelCount; groupLevelIndex++)
                {
                    resultSize[groupLevelIndex - 1] = 0f;
 
                    // Loop through all labels in the level
                    foreach (CustomLabel label in this.CustomLabels)
                    {
                        // Skip if label middle point is outside current scaleView
                        if (label.RowIndex == 0)
                        {
                            double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
                            if (middlePoint < this.ViewMinimum || middlePoint > this.ViewMaximum)
                            {
                                continue;
                            }
                        }
 
                        if (label.RowIndex == groupLevelIndex)
                        {
                            // Measure label text size
                            SizeF axisLabelSize = chartGraph.MeasureStringRel(label.Text.Replace("\\n", "\n"), (autoLabelFont != null) ? autoLabelFont : this.LabelStyle.Font);
                            axisLabelSize.Width = (float)Math.Ceiling(axisLabelSize.Width);
                            axisLabelSize.Height = (float)Math.Ceiling(axisLabelSize.Height);
 
 
							// Add image size
							if(label.Image.Length > 0)
							{
                                SizeF imageAbsSize = new SizeF();
 
                                if(this.Common.ImageLoader.GetAdjustedImageSize(label.Image, chartGraph.Graphics, ref imageAbsSize))
								{
									SizeF imageRelSize = chartGraph.GetRelativeSize(imageAbsSize);
									axisLabelSize.Width += imageRelSize.Width;
									axisLabelSize.Height = Math.Max(axisLabelSize.Height, imageRelSize.Height);
								}
							}
 
							// Add extra spacing for the box marking of the label
							if(label.LabelMark == LabelMarkStyle.Box)
							{
								// Get relative size from pixels and add it to the label size
								SizeF	spacerSize = chartGraph.GetRelativeSize(new SizeF(4, 4));
								axisLabelSize.Width += spacerSize.Width;
								axisLabelSize.Height += spacerSize.Height;
							}
 
 
 
                            // If axis is horizontal
                            if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
                            {
                                resultSize[groupLevelIndex - 1] = Math.Max(resultSize[groupLevelIndex - 1], axisLabelSize.Height);
                            }
                            // If axis is vertical
                            else
                            {
                                axisLabelSize.Width = chartGraph.GetAbsoluteSize(new SizeF(axisLabelSize.Height, axisLabelSize.Height)).Height;
                                axisLabelSize.Width = chartGraph.GetRelativeSize(new SizeF(axisLabelSize.Width, axisLabelSize.Width)).Width;
                                resultSize[groupLevelIndex - 1] = Math.Max(resultSize[groupLevelIndex - 1], axisLabelSize.Width);
                            }
 
                            // Check if we exceed the maximum value
                            if (resultSize[groupLevelIndex - 1] > maxLabelSize / groupLabelLevelCount)
                            {
                                // NOTE: Group Labels size limitations are removed !!!
                                //	resultSize[groupLevelIndex - 1] = maxLabelSize / groupLabelLevelCount;
                                //	break;
                            }
                        }
                    }
                }
            }
 
            return resultSize;
        }
 
        #endregion
 
        #region Axis helper methods
 
 
        /// <summary>
        /// Gets main or sub axis associated with this axis.
        /// </summary>
        /// <param name="subAxisName">Sub axis name or empty string to get the main axis.</param>
        /// <returns>Main or sub axis of the main axis.</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "subAxisName")]
        internal Axis GetSubAxis(string subAxisName)
        {
#if SUBAXES
			if(!this.IsSubAxis && subAxisName.Length > 0)
			{
				SubAxis subAxis = this.SubAxes.FindByName(subAxisName);
				if(subAxis == null)
				{
					throw(new InvalidOperationException( SR.ExceptionSubAxisNameNotFoundShort( subAxisName )));
				}
				return subAxis;
			}
#endif // SUBAXES
            return this;
        }
 
        /// <summary>
        /// Checks if axis marks should be next to the axis
        /// </summary>
        /// <returns>true if marks are next to axis.</returns>
        internal bool GetIsMarksNextToAxis()
        {
            if (ChartArea != null && ChartArea.chartAreaIsCurcular)
            {
                return true;
            }
            return this.IsMarksNextToAxis;
        }
 
		/// <summary>
		/// Gets axis auto interval type.
		/// </summary>
		/// <returns>Axis interval type.</returns>
		internal DateTimeIntervalType GetAxisIntervalType()
		{
			if(InternalIntervalType == DateTimeIntervalType.Auto)
			{
				if(GetAxisValuesType() == ChartValueType.DateTime ||
					GetAxisValuesType() == ChartValueType.Date ||
					GetAxisValuesType() == ChartValueType.Time ||
                    GetAxisValuesType() == ChartValueType.DateTimeOffset)
				{
					return DateTimeIntervalType.Years;
				}
 
                return DateTimeIntervalType.Number;
            }
 
            return InternalIntervalType;
        }
 
        /// <summary>
        /// Gets axis values type depending on the series attached
        /// </summary>
        /// <returns>Axis values type.</returns>
        internal ChartValueType GetAxisValuesType()
        {
            ChartValueType type = ChartValueType.Double;
 
            // Check all series in this Common.Chart area attached to this axis
            if (this.Common != null && this.Common.DataManager.Series != null && ChartArea != null)
            {
                foreach (Series series in this.Common.DataManager.Series)
                {
                    bool seriesAttached = false;
 
                    // Check series name
                    if (series.ChartArea == ChartArea.Name && series.IsVisible())
                    {
                        // Check if axis type of series match
                        if (this.axisType == AxisName.X && series.XAxisType == AxisType.Primary)
                        {
#if SUBAXES
							if(((Axis)this).SubAxisName == series.XSubAxisName)
#endif // SUBAXES
                            {
                                seriesAttached = true;
                            }
                        }
                        else if (this.axisType == AxisName.X2 && series.XAxisType == AxisType.Secondary)
                        {
#if SUBAXES
							if(((Axis)this).SubAxisName == series.XSubAxisName)
#endif // SUBAXES
                            {
                                seriesAttached = true;
                            }
                        }
                        else if (this.axisType == AxisName.Y && series.YAxisType == AxisType.Primary)
                        {
#if SUBAXES
							if(((Axis)this).SubAxisName == series.YSubAxisName)
#endif // SUBAXES
                            {
                                seriesAttached = true;
                            }
                        }
                        else if (this.axisType == AxisName.Y2 && series.YAxisType == AxisType.Secondary)
                        {
#if SUBAXES
							if(((Axis)this).SubAxisName == series.YSubAxisName)
#endif // SUBAXES
                            {
                                seriesAttached = true;
                            }
                        }
                    }
 
                    // If series attached to this axes
                    if (seriesAttached)
                    {
                        if (this.axisType == AxisName.X || this.axisType == AxisName.X2)
                        {
                            type = series.XValueType;
                        }
                        else if (this.axisType == AxisName.Y || this.axisType == AxisName.Y2)
                        {
                            type = series.YValueType;
                        }
                        break;
                    }
                }
            }
            return type;
        }
 
        /// <summary>
        /// Returns Arrow size
        /// </summary>
        /// <param name="arrowOrientation">Return arrow orientation.</param>
        /// <returns>Size of arrow</returns>
        internal SizeF GetArrowSize(out ArrowOrientation arrowOrientation)
        {
            Axis opositeAxis;
            double size;
            double sizeOpposite;
            arrowOrientation = ArrowOrientation.Top;
 
            // Set the position of axis
            switch (AxisPosition)
            {
                case AxisPosition.Left:
 
                    if (isReversed)
                        arrowOrientation = ArrowOrientation.Bottom;
                    else
                        arrowOrientation = ArrowOrientation.Top;
 
                    break;
                case AxisPosition.Right:
 
                    if (isReversed)
                        arrowOrientation = ArrowOrientation.Bottom;
                    else
                        arrowOrientation = ArrowOrientation.Top;
 
                    break;
                case AxisPosition.Bottom:
 
                    if (isReversed)
                        arrowOrientation = ArrowOrientation.Left;
                    else
                        arrowOrientation = ArrowOrientation.Right;
 
                    break;
                case AxisPosition.Top:
 
                    if (isReversed)
                        arrowOrientation = ArrowOrientation.Left;
                    else
                        arrowOrientation = ArrowOrientation.Right;
 
                    break;
            }
 
            // Opposite axis. Arrow uses this axis to find 
            // a shift from Common.Chart area border. This shift 
            // depend on Tick mark size.
            switch (arrowOrientation)
            {
                case ArrowOrientation.Left:
                    opositeAxis = ChartArea.AxisX;
                    break;
                case ArrowOrientation.Right:
                    opositeAxis = ChartArea.AxisX2;
                    break;
                case ArrowOrientation.Top:
                    opositeAxis = ChartArea.AxisY2;
                    break;
                case ArrowOrientation.Bottom:
                    opositeAxis = ChartArea.AxisY;
                    break;
                default:
                    opositeAxis = ChartArea.AxisX;
                    break;
            }
 
            // Arrow size has to have the same shape when width and height 
            // are changed. When the picture is resized, width of the Common.Chart 
            // picture is used only for arrow size.
            if (arrowOrientation == ArrowOrientation.Top || arrowOrientation == ArrowOrientation.Bottom)
            {
                size = _lineWidth;
                sizeOpposite = (double)(_lineWidth) * Common.Width / Common.Height;
            }
            else
            {
                size = (double)(_lineWidth) * Common.Width / Common.Height;
                sizeOpposite = _lineWidth;
            }
 
            // Arrow is sharp triangle
            if (_arrowStyle == AxisArrowStyle.SharpTriangle)
            {
                // Arrow direction is vertical
                if (arrowOrientation == ArrowOrientation.Top || arrowOrientation == ArrowOrientation.Bottom)
                    return new SizeF((float)(size * 2), (float)(opositeAxis.MajorTickMark.Size + sizeOpposite * 4));
                else
                    // Arrow direction is horizontal
                    return new SizeF((float)(opositeAxis.MajorTickMark.Size + sizeOpposite * 4), (float)(size * 2));
            }
            // There is no arrow
            else if (_arrowStyle == AxisArrowStyle.None)
                return new SizeF(0, 0);
            else// Arrow is triangle or line type
            {
                // Arrow direction is vertical
                if (arrowOrientation == ArrowOrientation.Top || arrowOrientation == ArrowOrientation.Bottom)
                    return new SizeF((float)(size * 2), (float)(opositeAxis.MajorTickMark.Size + sizeOpposite * 2));
                else
                    // Arrow direction is horizontal
                    return new SizeF((float)(opositeAxis.MajorTickMark.Size + sizeOpposite * 2), (float)(size * 2));
            }
        }
 
 
        /// <summary>
        /// Checks if arrow with specified orientation will require space
        /// in axis with specified position
        /// </summary>
        /// <param name="arrowOrientation">Arrow orientation.</param>
        /// <param name="axisPosition">Axis position.</param>
        /// <returns>True if arrow will be drawn in axis space</returns>
        private bool IsArrowInAxis(ArrowOrientation arrowOrientation, AxisPosition axisPosition)
        {
            if (axisPosition == AxisPosition.Top && arrowOrientation == ArrowOrientation.Top)
                return true;
            else if (axisPosition == AxisPosition.Bottom && arrowOrientation == ArrowOrientation.Bottom)
                return true;
            if (axisPosition == AxisPosition.Left && arrowOrientation == ArrowOrientation.Left)
                return true;
            else if (axisPosition == AxisPosition.Right && arrowOrientation == ArrowOrientation.Right)
                return true;
 
            return false;
        }
 
 
        /// <summary>
        /// This function converts real Interval to 
        /// absolute Interval
        /// </summary>
        /// <param name="realInterval">A interval represented as double value</param>
        /// <returns>A interval represented in pixels</returns>
        internal float GetPixelInterval(double realInterval)
        {
            double chartAreaSize;
 
            // The Chart area pixel size as double
            if (AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom)
            {
                chartAreaSize = PlotAreaPosition.Right - PlotAreaPosition.X;
            }
            else
            {
                chartAreaSize = PlotAreaPosition.Bottom - PlotAreaPosition.Y;
            }
 
            // Avoid division by zero.
            if (ViewMaximum - ViewMinimum == 0)
            {
                return (float)(chartAreaSize / realInterval);
            }
 
            // The interval integer
            return (float)(chartAreaSize / (ViewMaximum - ViewMinimum) * realInterval);
        }
 
        /// <summary>
        /// Find if axis is on the edge of the Common.Chart plot area
        /// </summary>
        internal bool IsAxisOnAreaEdge
        {
            get
            {
                double edgePosition = 0;
                if (this.AxisPosition == AxisPosition.Bottom)
                {
                    edgePosition = PlotAreaPosition.Bottom;
                }
                else if (this.AxisPosition == AxisPosition.Left)
                {
                    edgePosition = PlotAreaPosition.X;
                }
                else if (this.AxisPosition == AxisPosition.Right)
                {
                    edgePosition = PlotAreaPosition.Right;
                }
                else if (this.AxisPosition == AxisPosition.Top)
                {
                    edgePosition = PlotAreaPosition.Y;
                }
 
                // DT Fix : problems with values on edge ~0.0005
                if (Math.Abs(GetAxisPosition() - edgePosition) < 0.0015)
                {
                    return true;
                }
 
                return false;
            }
        }
 
        /// <summary>
        /// Find axis position using crossing value.
        /// </summary>
        /// <returns>Relative position</returns>
        internal double GetAxisPosition()
        {
            return GetAxisPosition(false);
        }
 
        /// <summary>
        /// Find axis position using crossing value.
        /// </summary>
        /// <param name="ignoreCrossing">Axis crossing should be ignored.</param>
        /// <returns>Relative position</returns>
        virtual internal double GetAxisPosition(bool ignoreCrossing)
        {
            Axis axisOpposite = GetOppositeAxis();
 
            // Get axis position for circular Common.Chart area
            if (ChartArea != null && ChartArea.chartAreaIsCurcular)
            {
                return PlotAreaPosition.X + PlotAreaPosition.Width / 2f;
            }
 
            // Axis is not connected with any series. There is no maximum and minimum
            if (axisOpposite.maximum == axisOpposite.minimum ||
                double.IsNaN(axisOpposite.maximum) ||
                double.IsNaN(axisOpposite.minimum) ||
                maximum == minimum ||
                double.IsNaN(maximum) ||
                double.IsNaN(minimum))
            {
                switch (AxisPosition)
                {
                    case AxisPosition.Top:
                        return PlotAreaPosition.Y;
                    case AxisPosition.Bottom:
                        return PlotAreaPosition.Bottom;
                    case AxisPosition.Right:
                        return PlotAreaPosition.Right;
                    case AxisPosition.Left:
                        return PlotAreaPosition.X;
                }
            }
 
            // Auto crossing enabled
            if (Double.IsNaN(axisOpposite.crossing) || ignoreCrossing)
            {
                // Primary
                if (axisType == AxisName.X || axisType == AxisName.Y)
                    return axisOpposite.GetLinearPosition(axisOpposite.ViewMinimum);
                else // Secondary
                    return axisOpposite.GetLinearPosition(axisOpposite.ViewMaximum);
            }
            else // Auto crossing disabled
            {
                axisOpposite.crossing = axisOpposite.tempCrossing;
 
                if (axisOpposite.crossing < axisOpposite.ViewMinimum)
                {
                    axisOpposite.crossing = axisOpposite.ViewMinimum;
                }
                else if (axisOpposite.crossing > axisOpposite.ViewMaximum)
                {
                    axisOpposite.crossing = axisOpposite.ViewMaximum;
                }
            }
 
            return axisOpposite.GetLinearPosition(axisOpposite.crossing);
        }
 
        #endregion
 
        #region Axis 3D helper methods
 
        /// <summary>
        /// Returns angle between 2D axis line and it's 3D transformed projection.
        /// </summary>
        /// <returns>Axis projection angle.</returns>
        internal double GetAxisProjectionAngle()
        {
            // Get Z position
            bool axisOnEdge;
            float zPosition = GetMarksZPosition(out axisOnEdge);
 
            // Get axis position
            float axisPosition = (float)GetAxisPosition();
 
            // Create two points on the sides of the axis
            Point3D[] axisPoints = new Point3D[2];
            if (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom)
            {
                axisPoints[0] = new Point3D(0f, axisPosition, zPosition);
                axisPoints[1] = new Point3D(100f, axisPosition, zPosition);
            }
            else
            {
                axisPoints[0] = new Point3D(axisPosition, 0f, zPosition);
                axisPoints[1] = new Point3D(axisPosition, 100f, zPosition);
            }
 
            // Transform coordinates
            ChartArea.matrix3D.TransformPoints(axisPoints);
 
            // Round result
            axisPoints[0].X = (float)Math.Round(axisPoints[0].X, 4);
            axisPoints[0].Y = (float)Math.Round(axisPoints[0].Y, 4);
            axisPoints[1].X = (float)Math.Round(axisPoints[1].X, 4);
            axisPoints[1].Y = (float)Math.Round(axisPoints[1].Y, 4);
 
            // Calculate angle
            double angle = 0.0;
            if (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom)
            {
                angle = Math.Atan((axisPoints[1].Y - axisPoints[0].Y) / (axisPoints[1].X - axisPoints[0].X));
            }
            else
            {
                angle = Math.Atan((axisPoints[1].X - axisPoints[0].X) / (axisPoints[1].Y - axisPoints[0].Y));
            }
 
            // Conver to degrees
            return (angle * 180.0) / Math.PI;
        }
 
        #endregion
 
        #region IDisposable Members
 
        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_fontCache != null)
                {
                    _fontCache.Dispose();
                    _fontCache = null;
                }
 
                if (labelStyle != null)
                {
                    labelStyle.Dispose();
                    labelStyle = null;
                }
 
                if (_stripLines != null)
                {
                    _stripLines.Dispose();
                    _stripLines = null;
                }
                if (_customLabels != null)
                {
                    _customLabels.Dispose();
                    _customLabels = null;
                }
                if (tempLabels != null)
                {
                    tempLabels.Dispose();
                    tempLabels = null;
                }
#if Microsoft_CONTROL
                if (this.scrollBar != null)
                {
                    this.scrollBar.Dispose();
                    this.scrollBar = null;
                }
#endif // Microsoft_CONTROL
            }
            base.Dispose(disposing);
        }
 
 
        #endregion
 
    }
}