File: Common\General\SmartLabels.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:		SmartLabelStyle.cs
//
//  Namespace:	DataVisualization.Charting
//
//	Classes:	SmartLabelStyle, SmartLabelStyle
//
//  Purpose:	Smart Labels are used to avoid data point's labels 
//				overlapping. SmartLabelStyle class is exposed from 
//				the Series and Annotation classes and allows enabling 
//              and adjusting of SmartLabelStyle algorithm. SmartLabelStyle class 
//              exposes a set of helper utility methods and store 
//              information about labels in a chart area.
//
//	Reviewed:	AG - Microsoft 14, 2007
//
//===================================================================
 
#region Used namespaces
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.Drawing2D;
#if Microsoft_CONTROL

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;
using System.Windows.Forms.DataVisualization.Charting;
 
using System.Globalization;
using System.ComponentModel.Design.Serialization;
using System.Reflection;
using System.Windows.Forms.Design;
#else
	using System.Web;
	using System.Web.UI;
	using System.Globalization;
	using System.Web.UI.DataVisualization.Charting;
	using System.Web.UI.DataVisualization.Charting.Data;
	using System.Web.UI.DataVisualization.Charting.ChartTypes;
	using System.Web.UI.DataVisualization.Charting.Utilities;
	using System.Web.UI.DataVisualization.Charting.Borders3D;
#endif
 
#endregion
 
#if Microsoft_CONTROL
	namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
 
#endif
{
		#region Enumerations
 
		/// <summary>
		/// Line anchor cap style.
		/// </summary>
		[
		SRDescription("DescriptionAttributeLineAnchorCapStyle_LineAnchorCapStyle")
		]
		public enum LineAnchorCapStyle
		{
			/// <summary>
			/// No line anchor cap.
			/// </summary>
			None,
			/// <summary>
			/// Arrow line anchor cap.
			/// </summary>
			Arrow,
			/// <summary>
			/// Diamond line anchor cap.
			/// </summary>
			Diamond,
			/// <summary>
			/// Square line anchor cap.
			/// </summary>
			Square,
			/// <summary>
			/// Round line anchor cap.
			/// </summary>
			Round
		}
 
		/// <summary>
		/// Data point label callout style.
		/// </summary>
		[
		SRDescription("DescriptionAttributeLabelCalloutStyle_LabelCalloutStyle")
		]
		public enum LabelCalloutStyle
		{
			/// <summary>
			/// Label connected with the marker using just a line.
			/// </summary>
			None,
			/// <summary>
			/// Label is undelined and connected with the marker using a line.
			/// </summary>
			Underlined,
			/// <summary>
			/// Box is drawn around the label and it's connected with the marker using a line.
			/// </summary>
			Box
		}
 
		/// <summary>
		/// Data point label outside of the plotting area style.
		/// </summary>
		[
		SRDescription("DescriptionAttributeLabelOutsidePlotAreaStyle_LabelOutsidePlotAreaStyle")
		]
		public enum LabelOutsidePlotAreaStyle
		{
			/// <summary>
			/// Labels can be positioned outside of the plotting area.
			/// </summary>
			Yes,
			/// <summary>
			/// Labels can not be positioned outside of the plotting area.
			/// </summary>
			No,
			/// <summary>
			/// Labels can be partially outside of the plotting area.
			/// </summary>
			Partial
		}
 
		#endregion
 
		/// <summary>
        /// SmartLabelStyle class is used to enable and configure the 
        /// SmartLabelStyle algorithm for data point labels and annotations. 
        /// In most of the cases it is enough just to enable the algorithm, 
        /// but this class also contains properties which allow controlling 
        /// how the labels are moved around to avoid collisions. Visual 
        /// appearance of callouts can also be set through this class.
		/// </summary>
		[
		DefaultProperty("Enabled"),
		SRDescription("DescriptionAttributeSmartLabelsStyle_SmartLabelsStyle"),
        TypeConverter(typeof(NoNameExpandableObjectConverter))
		]
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
        public class SmartLabelStyle
		{
			#region Fields
 
			// Reference to the series this style belongs to
			internal	object					chartElement = null;
 
			// Indicates if SmartLabelStyle algorithm is enabled.
			private		bool					_enabled = true;
 
			// Indicates that marker overlapping by label is allowed.
			private		bool					_isMarkerOverlappingAllowed = false;
 
			// Indicates that overlapped labels that can't be repositioned will be hidden.
			private		bool					_isOverlappedHidden = true;
 
			// Possible moving directions for the overlapped SmartLabelStyle.
			private		LabelAlignmentStyles			_movingDirection = LabelAlignmentStyles.Top | LabelAlignmentStyles.Bottom | LabelAlignmentStyles.Right | LabelAlignmentStyles.Left | LabelAlignmentStyles.TopLeft | LabelAlignmentStyles.TopRight | LabelAlignmentStyles.BottomLeft | LabelAlignmentStyles.BottomRight;
 
			// Minimum distance the overlapped SmartLabelStyle can be moved from the marker. Distance is measured in pixels.
			private		double					_minMovingDistance = 0.0;
 
			// Maximum distance the overlapped SmartLabelStyle can be moved from the marker. Distance is measured in pixels.
			private		double					_maxMovingDistance = 30.0;
 
			// Defines if SmartLabelStyle are allowed to be drawn outside of the plotting area.
			private	LabelOutsidePlotAreaStyle	_allowOutsidePlotArea = LabelOutsidePlotAreaStyle.Partial;
 
			// Callout style of the repositioned SmartLabelStyle.
			private		LabelCalloutStyle		_calloutStyle = LabelCalloutStyle.Underlined;
 
			// Label callout line color.
			private		Color					_calloutLineColor = Color.Black;
 
			// Label callout line style.
			private		ChartDashStyle			_calloutLineDashStyle = ChartDashStyle.Solid;
 
			// Label callout back color. Applies to the Box style only!
			private		Color					_calloutBackColor = Color.Transparent;
 
			// Label callout line width.
			private		int						_calloutLineWidth = 1;
 
			// Label callout line anchor cap.
			private		LineAnchorCapStyle			_calloutLineAnchorCapStyle = LineAnchorCapStyle.Arrow;
			
			#endregion
 
			#region Constructors and initialization
 
			/// <summary>
			/// Default public constructor.
			/// </summary>
			public SmartLabelStyle()
			{
				this.chartElement = null;
			}
 
			/// <summary>
			/// Constructor.
			/// </summary>
			/// <param name="chartElement">Chart element this style belongs to.</param>
			internal SmartLabelStyle(Object chartElement)
			{
				this.chartElement = chartElement;
			}
 
			#endregion
 
			#region Properties
 
			/// <summary>
			/// SmartLabelStyle algorithm enabled flag.
			/// </summary>
			[
			SRCategory("CategoryAttributeMisc"),
			Bindable(true),
			DefaultValue(true),
			SRDescription("DescriptionAttributeEnabled13"),
			ParenthesizePropertyNameAttribute(true),
			]
			virtual public bool Enabled
			{
				get
				{
					return _enabled;
				}
				set
				{
					_enabled = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Indicates that marker overlapping by label is allowed.
			/// </summary>
			[
			SRCategory("CategoryAttributeMisc"),
			Bindable(true),
			DefaultValue(false),
			SRDescription("DescriptionAttributeMarkerOverlapping"),
			]
			virtual public bool IsMarkerOverlappingAllowed
			{
				get
				{
					return _isMarkerOverlappingAllowed;
				}
				set
				{
					_isMarkerOverlappingAllowed = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Indicates that overlapped labels that can't be repositioned will be hidden.
			/// </summary>
			[
			SRCategory("CategoryAttributeMisc"),
			Bindable(true),
			DefaultValue(true),
			SRDescription("DescriptionAttributeHideOverlapped"),
			]
			virtual public bool IsOverlappedHidden
			{
				get
				{
					return _isOverlappedHidden;
				}
				set
				{
					_isOverlappedHidden = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Possible moving directions for the overlapped SmartLabelStyle.
			/// </summary>
			[
			SRCategory("CategoryAttributeMisc"),
			Bindable(true),
			DefaultValue(typeof(LabelAlignmentStyles), "Top, Bottom, Right, Left, TopLeft, TopRight, BottomLeft, BottomRight"),
			SRDescription("DescriptionAttributeMovingDirection"),
            Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base),
			]
			virtual public LabelAlignmentStyles MovingDirection
			{
				get
				{
					return _movingDirection;
				}
				set
				{
					if(value == 0)
					{
                        throw (new InvalidOperationException(SR.ExceptionSmartLabelsDirectionUndefined));
					}
 
					_movingDirection = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Minimum distance the overlapped SmartLabelStyle can be moved from the marker. Distance is measured in pixels.
			/// </summary>
			[
			SRCategory("CategoryAttributeMisc"),
			Bindable(true),
			DefaultValue(0.0),
			SRDescription("DescriptionAttributeMinMovingDistance"),
			]
			virtual public double MinMovingDistance
			{
				get
				{
					return _minMovingDistance;
				}
				set
				{
					if(value < 0)
					{
                        throw (new InvalidOperationException(SR.ExceptionSmartLabelsMinMovingDistanceIsNegative));
					}
					_minMovingDistance = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Maximum distance the overlapped SmartLabelStyle can be moved from the marker. Distance is measured in pixels.
			/// </summary>
			[
			SRCategory("CategoryAttributeMisc"),
			Bindable(true),
			DefaultValue(30.0),
			SRDescription("DescriptionAttributeMaxMovingDistance"),
			]
			virtual public double MaxMovingDistance
			{
				get
				{
					return _maxMovingDistance;
				}
				set
				{
					if(value < 0 )
					{
                        throw (new InvalidOperationException(SR.ExceptionSmartLabelsMaxMovingDistanceIsNegative));
					}
					_maxMovingDistance = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Defines if SmartLabelStyle are allowed to be drawn outside of the plotting area.
			/// </summary>
			[
			SRCategory("CategoryAttributeMisc"),
			Bindable(true),
			DefaultValue(LabelOutsidePlotAreaStyle.Partial),
			SRDescription("DescriptionAttributeAllowOutsidePlotArea"),
			]
			virtual public LabelOutsidePlotAreaStyle AllowOutsidePlotArea
			{
				get
				{
					return _allowOutsidePlotArea;
				}
				set
				{
					_allowOutsidePlotArea = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Callout style of the repositioned SmartLabelStyle.
			/// </summary>
			[
			SRCategory("CategoryAttributeMisc"),
			Bindable(true),
			DefaultValue(LabelCalloutStyle.Underlined),
			SRDescription("DescriptionAttributeCalloutStyle3"),
			]
			virtual public LabelCalloutStyle CalloutStyle
			{
				get
				{
					return _calloutStyle;
				}
				set
				{
					_calloutStyle = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Label callout line color.
			/// </summary>
			[
			SRCategory("CategoryAttributeAppearance"),
			Bindable(true),
			DefaultValue(typeof(Color), "Black"),
            SRDescription("DescriptionAttributeCalloutLineColor"),
            TypeConverter(typeof(ColorConverter)),
            Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
			]
			virtual public Color CalloutLineColor
			{
				get
				{
					return _calloutLineColor;
				}
				set
				{
					_calloutLineColor = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Label callout line style.
			/// </summary>
			[
			SRCategory("CategoryAttributeAppearance"),
			Bindable(true),
			DefaultValue(ChartDashStyle.Solid),
            SRDescription("DescriptionAttributeLineDashStyle"),
			#if !Microsoft_CONTROL
			PersistenceMode(PersistenceMode.Attribute)
			#endif
			]
			virtual public ChartDashStyle CalloutLineDashStyle
			{
				get
				{
					return _calloutLineDashStyle;
				}
				set
				{
					_calloutLineDashStyle = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Label callout back color. Applies to the Box style only!
			/// </summary>
			[
			SRCategory("CategoryAttributeAppearance"),
			Bindable(true),
			DefaultValue(typeof(Color), "Transparent"),
            SRDescription("DescriptionAttributeCalloutBackColor"),
            TypeConverter(typeof(ColorConverter)),
            Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
			]
			virtual public Color CalloutBackColor
			{
				get
				{
					return _calloutBackColor;
				}
				set
				{
					_calloutBackColor = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Label callout line width.
			/// </summary>
			[
			SRCategory("CategoryAttributeAppearance"),
			Bindable(true),
			DefaultValue(1),
            SRDescription("DescriptionAttributeLineWidth"),
			]
			virtual public int CalloutLineWidth
			{
				get
				{
					return _calloutLineWidth;
				}
				set
				{
					_calloutLineWidth = value;
					Invalidate();
				}
			}
 
			/// <summary>
			/// Label callout line anchor cap.
			/// </summary>
			[
			SRCategory("CategoryAttributeAppearance"),
			Bindable(true),
			DefaultValue(LineAnchorCapStyle.Arrow),
			SRDescription(SR.Keys.DescriptionAttributeCalloutLineAnchorCap),
			]
			virtual public LineAnchorCapStyle CalloutLineAnchorCapStyle
			{
				get
				{
					return _calloutLineAnchorCapStyle;
				}
				set
				{
					_calloutLineAnchorCapStyle = value;
					Invalidate();
				}
			}
 
			#endregion
 
			#region Methods
 
			/// <summary>
			/// Invalidates ----osiated chart element.
			/// </summary>
			private void Invalidate()
			{
				if(chartElement != null)
				{
					if(chartElement is Series)
					{
						((Series)chartElement).Invalidate(false, false);
					}
 
					else if(chartElement is Annotation)
					{
						((Annotation)chartElement).Invalidate();
					}
 
				}
			}
 
			#endregion 
		}
 
		/// <summary>
        /// SmartLabelStyle class implements the SmartLabelStyle algorithm for the 
        /// data series points. It keeps track of all labels drawn and 
        /// detects their collisions. When labels collision is detected 
        /// the algorithm tries to resolve it by repositioning the labels. 
        /// If label can not be repositioned it maybe hidden depending on 
        /// the current settings.
		/// </summary>
		[
		SRDescription("DescriptionAttributeSmartLabels_SmartLabels"),
		]
		internal class SmartLabel
		{
			#region Fields
 
			// List of all SmartLabelStyle positions in the area
			internal		ArrayList			smartLabelsPositions = null;
 
			// Indicates that not a single collision is allowed
			internal		bool				checkAllCollisions = false;
 
			// Number of positions in array for the markers
			internal		int					markersCount = 0;
 
			#endregion
 
			#region Constructors and initialization
 
			/// <summary>
			/// Default public constructor.
			/// </summary>
			public SmartLabel()
			{
			}
 
			#endregion
 
			#region Methods
 
			/// <summary>
			/// Reset SmartLabelStyle object.
			/// </summary>
			internal void Reset()
			{
				// Re-initialize list of labels position
				smartLabelsPositions = new ArrayList();
			}
 
			/// <summary>
			/// Process single SmartLabelStyle by adjusting it's position in case of collision.
			/// </summary>
			/// <param name="common">Reference to common elements.</param>
			/// <param name="graph">Reference to chart graphics object.</param>
			/// <param name="area">Chart area.</param>
			/// <param name="smartLabelStyle">Smart labels style.</param>
			/// <param name="labelPosition">Original label position.</param>
			/// <param name="labelSize">Label text size.</param>
			/// <param name="format">Label string format.</param>
			/// <param name="markerPosition">Marker position.</param>
			/// <param name="markerSize">Marker size.</param>
			/// <param name="labelAlignment">Original label alignment.</param>
			/// <returns>Adjusted position of the label.</returns>
			internal PointF AdjustSmartLabelPosition(
				CommonElements common, 
				ChartGraphics graph, 
				ChartArea area,
				SmartLabelStyle smartLabelStyle,
				PointF labelPosition, 
				SizeF labelSize,
				StringFormat format,
				PointF markerPosition, 
				SizeF markerSize,
				LabelAlignmentStyles labelAlignment)
			{
				return AdjustSmartLabelPosition(
					common, 
					graph, 
					area,
					smartLabelStyle,
					labelPosition, 
					labelSize,
					format,
					markerPosition, 
					markerSize,
					labelAlignment,
					false);
			}
 
			/// <summary>
			/// Process single SmartLabelStyle by adjusting it's position in case of collision.
			/// </summary>
			/// <param name="common">Reference to common elements.</param>
			/// <param name="graph">Reference to chart graphics object.</param>
			/// <param name="area">Chart area.</param>
			/// <param name="smartLabelStyle">Smart labels style.</param>
			/// <param name="labelPosition">Original label position.</param>
			/// <param name="labelSize">Label text size.</param>
			/// <param name="format">Label string format.</param>
			/// <param name="markerPosition">Marker position.</param>
			/// <param name="markerSize">Marker size.</param>
			/// <param name="labelAlignment">Original label alignment.</param>
			/// <param name="checkCalloutLineOverlapping">Indicates that labels overlapping by callout line must be checked.</param>
			/// <returns>Adjusted position of the label.</returns>
			internal PointF AdjustSmartLabelPosition(
				CommonElements common, 
				ChartGraphics graph, 
				ChartArea area,
				SmartLabelStyle smartLabelStyle,
				PointF labelPosition, 
				SizeF labelSize,
				StringFormat format,
				PointF markerPosition, 
				SizeF markerSize,
				LabelAlignmentStyles labelAlignment,
				bool checkCalloutLineOverlapping)
			{
				// Check if SmartLabelStyle are enabled
				if(smartLabelStyle.Enabled)
				{
					bool	labelMovedAway = false;
 
					// Add series markers positions to avoid their overlapping
					bool rememberMarkersCount = (this.smartLabelsPositions.Count == 0);
					AddMarkersPosition(common, area);
					if(rememberMarkersCount)
					{
						this.markersCount = this.smartLabelsPositions.Count;
					}
 
					// Check label collision
					if(IsSmartLabelCollide(
						common, 
						graph, 
						area, 
						smartLabelStyle, 
						labelPosition, 
						labelSize, 
						markerPosition,
						format,
						labelAlignment, 
						checkCalloutLineOverlapping))
					{
						// Try to find a new position for the SmartLabelStyle
						labelMovedAway = FindNewPosition(
							common,
							graph, 
							area, 
							smartLabelStyle, 
							ref labelPosition,
							labelSize,
							format,
							markerPosition, 
							ref markerSize,
							ref labelAlignment,
							checkCalloutLineOverlapping);
 
						// Draw label callout if label was moved away or 
						// it's displayed in the corners of the marker
						if(labelMovedAway || 
							(labelAlignment == LabelAlignmentStyles.BottomLeft ||
							labelAlignment == LabelAlignmentStyles.BottomRight ||
							labelAlignment == LabelAlignmentStyles.TopLeft ||
							labelAlignment == LabelAlignmentStyles.TopRight))
						{
							if(!labelPosition.IsEmpty)
							{
								DrawCallout(
									common,
									graph, 
									area, 
									smartLabelStyle, 
									labelPosition,
									labelSize,
									format,
									markerPosition, 
									markerSize,
									labelAlignment);
							}
						}
					}
 
					// Add label position into the list
					AddSmartLabelPosition(graph, labelPosition, labelSize, format);
				}
 
				// Return label position
				return labelPosition;
			}	
 
 
			/// <summary>
			/// Process single SmartLabelStyle by adjusting it's position in case of collision.
			/// </summary>
			/// <param name="common">Reference to common elements.</param>
			/// <param name="graph">Reference to chart graphics object.</param>
			/// <param name="area">Chart area.</param>
			/// <param name="smartLabelStyle">Smart labels style.</param>
			/// <param name="labelPosition">Original label position.</param>
			/// <param name="labelSize">Label text size.</param>
			/// <param name="format">Label string format.</param>
			/// <param name="markerPosition">Marker position.</param>
			/// <param name="markerSize">Marker size.</param>
			/// <param name="labelAlignment">Label alignment.</param>
			/// <param name="checkCalloutLineOverlapping">Indicates that labels overlapping by callout line must be checked.</param>
			/// <returns>True if label was moved away from the marker.</returns>
			private bool FindNewPosition(
				CommonElements common, 
				ChartGraphics graph, 
				ChartArea area,
				SmartLabelStyle smartLabelStyle,
				ref PointF labelPosition, 
				SizeF labelSize,
				StringFormat format,
				PointF markerPosition, 
				ref SizeF markerSize,
				ref LabelAlignmentStyles labelAlignment,
				bool checkCalloutLineOverlapping)
			{
				SizeF	newMarkerSize = SizeF.Empty;
				PointF	newLabelPosition = PointF.Empty;
				int		positionIndex = 0;
				float	labelMovement = 0f;
				bool	labelMovedAway = false;
				LabelAlignmentStyles[] positions = new LabelAlignmentStyles[] {
									LabelAlignmentStyles.Top,
									LabelAlignmentStyles.Bottom,
									LabelAlignmentStyles.Left,
									LabelAlignmentStyles.Right,
									LabelAlignmentStyles.TopLeft,																		
									LabelAlignmentStyles.TopRight,
									LabelAlignmentStyles.BottomLeft,
									LabelAlignmentStyles.BottomRight,
									LabelAlignmentStyles.Center
								};
 
				// Get relative size of single pixel
				SizeF pixelSize = graph.GetRelativeSize(new SizeF(1f, 1f));
 
				// Try to find a new position for the label
				bool	positionFound = false;
				float	movingStep = 2f;
				float	minMove = (float)Math.Min(smartLabelStyle.MinMovingDistance, smartLabelStyle.MaxMovingDistance);
				float	maxMove = (float)Math.Max(smartLabelStyle.MinMovingDistance, smartLabelStyle.MaxMovingDistance);
				for(labelMovement = minMove; !positionFound && labelMovement <= maxMove; labelMovement += movingStep)
				{
					// Move label by increasing marker size by 4 pixels
					newMarkerSize = new SizeF(
						markerSize.Width + labelMovement*(pixelSize.Width * 2f), 
						markerSize.Height + labelMovement*(pixelSize.Height * 2f));
 
					// Loop through different alignment types
					for(positionIndex = 0; positionIndex < positions.Length; positionIndex++)
					{
						// Center label alignment should only be tried once!
						if(positions[positionIndex] == LabelAlignmentStyles.Center && labelMovement != minMove)
						{
							continue;
						}
 
						// Check if this alignment is valid
						if((smartLabelStyle.MovingDirection & positions[positionIndex]) == positions[positionIndex])
						{
							// Calculate new position of the label
							newLabelPosition = CalculatePosition(
								positions[positionIndex],
								markerPosition,
								newMarkerSize,
								labelSize,
								ref format);
					
							// Check new position collision
							if(!IsSmartLabelCollide(
								common, 
								null, 
								area, 
								smartLabelStyle, 
								newLabelPosition, 
								labelSize, 
								markerPosition,
								format,
								positions[positionIndex],
								checkCalloutLineOverlapping))
							{
								positionFound = true;
								labelMovedAway = (labelMovement == 0f) ? false : true;
								break;
							}
						}
					}
				}
				
				// Set new data if new label position was found
				if(positionFound)
				{
					markerSize = newMarkerSize;
					labelPosition = newLabelPosition;
					labelAlignment = positions[positionIndex];
				}
 
				// DEBUG code
#if DEBUG
				if(common.Chart.ShowDebugMarkings)
				{
					RectangleF	lp = GetLabelPosition(graph, labelPosition, labelSize, format, false);
					if(positionFound)
					{
						graph.Graphics.DrawRectangle(Pens.Green, Rectangle.Round(graph.GetAbsoluteRectangle(lp)));
					}
					else
					{
						graph.Graphics.DrawRectangle(new Pen(Color.Magenta, 3), Rectangle.Round(graph.GetAbsoluteRectangle(lp)));
					}
				}
#endif
				// Do not draw overlapped labels that can't be repositioned
				if(!positionFound && smartLabelStyle.IsOverlappedHidden)
				{
					labelPosition = PointF.Empty;
				}
 
	
				return (labelMovedAway && positionFound) ? true : false;
			}
 
			/// <summary>
			/// Process single SmartLabelStyle by adjusting it's position in case of collision.
			/// </summary>
			/// <param name="common">Reference to common elements.</param>
			/// <param name="graph">Reference to chart graphics object.</param>
			/// <param name="area">Chart area.</param>
			/// <param name="smartLabelStyle">Smart labels style.</param>
			/// <param name="labelPosition">Original label position.</param>
			/// <param name="labelSize">Label text size.</param>
			/// <param name="format">Label string format.</param>
			/// <param name="markerPosition">Marker position.</param>
			/// <param name="markerSize">Marker size.</param>
			/// <param name="labelAlignment">Label alignment.</param>
			/// <returns>Adjusted position of the label.</returns>
			virtual internal void DrawCallout(
				CommonElements common, 
				ChartGraphics graph, 
				ChartArea area,
				SmartLabelStyle smartLabelStyle,
				PointF labelPosition, 
				SizeF labelSize,
				StringFormat format,
				PointF markerPosition, 
				SizeF markerSize,
				LabelAlignmentStyles labelAlignment)
			{
				// Calculate label position rectangle
				RectangleF	labelRectAbs = graph.GetAbsoluteRectangle(
					GetLabelPosition(graph, labelPosition, labelSize, format, true));
 
				// Create callout pen
				Pen calloutPen = new Pen(smartLabelStyle.CalloutLineColor, smartLabelStyle.CalloutLineWidth);
				calloutPen.DashStyle = graph.GetPenStyle(smartLabelStyle.CalloutLineDashStyle);
 
				// Draw callout frame
				if(smartLabelStyle.CalloutStyle == LabelCalloutStyle.Box)
				{
					// Fill callout box around the label
					if(smartLabelStyle.CalloutBackColor != Color.Transparent)
					{
                        using (Brush calloutBrush = new SolidBrush(smartLabelStyle.CalloutBackColor))
                        {
                            graph.FillRectangle(calloutBrush, labelRectAbs);
                        }
					}
 
					// Draw box border
					graph.DrawRectangle(calloutPen, labelRectAbs.X, labelRectAbs.Y, labelRectAbs.Width, labelRectAbs.Height);
				}
 
				else if(smartLabelStyle.CalloutStyle == LabelCalloutStyle.Underlined)
				{
					if(labelAlignment == LabelAlignmentStyles.Right)
					{
						// Draw line to the left of label's text
						graph.DrawLine(calloutPen, labelRectAbs.X, labelRectAbs.Top, labelRectAbs.X, labelRectAbs.Bottom);
					}
					else if(labelAlignment == LabelAlignmentStyles.Left)
					{
						// Draw line to the right of label's text
						graph.DrawLine(calloutPen, labelRectAbs.Right, labelRectAbs.Top, labelRectAbs.Right, labelRectAbs.Bottom);
					}
					else if(labelAlignment == LabelAlignmentStyles.Bottom)
					{
						// Draw line on top of the label's text
						graph.DrawLine(calloutPen, labelRectAbs.X, labelRectAbs.Top, labelRectAbs.Right, labelRectAbs.Top);
					}
					else
					{
						// Draw line under the label's text
						graph.DrawLine(calloutPen, labelRectAbs.X, labelRectAbs.Bottom, labelRectAbs.Right, labelRectAbs.Bottom);
					}
				}
 
				// Calculate connector line point on the label
				PointF	connectorPosition = graph.GetAbsolutePoint(labelPosition);
				if(labelAlignment == LabelAlignmentStyles.Top)
				{
					connectorPosition.Y = labelRectAbs.Bottom;
				}
				else if(labelAlignment == LabelAlignmentStyles.Bottom)
				{
					connectorPosition.Y = labelRectAbs.Top;
				}
 
				if(smartLabelStyle.CalloutStyle == LabelCalloutStyle.Underlined)
				{
					if(labelAlignment == LabelAlignmentStyles.TopLeft ||
						labelAlignment == LabelAlignmentStyles.TopRight ||
						labelAlignment == LabelAlignmentStyles.BottomLeft ||
						labelAlignment == LabelAlignmentStyles.BottomRight)
					{
						connectorPosition.Y = labelRectAbs.Bottom;
					}
				}
 
				// Apply anchor cap settings
				if(smartLabelStyle.CalloutLineAnchorCapStyle == LineAnchorCapStyle.Arrow)
				{
					//calloutPen.StartCap = LineCap.ArrowAnchor;
					calloutPen.StartCap = LineCap.Custom;
					calloutPen.CustomStartCap = new AdjustableArrowCap(calloutPen.Width + 2, calloutPen.Width + 3, true);
				}
				else if(smartLabelStyle.CalloutLineAnchorCapStyle == LineAnchorCapStyle.Diamond)
				{
					calloutPen.StartCap = LineCap.DiamondAnchor;
				}
				else if(smartLabelStyle.CalloutLineAnchorCapStyle == LineAnchorCapStyle.Round)
				{
					calloutPen.StartCap = LineCap.RoundAnchor;
				}
				else if(smartLabelStyle.CalloutLineAnchorCapStyle == LineAnchorCapStyle.Square)
				{
					calloutPen.StartCap = LineCap.SquareAnchor;
				}
 
				// Draw connection line between marker position and label
				PointF	markerPositionAbs = graph.GetAbsolutePoint(markerPosition);
				graph.DrawLine(
					calloutPen, 
					markerPositionAbs.X, 
					markerPositionAbs.Y, 
					connectorPosition.X, 
					connectorPosition.Y);
			}
				
			/// <summary>
			/// Checks SmartLabelStyle collision.
			/// </summary>
			/// <param name="common">Reference to common elements.</param>
			/// <param name="graph">Reference to chart graphics object.</param>
			/// <param name="area">Chart area.</param>
			/// <param name="smartLabelStyle">Smart labels style.</param>
			/// <param name="position">Original label position.</param>
			/// <param name="size">Label text size.</param>
			/// <param name="markerPosition">Marker position.</param>
			/// <param name="format">Label string format.</param>
			/// <param name="labelAlignment">Label alignment.</param>
			/// <param name="checkCalloutLineOverlapping">Indicates that labels overlapping by callout line must be checked.</param>
			/// <returns>True if label collides.</returns>
			virtual internal bool IsSmartLabelCollide(
				CommonElements common, 
				ChartGraphics graph, 
				ChartArea area,
				SmartLabelStyle smartLabelStyle,
				PointF position, 
				SizeF size,
				PointF markerPosition,
				StringFormat format,
				LabelAlignmentStyles labelAlignment,
				bool checkCalloutLineOverlapping)
			{
				bool	collisionDetected = false;
 
				// Calculate label position rectangle
				RectangleF	labelPosition = GetLabelPosition(graph, position, size, format, false);
 
				// Check if label goes outside of the chart picture
				if(labelPosition.X < 0f || labelPosition.Y < 0f ||
					labelPosition.Bottom > 100f || labelPosition.Right > 100f)
				{
#if DEBUG					
					// DEBUG: Mark collided labels
                    if (graph != null && common!=null && common.Chart!=null && common.Chart.ShowDebugMarkings)
					{
						graph.Graphics.DrawRectangle(Pens.Cyan, Rectangle.Round(graph.GetAbsoluteRectangle(labelPosition)));
					}
#endif					
					collisionDetected = true;
				}
 
 
				// Check if label is drawn outside of plotting area (collides with axis?).
				if(!collisionDetected && area != null)
				{
					if(area.chartAreaIsCurcular)
					{
						using( GraphicsPath areaPath = new GraphicsPath() )
						{
							// Add circular shape of the area into the graphics path
							areaPath.AddEllipse(area.PlotAreaPosition.ToRectangleF());
 
							if(smartLabelStyle.AllowOutsidePlotArea == LabelOutsidePlotAreaStyle.Partial)
							{
								PointF	centerPos = new PointF(
									labelPosition.X + labelPosition.Width/2f,
									labelPosition.Y + labelPosition.Height/2f);
								if(!areaPath.IsVisible(centerPos))
								{
									// DEBUG: Mark collided labels
#if DEBUG							
									if(graph != null && common.Chart.ShowDebugMarkings)
									{
										graph.Graphics.DrawRectangle(Pens.Cyan, Rectangle.Round(graph.GetAbsoluteRectangle(labelPosition)));
									}
#endif
									collisionDetected = true;
								}
							}
							else if(smartLabelStyle.AllowOutsidePlotArea == LabelOutsidePlotAreaStyle.No)
							{
								if(!areaPath.IsVisible(labelPosition.Location) ||
									!areaPath.IsVisible(new PointF(labelPosition.Right, labelPosition.Y)) ||
									!areaPath.IsVisible(new PointF(labelPosition.Right, labelPosition.Bottom)) ||
									!areaPath.IsVisible(new PointF(labelPosition.X, labelPosition.Bottom)) )
								{
									// DEBUG: Mark collided labels
#if DEBUG
									if(graph != null && common.Chart.ShowDebugMarkings)
									{
										graph.Graphics.DrawRectangle(Pens.Cyan, Rectangle.Round(graph.GetAbsoluteRectangle(labelPosition)));
									}
#endif
									collisionDetected = true;
								}
							}
						}
					}
					else
					{
						if(smartLabelStyle.AllowOutsidePlotArea == LabelOutsidePlotAreaStyle.Partial)
						{
							PointF	centerPos = new PointF(
								labelPosition.X + labelPosition.Width/2f,
								labelPosition.Y + labelPosition.Height/2f);
							if(!area.PlotAreaPosition.ToRectangleF().Contains(centerPos))
							{
								// DEBUG: Mark collided labels
#if DEBUG							
								if(graph != null && common.Chart.ShowDebugMarkings)
								{
									graph.Graphics.DrawRectangle(Pens.Cyan, Rectangle.Round(graph.GetAbsoluteRectangle(labelPosition)));
								}
#endif
								collisionDetected = true;
							}
						}
						else if(smartLabelStyle.AllowOutsidePlotArea == LabelOutsidePlotAreaStyle.No)
						{
							if(!area.PlotAreaPosition.ToRectangleF().Contains(labelPosition))
							{
								// DEBUG: Mark collided labels
#if DEBUG
								if(graph != null && common.Chart.ShowDebugMarkings)
								{
									graph.Graphics.DrawRectangle(Pens.Cyan, Rectangle.Round(graph.GetAbsoluteRectangle(labelPosition)));
								}
#endif
								collisionDetected = true;
							}
						}
					}
				}
 
				// Check if 1 collisuion is aceptable in case of cennter alignment
				bool	allowOneCollision = 
					(labelAlignment == LabelAlignmentStyles.Center && !smartLabelStyle.IsMarkerOverlappingAllowed) ? true : false;
				if(this.checkAllCollisions)
				{
					allowOneCollision = false;
				}
 
 
				// Loop through all smart label positions
				if(!collisionDetected && this.smartLabelsPositions != null)
				{
					int index = -1;
					foreach(RectangleF pos in this.smartLabelsPositions)
					{
						// Increase index
						++index;
 
						// Check if label collide with other labels or markers.
						bool collision = pos.IntersectsWith(labelPosition);
 
						// Check if label callout line collide with other labels or markers.
						// Line may overlap markers!
						if(!collision && 
							checkCalloutLineOverlapping &&
							index >= markersCount)
						{
							PointF labelCenter = new PointF(
								labelPosition.X + labelPosition.Width / 2f,
								labelPosition.Y + labelPosition.Height / 2f);
							if(LineIntersectRectangle(pos, markerPosition, labelCenter))
							{
								collision = true;
							}
						}
 
						// Collision detected
						if(collision)
						{
							// Check if 1 collision allowed
							if(allowOneCollision)
							{
								allowOneCollision = false;
								continue;
							}
 
							// DEBUG: Mark collided labels
#if DEBUG							
							if(graph != null &&
								common.ChartPicture != null && 
								common.ChartPicture.ChartGraph != null &&
								common.Chart.ShowDebugMarkings)
							{
								common.ChartPicture.ChartGraph.Graphics.DrawRectangle(Pens.Blue, Rectangle.Round(common.ChartPicture.ChartGraph.GetAbsoluteRectangle(pos)));
								common.ChartPicture.ChartGraph.Graphics.DrawRectangle(Pens.Red, Rectangle.Round(common.ChartPicture.ChartGraph.GetAbsoluteRectangle(labelPosition)));
							}
#endif
							collisionDetected = true;
							break;
						}
					}
				}
 
				return collisionDetected;
			}
 
			/// <summary>
			/// Checks if rectangle intersected by the line.
			/// </summary>
			/// <param name="rect">Rectangle to be tested.</param>
			/// <param name="point1">First line point.</param>
			/// <param name="point2">Second line point.</param>
			/// <returns>True if line intersects rectangle.</returns>
			private bool LineIntersectRectangle(RectangleF rect, PointF point1, PointF point2)
			{
				// Check for horizontal line
				if(point1.X == point2.X)
				{
					if(point1.X >= rect.X && point1.X <= rect.Right)
					{
						if(point1.Y < rect.Y && point2.Y < rect.Y)
						{
							return false;
						}
						if(point1.Y > rect.Bottom && point2.Y > rect.Bottom)
						{
							return false;
						}
						return true;
					}
					return false;
				}
 
				// Check for vertical line
				if(point1.Y == point2.Y)
				{
					if(point1.Y >= rect.Y && point1.Y <= rect.Bottom)
					{
						if(point1.X < rect.X && point2.X < rect.X)
						{
							return false;
						}
						if(point1.X > rect.Right && point2.X > rect.Right)
						{
							return false;
						}
						return true;
					}
					return false;
 
				}
 
				// Check if line completly outside rectangle
				if(point1.X < rect.X && point2.X < rect.X)
				{
					return false;
				}
				else if(point1.X > rect.Right && point2.X > rect.Right)
				{
					return false;
				}
				else if(point1.Y < rect.Y && point2.Y < rect.Y)
				{
					return false;
				}
				else if(point1.Y > rect.Bottom && point2.Y > rect.Bottom)
				{
					return false;
				}
 
				// Check if one of the points inside rectangle
				if( rect.Contains(point1) ||
					rect.Contains(point2) )
				{
					return true;
				}
 
				// Calculate intersection point of the line with each side of the rectangle
				PointF intersection = CalloutAnnotation.GetIntersectionY(point1, point2, rect.Y);
				if( rect.Contains(intersection))
				{
					return true;
				}
				intersection = CalloutAnnotation.GetIntersectionY(point1, point2, rect.Bottom);
				if( rect.Contains(intersection))
				{
					return true;
				}
				intersection = CalloutAnnotation.GetIntersectionX(point1, point2, rect.X);
				if( rect.Contains(intersection))
				{
					return true;
				}
				intersection = CalloutAnnotation.GetIntersectionX(point1, point2, rect.Right);
				if( rect.Contains(intersection))
				{
					return true;
				}
 
				return false;
			}
 
			/// <summary>
			/// Adds positions of the series markers into the list.
			/// </summary>
			/// <param name="common">Reference to common elements.</param>
			/// <param name="area">Chart area.</param>
			virtual internal void AddMarkersPosition(
				CommonElements common, 
				ChartArea area)
			{
				// Proceed only if there is no items in the list yet
				if(this.smartLabelsPositions.Count == 0 && area != null)
				{
					// Get chart types registry
					ChartTypeRegistry	registry = common.ChartTypeRegistry;
 
					// Loop through all the series from this chart area
					foreach(Series series in common.DataManager.Series)
					{
						// Check if marker overapping is enabled for the series
						if(series.ChartArea == area.Name && 
							series.SmartLabelStyle.Enabled &&
							!series.SmartLabelStyle.IsMarkerOverlappingAllowed)
						{
							// Get series chart type
							IChartType chartType = registry.GetChartType(series.ChartTypeName);
 
							// Add series markers positions into the list
							chartType.AddSmartLabelMarkerPositions(common, area, series, this.smartLabelsPositions);
						}
					}
 
 
 
					// Make sure labels do not intersect with scale breaks
					foreach(Axis currentAxis in area.Axes)
					{
						// Check if scale breaks are defined and there are non zero spacing
						if(currentAxis.ScaleBreakStyle.Spacing > 0.0 
							&& currentAxis.ScaleSegments.Count > 0)
						{
							for(int index = 0; index < (currentAxis.ScaleSegments.Count - 1); index++)
							{
								// Get break position in pixel coordinates
								RectangleF breakPosition = currentAxis.ScaleSegments[index].GetBreakLinePosition(common.graph, currentAxis.ScaleSegments[index + 1]);
								breakPosition = common.graph.GetRelativeRectangle(breakPosition);
 
								// Create array list if needed
								if(this.smartLabelsPositions == null)
								{
									this.smartLabelsPositions = new ArrayList();
								}
 
								// Add label position into the list
								this.smartLabelsPositions.Add(breakPosition);
 
							}
						}
					}
 
 
				}
			}
 
			/// <summary>
			/// Adds single Smart Label position into the list.
			/// </summary>
			/// <param name="graph">Chart graphics object.</param>
			/// <param name="position">Original label position.</param>
			/// <param name="size">Label text size.</param>
			/// <param name="format">Label string format.</param>
			internal void AddSmartLabelPosition(
				ChartGraphics graph,
				PointF position, 
				SizeF size,
				StringFormat format)
			{
				// Calculate label position rectangle
				RectangleF	labelPosition = GetLabelPosition(graph, position, size, format, false);
 
				if(this.smartLabelsPositions == null)
				{
					this.smartLabelsPositions = new ArrayList();
				}
 
				// Add label position into the list
				this.smartLabelsPositions.Add(labelPosition);
			}
 
			/// <summary>
			/// Gets rectangle position of the label.
			/// </summary>
			/// <param name="graph">Chart graphics object.</param>
			/// <param name="position">Original label position.</param>
			/// <param name="size">Label text size.</param>
			/// <param name="format">Label string format.</param>
			/// <param name="adjustForDrawing">Result position is adjusted for drawing.</param>
			/// <returns>Label rectangle position.</returns>
			internal RectangleF GetLabelPosition(
				ChartGraphics graph,
				PointF position, 
				SizeF size,
				StringFormat format,
				bool adjustForDrawing)
			{
				// Calculate label position rectangle
				RectangleF	labelPosition = RectangleF.Empty;
				labelPosition.Width = size.Width;
				labelPosition.Height = size.Height;
 
				// Calculate pixel size in relative coordiantes
				SizeF	pixelSize = SizeF.Empty;
				if(graph != null)
				{
					pixelSize = graph.GetRelativeSize(new SizeF(1f, 1f));
				}
 
				if(format.Alignment == StringAlignment.Far)
				{
					labelPosition.X = position.X - size.Width;
					if(adjustForDrawing && !pixelSize.IsEmpty)
					{
						labelPosition.X -= 4f*pixelSize.Width;
						labelPosition.Width += 4f*pixelSize.Width;
					}
				}
				else if(format.Alignment == StringAlignment.Near)
				{
					labelPosition.X = position.X;
					if(adjustForDrawing && !pixelSize.IsEmpty)
					{
						labelPosition.Width += 4f*pixelSize.Width;
					}
				}
				else if(format.Alignment == StringAlignment.Center)
				{
					labelPosition.X = position.X - size.Width/2F;
					if(adjustForDrawing && !pixelSize.IsEmpty)
					{
						labelPosition.X -= 2f*pixelSize.Width;
						labelPosition.Width += 4f*pixelSize.Width;
					}
				}
 
				if(format.LineAlignment == StringAlignment.Far)
				{
					labelPosition.Y = position.Y - size.Height;
				}
				else if(format.LineAlignment == StringAlignment.Near)
				{
					labelPosition.Y = position.Y;
				}
				else if(format.LineAlignment == StringAlignment.Center)
				{
					labelPosition.Y = position.Y - size.Height/2F;
				}
 
				return labelPosition;
			}
 
			/// <summary>
			/// Gets point position of the label.
			/// </summary>
			/// <param name="labelAlignment">Label alignment.</param>
			/// <param name="markerPosition">Marker position.</param>
			/// <param name="sizeMarker">Marker size.</param>
			/// <param name="sizeFont">Label size.</param>
			/// <param name="format">String format.</param>
			/// <returns>Label point position.</returns>
			private PointF CalculatePosition(
				LabelAlignmentStyles labelAlignment, 
				PointF markerPosition, 
				SizeF sizeMarker, 
				SizeF sizeFont, 
				ref StringFormat format)
			{
				format.Alignment = StringAlignment.Near;
				format.LineAlignment = StringAlignment.Center;
 
				// Calculate label position
				PointF	position = new PointF(markerPosition.X, markerPosition.Y);
				switch(labelAlignment)
				{
					case LabelAlignmentStyles.Center:
						format.Alignment = StringAlignment.Center;
						break;
					case LabelAlignmentStyles.Bottom:
						format.Alignment = StringAlignment.Center;
						position.Y += sizeMarker.Height / 1.75F;
						position.Y += sizeFont.Height/ 2F;
						break;
					case LabelAlignmentStyles.Top:
						format.Alignment = StringAlignment.Center;
						position.Y -= sizeMarker.Height / 1.75F;
						position.Y -= sizeFont.Height/ 2F;
						break;
					case LabelAlignmentStyles.Left:
						format.Alignment = StringAlignment.Far;
						position.X -= sizeMarker.Height / 1.75F;
						break;
					case LabelAlignmentStyles.TopLeft:
						format.Alignment = StringAlignment.Far;
						position.X -= sizeMarker.Height / 1.75F;
						position.Y -= sizeMarker.Height / 1.75F;
						position.Y -= sizeFont.Height/ 2F;
						break;
					case LabelAlignmentStyles.BottomLeft:
						format.Alignment = StringAlignment.Far;
						position.X -= sizeMarker.Height / 1.75F;
						position.Y += sizeMarker.Height / 1.75F;
						position.Y += sizeFont.Height/ 2F;
						break;
					case LabelAlignmentStyles.Right:
						position.X += sizeMarker.Height / 1.75F;
						break;
					case LabelAlignmentStyles.TopRight:
						position.X += sizeMarker.Height / 1.75F;
						position.Y -= sizeMarker.Height / 1.75F;
						position.Y -= sizeFont.Height/ 2F;
						break;
					case LabelAlignmentStyles.BottomRight:
						position.X += sizeMarker.Height / 1.75F;
						position.Y += sizeMarker.Height / 1.75F;
						position.Y += sizeFont.Height/ 2F;
						break;
				}
 
				return position;
			}
 
			#endregion
		}
 
		/// <summary>
        /// AnnotationSmartLabel class provides SmartLabelStyle functionality 
        /// specific to the annotation objects.
		/// </summary>
		[
		SRDescription("DescriptionAttributeAnnotationSmartLabels_AnnotationSmartLabels"),
		]
        internal class AnnotationSmartLabel : SmartLabel
		{
			#region Constructors and initialization
 
			/// <summary>
			/// Default public constructor.
			/// </summary>
			public AnnotationSmartLabel()
			{
			}
 
			#endregion
 
			#region Methods
 
			/// <summary>
			/// Checks SmartLabelStyle collision.
			/// </summary>
			/// <param name="common">Reference to common elements.</param>
			/// <param name="graph">Reference to chart graphics object.</param>
			/// <param name="area">Chart area.</param>
			/// <param name="smartLabelStyle">Smart labels style.</param>
			/// <param name="position">Original label position.</param>
			/// <param name="size">Label text size.</param>
			/// <param name="markerPosition">Marker position.</param>
			/// <param name="format">Label string format.</param>
			/// <param name="labelAlignment">Label alignment.</param>
			/// <param name="checkCalloutLineOverlapping">Indicates that labels overlapping by callout line must be checked.</param>
			/// <returns>True if label collides.</returns>
			override internal bool IsSmartLabelCollide(
				CommonElements common, 
				ChartGraphics graph, 
				ChartArea area,
				SmartLabelStyle smartLabelStyle,
				PointF position, 
				SizeF size,
				PointF markerPosition,
				StringFormat format,
				LabelAlignmentStyles labelAlignment,
				bool checkCalloutLineOverlapping)
			{
				bool	collisionDetected = false;
 
				//*******************************************************************
				//** Check collision with smatl labels of series in chart area
				//*******************************************************************
                if (area != null && area.Visible)
				{
                    area.smartLabels.checkAllCollisions = true;
                    if (area.smartLabels.IsSmartLabelCollide(
						common, 
						graph,
                        area,
						smartLabelStyle,
						position, 
						size,
						markerPosition,
						format,
						labelAlignment,
						checkCalloutLineOverlapping) )
					{
                        area.smartLabels.checkAllCollisions = false;
						return true;
					}
                    area.smartLabels.checkAllCollisions = false;
				}
 
				//*******************************************************************
				//** Check collision with other annotations.
				//*******************************************************************
 
				// Calculate label position rectangle
				RectangleF	labelPosition = GetLabelPosition(graph, position, size, format, false);
 
				// Check if 1 collisuion is aceptable in case of cennter alignment
				bool	allowOneCollision = 
					(labelAlignment == LabelAlignmentStyles.Center && !smartLabelStyle.IsMarkerOverlappingAllowed) ? true : false;
				if(this.checkAllCollisions)
				{
					allowOneCollision = false;
				}
 
				// Check if label collide with other labels or markers.
				foreach(RectangleF pos in this.smartLabelsPositions)
				{
					if(pos.IntersectsWith(labelPosition))
					{
						// Check if 1 collision allowed
						if(allowOneCollision)
						{
							allowOneCollision = false;
							continue;
						}
 
						// DEBUG: Mark collided labels
#if DEBUG							
						if(graph != null && common.Chart.ShowDebugMarkings)
						{
							graph.Graphics.DrawRectangle(Pens.Blue, Rectangle.Round(graph.GetAbsoluteRectangle(pos)));
							graph.Graphics.DrawRectangle(Pens.Red, Rectangle.Round(graph.GetAbsoluteRectangle(labelPosition)));
						}
#endif
						collisionDetected = true;
						break;
					}
				}
 
				return collisionDetected;
			}
 
			/// <summary>
			/// Adds positions of the series markers into the list.
			/// </summary>
			/// <param name="common">Reference to common elements.</param>
			/// <param name="area">Chart area.</param>
			override internal void AddMarkersPosition(
				CommonElements common, 
				ChartArea area)
			{
				// Proceed only if there is no items in the list yet
				if(this.smartLabelsPositions.Count == 0 &&
					common != null &&
					common.Chart != null)
				{
					// Add annotations anchor points
					foreach(Annotation annotation in common.Chart.Annotations)
					{
						annotation.AddSmartLabelMarkerPositions(this.smartLabelsPositions);
					}
				}
			}
 
			/// <summary>
			/// Process single SmartLabelStyle by adjusting it's position in case of collision.
			/// </summary>
			/// <param name="common">Reference to common elements.</param>
			/// <param name="graph">Reference to chart graphics object.</param>
			/// <param name="area">Chart area.</param>
			/// <param name="smartLabelStyle">Smart labels style.</param>
			/// <param name="labelPosition">Original label position.</param>
			/// <param name="labelSize">Label text size.</param>
			/// <param name="format">Label string format.</param>
			/// <param name="markerPosition">Marker position.</param>
			/// <param name="markerSize">Marker size.</param>
			/// <param name="labelAlignment">Label alignment.</param>
			/// <returns>Adjusted position of the label.</returns>
			override internal void DrawCallout(
				CommonElements common, 
				ChartGraphics graph, 
				ChartArea area,
				SmartLabelStyle smartLabelStyle,
				PointF labelPosition, 
				SizeF labelSize,
				StringFormat format,
				PointF markerPosition, 
				SizeF markerSize,
				LabelAlignmentStyles labelAlignment)
			{
				// No callout is drawn for the annotations
			}
 
			#endregion
		}
}