File: Common\General\ChartGraphics.cs
Project: ndp\fx\src\DataVisualization\System.Web.DataVisualization.csproj (System.Web.DataVisualization)
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
//   Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
//  File:		ChartGraphics.cs
//
//  Namespace:	System.Web.UI.WebControls[Windows.Forms].Charting
//
//	Classes:	ChartGraphics
//
//  Purpose:	Chart graphic class is used for drawing Chart 
//				elements as Rectangles, Pie slices, lines, areas 
//				etc. This class is used in all classes where 
//				drawing is necessary. The GDI+ graphic class is 
//				used throw this class. Encapsulates a GDI+ chart 
//				drawing functionality
//
//	Reviewed:	GS - Jul 31, 2002
//				AG - August 7, 2002
//              AG - Microsoft 16, 2007
//
//===================================================================
 
#region Used namespaces
 
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Drawing.Imaging;
using System.Diagnostics.CodeAnalysis;
 
#if Microsoft_CONTROL
    using System.Windows.Forms.DataVisualization.Charting.Utilities;
    using System.Windows.Forms.DataVisualization.Charting.Borders3D;
#else
	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>
	/// Defines the style how the bars/columns are drawn.
	/// </summary>
    internal enum BarDrawingStyle
	{
		/// <summary>
		/// Default bar/column style.
		/// </summary>
		Default,
 
		/// <summary>
		/// Cylinder bar/column style.
		/// </summary>
		Cylinder,
 
		/// <summary>
		/// Emboss bar/column style.
		/// </summary>
		Emboss,
 
		/// <summary>
		/// LightToDark bar/column style.
		/// </summary>
		LightToDark,
		
		/// <summary>
		/// Wedge bar/column style.
		/// </summary>
		Wedge,
	}
 
	/// <summary>
	/// Defines the style how the pie and doughnut charts are drawn.
	/// </summary>
    internal enum PieDrawingStyle
	{
		/// <summary>
		/// Default pie/doughnut drawing style.
		/// </summary>
		Default,
 
        /// <summary>
        /// Soft edge shadow is drawn on the edges of the pie/doughnut slices.
        /// </summary>
		SoftEdge,
 
		/// <summary>
		/// A shadow is drawn from the top to the bottom of the pie/doughnut chart.
		/// </summary>
		Concave,
	}
 
	/// <summary>
	/// An enumeration of line styles.
	/// </summary>
	public enum ChartDashStyle
	{
		/// <summary>
		/// Line style not set
		/// </summary>
		NotSet,
		/// <summary>
		/// Specifies a line consisting of dashes. 
		/// </summary>
		Dash,
		/// <summary>
		/// Specifies a line consisting of a repeating pattern of dash-dot. 
		/// </summary>
		DashDot,
		/// <summary>
		/// Specifies a line consisting of a repeating pattern of dash-dot-dot. 
		/// </summary>
		DashDotDot,
		/// <summary>
		/// Specifies a line consisting of dots. 
		/// </summary>
		Dot,
		/// <summary>
		/// Specifies a solid line. 
		/// </summary>
		Solid,
	}
 
	#endregion
 
	/// <summary>
    /// The ChartGraphics class provides all chart drawing capabilities. 
    /// It contains methods for drawing 2D primitives and also exposes 
    /// all ChartGraphics3D class methods for 3D shapes. Only this 
    /// class should be used for any drawing in the chart.
	/// </summary>
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
    public partial class ChartGraphics : ChartElement
	{
		#region Fields
 
		// Common Elements
		private CommonElements		_common;
 
		// Reusable objects
		private Pen                 _pen;
		private SolidBrush			_solidBrush;
		private Matrix				_myMatrix;
	
		// Private fields which represents picture size
		private int					_width;
		private int					_height;
		
		// Indicates that smoothing is applied while drawing shadows
		internal bool				softShadows = true;
 
		// Anti aliasing flags
		private	AntiAliasingStyles		_antiAliasing = AntiAliasingStyles.All;
 
		// True if rendering into the metafile
		internal bool				IsMetafile = false;
 
		#endregion
 
		#region Lines Methods
 
		/// <summary>
		/// Draws a line connecting the two specified points.
		/// </summary>
		/// <param name="color">Line color.</param>
		/// <param name="width">Line width.</param>
		/// <param name="style">Line style.</param>
		/// <param name="firstPointF">A Point that represents the first point to connect.</param>
		/// <param name="secondPointF">A Point that represents the second point to connect.</param>
		internal void DrawLineRel( 
			Color color, 
			int width, 
			ChartDashStyle style, 
			PointF firstPointF, 
			PointF secondPointF 
			)
		{
			DrawLineAbs(
				color, 
				width, 
				style, 
				GetAbsolutePoint(firstPointF), 
				GetAbsolutePoint(secondPointF) );
		}
 
		/// <summary>
		/// Draws a line connecting the two specified points using absolute coordinates.
		/// </summary>
		/// <param name="color">Line color.</param>
		/// <param name="width">Line width.</param>
		/// <param name="style">Line style.</param>
		/// <param name="firstPoint">A Point that represents the first point to connect.</param>
		/// <param name="secondPoint">A Point that represents the second point to connect.</param>
		internal void DrawLineAbs( 
			Color color, 
			int width, 
			ChartDashStyle style, 
			PointF firstPoint, 
			PointF secondPoint 
			)
		{
			// Do not draw line if width is 0 or style not set
			if( width == 0 || style == ChartDashStyle.NotSet )
			{
				return;
			}
 
			// Set a line color
			if(_pen.Color != color)
			{
				_pen.Color = color;
			}
 
			// Set a line width
			if(_pen.Width != width)
			{
				_pen.Width = width;
			}
 
			// Set a line style
			if(_pen.DashStyle != GetPenStyle( style ))
			{
				_pen.DashStyle = GetPenStyle( style );
			}
 
			// Remember SmoothingMode and turn off anti aliasing for 
			// vertical or horizontal lines usinig 1 pixel dashed pen.
			// This prevents anialiasing from completly smoothing the 
			// dashed line.
			SmoothingMode oldSmoothingMode = this.SmoothingMode;
			if(width <= 1 && style != ChartDashStyle.Solid)
			{
				if(firstPoint.X == secondPoint.X ||
					firstPoint.Y == secondPoint.Y)
				{
                    this.SmoothingMode = SmoothingMode.Default;
				}
			}
 
			// Draw a line
            this.DrawLine(_pen, 
				(float)Math.Round(firstPoint.X), 
				(float)Math.Round(firstPoint.Y), 
				(float)Math.Round(secondPoint.X), 
				(float)Math.Round(secondPoint.Y) );
 
			// Return old smoothing mode
            this.SmoothingMode = oldSmoothingMode;
		}
 
		/// <summary>
		/// Draws a line with shadow connecting the two specified points.
		/// </summary>
		/// <param name="color">Line color.</param>
		/// <param name="width">Line width.</param>
		/// <param name="style">Line style.</param>
		/// <param name="firstPoint">A Point that represents the first point to connect.</param>
		/// <param name="secondPoint">A Point that represents the second point to connect.</param>		
		/// <param name="shadowColor">Shadow Color.</param>
		/// <param name="shadowOffset">Shadow Offset.</param>
		internal void DrawLineRel(	
			Color color, 
			int width, 
			ChartDashStyle style, 
			PointF firstPoint, 
			PointF secondPoint, 
			Color shadowColor, 
			int shadowOffset  
			)
		{
			DrawLineAbs(	
				color, 
				width, 
				style, 
				GetAbsolutePoint(firstPoint), 
				GetAbsolutePoint(secondPoint), 
				shadowColor, 
				shadowOffset );
		}
 
		/// <summary>
		/// Draws a line with shadow connecting the two specified points.
		/// </summary>
		/// <param name="color">Line color.</param>
		/// <param name="width">Line width.</param>
		/// <param name="style">Line style.</param>
		/// <param name="firstPoint">A Point that represents the first point to connect.</param>
		/// <param name="secondPoint">A Point that represents the second point to connect.</param>		
		/// <param name="shadowColor">Shadow Color.</param>
		/// <param name="shadowOffset">Shadow Offset.</param>
		internal void DrawLineAbs(	
			Color color, 
			int width, 
			ChartDashStyle style, 
			PointF firstPoint, 
			PointF secondPoint, 
			Color shadowColor, 
			int shadowOffset  
			)
		{
			if(shadowOffset != 0)
			{
				// Shadow color
				Color shColor;
 
				// Make shadow semi transparent 
				// if alpha value not used
				if( shadowColor.A != 255 )
					shColor = shadowColor;
				else
					shColor = Color.FromArgb(color.A/2, shadowColor);
 
				// Set shadow line position
				PointF firstShadow = new PointF( firstPoint.X + shadowOffset, firstPoint.Y + shadowOffset);
				PointF secondShadow = new PointF( secondPoint.X + shadowOffset, secondPoint.Y + shadowOffset );
 
				// Draw Shadow of Line
				DrawLineAbs( shColor, width, style, firstShadow, secondShadow );
			}
 
			// Draw Line
			DrawLineAbs( color, width, style, firstPoint, secondPoint );
		}
 
		#endregion
 
		#region Pen and Brush Methods
 
		/// <summary>
		/// Creates a Hatch Brush.
		/// </summary>
		/// <param name="hatchStyle">Chart Hatch style.</param>
		/// <param name="backColor">Back Color.</param>
		/// <param name="foreColor">Fore Color.</param>
		/// <returns>Brush</returns>
        internal Brush GetHatchBrush( 
			ChartHatchStyle hatchStyle, 
			Color backColor, 
			Color foreColor 
			)
		{
			// Convert Chart Hatch Style enum 
			// to Hatch Style enum.
			HatchStyle hatch;
			hatch = (HatchStyle)Enum.Parse(typeof(HatchStyle),hatchStyle.ToString());
			
			// Create Hatch Brush
			return new HatchBrush( hatch, foreColor, backColor );
		}
 
		/// <summary>
		/// Creates a textured brush.
		/// </summary>
		/// <param name="name">Image file name or URL.</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
		/// <param name="mode">Wrap mode.</param>
		/// <param name="backColor">Image background color.</param>
		/// <returns>Textured brush.</returns>
		internal Brush GetTextureBrush(
			string name, 
			Color backImageTransparentColor, 
			ChartImageWrapMode mode,
			Color backColor
			)
		{
			// Load a image
           System.Drawing.Image image = _common.ImageLoader.LoadImage( name );
 
			// Create a brush
			ImageAttributes attrib = new ImageAttributes();
			attrib.SetWrapMode((mode == ChartImageWrapMode.Unscaled) ? WrapMode.Clamp : ((WrapMode)mode));
			if(backImageTransparentColor != Color.Empty)
			{
				attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
			}
 
			// If image is a metafile background must be filled first
			// Solves issue that background is not cleared correctly
			if(backImageTransparentColor == Color.Empty &&
				image is Metafile &&
				backColor != Color.Transparent)
			{
				TextureBrush backFilledBrush = null;
				Bitmap bitmap = new Bitmap(image.Width, image.Height);
				using(Graphics graphics = Graphics.FromImage(bitmap))
				{
					using(SolidBrush backBrush = new SolidBrush(backColor))
					{
						graphics.FillRectangle(backBrush, 0, 0, image.Width, image.Height);
						graphics.DrawImageUnscaled(image, 0, 0);
						backFilledBrush= new TextureBrush( bitmap, new RectangleF(0,0,image.Width,image.Height), attrib); 
					}
				}
 
				return backFilledBrush;
			}
                       
            
            TextureBrush textureBrush;
 
            if (ImageLoader.DoDpisMatch(image, this.Graphics))
                textureBrush = new TextureBrush(image, new RectangleF(0, 0, image.Width, image.Height), attrib);
            else  // if the image dpi does not match the graphics dpi we have to scale the image    
            {
                Image scaledImage = ImageLoader.GetScaledImage(image, this.Graphics);
                textureBrush = new TextureBrush(scaledImage, new RectangleF(0, 0, scaledImage.Width, scaledImage.Height), attrib);
                scaledImage.Dispose();
            }
            
            return textureBrush;
 
		}
                
		/// <summary>
		/// This method creates a gradient brush.
		/// </summary>
		/// <param name="rectangle">A rectangle which has to be filled with a gradient color.</param>
		/// <param name="firstColor">First color.</param>
		/// <param name="secondColor">Second color.</param>
		/// <param name="type ">Gradient type .</param>
		/// <returns>Gradient Brush</returns>
        internal Brush GetGradientBrush( 
			RectangleF rectangle, 
			Color firstColor, 
			Color secondColor, 
			GradientStyle type
			)
		{
			// Increse the brush rectangle by 1 pixel to ensure the fit
			rectangle.Inflate(1f, 1f);
 
			Brush gradientBrush = null;
			float angle = 0;
 
			// Function which create gradient brush fires exception if 
			// rectangle size is zero.
			if( rectangle.Height == 0 || rectangle.Width == 0 )
			{
				gradientBrush = new SolidBrush( Color.Black );
				return gradientBrush;
			}
 
			// *******************************************
			// Linear Gradient
			// *******************************************
			// Check linear type .
			if( type == GradientStyle.LeftRight || type == GradientStyle.VerticalCenter )
			{
				angle = 0;
			}
			else if( type == GradientStyle.TopBottom || type == GradientStyle.HorizontalCenter )
			{
				angle = 90;
			}
			else if(  type == GradientStyle.DiagonalLeft )
			{
				angle = (float)(Math.Atan(rectangle.Width / rectangle.Height)* 180 / Math.PI); 
			}
			else if(  type == GradientStyle.DiagonalRight )
			{
				angle = (float)(180 - Math.Atan(rectangle.Width / rectangle.Height)* 180 / Math.PI); 
			}
			
			// Create a linear gradient brush
			if( type == GradientStyle.TopBottom || type == GradientStyle.LeftRight 
				|| type == GradientStyle.DiagonalLeft || type == GradientStyle.DiagonalRight
				|| type == GradientStyle.HorizontalCenter || type == GradientStyle.VerticalCenter )
			{
				RectangleF tempRect = new RectangleF(rectangle.X,rectangle.Y,rectangle.Width,rectangle.Height);
				// For Horizontal and vertical center gradient types
				if( type == GradientStyle.HorizontalCenter )
				{
					// Resize and wrap gradient
					tempRect.Height = tempRect.Height / 2F;
                    LinearGradientBrush linearGradientBrush = new LinearGradientBrush(tempRect, firstColor, secondColor, angle);
                    gradientBrush = linearGradientBrush;
					linearGradientBrush.WrapMode = WrapMode.TileFlipX;
				}
				else if( type == GradientStyle.VerticalCenter )
				{
					// Resize and wrap gradient
					tempRect.Width = tempRect.Width / 2F;
                    LinearGradientBrush linearGradientBrush = new LinearGradientBrush(tempRect, firstColor, secondColor, angle);
                    gradientBrush = linearGradientBrush;
                    linearGradientBrush.WrapMode = WrapMode.TileFlipX;
				}
				else
				{
					gradientBrush = new LinearGradientBrush( rectangle, firstColor, secondColor, angle );
				}
				return gradientBrush;
			}
 
			// *******************************************
			// Gradient is not linear : From Center.
			// *******************************************
			
			// Create a path
			GraphicsPath path = new GraphicsPath();
 
			// Add a rectangle to the path
			path.AddRectangle( rectangle );
 
			// Create a gradient brush
            PathGradientBrush pathGradientBrush = new PathGradientBrush(path);
            gradientBrush = pathGradientBrush;
 
			// Set the center color
            pathGradientBrush.CenterColor = firstColor;
 
			// Set the Surround color
			Color[] colors = {secondColor};
            pathGradientBrush.SurroundColors = colors;
			
			if( path != null )
			{
				path.Dispose();
			}
 
			return gradientBrush;
		}
 
		/// <summary>
		/// This method creates a gradient brush for pie. This gradient is one 
		/// of the types used only with pie and doughnut.
		/// </summary>
		/// <param name="rectangle">A rectangle which has to be filled with a gradient color</param>
		/// <param name="firstColor">First color</param>
		/// <param name="secondColor">Second color</param>
		/// <returns>Gradient Brush</returns>
		internal Brush GetPieGradientBrush( 
			RectangleF rectangle, 
			Color firstColor, 
			Color secondColor 
			)
		{
			// Create a path that consists of a single ellipse.
			GraphicsPath path = new GraphicsPath();
			path.AddEllipse( rectangle );
 
			// Use the path to construct a brush.
			PathGradientBrush gradientBrush = new PathGradientBrush(path);
 
			// Set the color at the center of the path.
			gradientBrush.CenterColor = firstColor;
 
			// Set the color along the entire boundary 
			// of the path to aqua.
			Color[] colors = {secondColor};
 
			gradientBrush.SurroundColors = colors;
 
			if( path != null )
			{
				path.Dispose();
			}
 
			return gradientBrush;
 
		}
 
		/// <summary>
		/// Converts GDI+ line style to Chart Graph line style.
		/// </summary>
		/// <param name="style">Chart Line style.</param>
		/// <returns>GDI+ line style.</returns>
		internal DashStyle GetPenStyle( ChartDashStyle style )
		{
			// Convert to chart line styles. The custom style doesn’t exist.
			switch( style )
			{
				case ChartDashStyle.Dash:
					return DashStyle.Dash;
				case ChartDashStyle.DashDot:
					return DashStyle.DashDot;
				case ChartDashStyle.DashDotDot:
					return DashStyle.DashDotDot;
				case ChartDashStyle.Dot:
					return DashStyle.Dot;
			}
 
			return DashStyle.Solid;
		}
 
		#endregion
 
		#region Markers
 
		/// <summary>
		/// Creates polygon for multi-corner star marker.
		/// </summary>
		/// <param name="rect">Marker rectangle.</param>
		/// <param name="numberOfCorners">Number of corners (4 and up).</param>
		/// <returns>Array of points.</returns>
		internal PointF[] CreateStarPolygon(RectangleF rect, int numberOfCorners)
		{
            int numberOfCornersX2;
            checked
            {
                numberOfCornersX2 = numberOfCorners * 2;
            }
 
            bool outside = true;
            PointF[] points = new PointF[numberOfCornersX2];
            PointF[] tempPoints = new PointF[1];
            // overflow check
            for (int pointIndex = 0; pointIndex < numberOfCornersX2; pointIndex++)
			{
				tempPoints[0] = new PointF(rect.X + rect.Width/2f, (outside == true) ? rect.Y : rect.Y + rect.Height/4f);
				Matrix	matrix = new Matrix();
				matrix.RotateAt(pointIndex*(360f/(numberOfCorners*2f)), new PointF(rect.X + rect.Width/2f, rect.Y + rect.Height/2f));
				matrix.TransformPoints(tempPoints);
				points[pointIndex] = tempPoints[0];
				outside = !outside;
			}
 
			return points;
		}
 
		/// <summary>
		/// Draw marker using relative coordinates of the center.
		/// </summary>
		/// <param name="point">Coordinates of the center.</param>
		/// <param name="markerStyle">Marker style.</param>
		/// <param name="markerSize">Marker size.</param>
		/// <param name="markerColor">Marker color.</param>
		/// <param name="markerBorderColor">Marker border color.</param>
		/// <param name="markerBorderSize">Marker border size.</param>
		/// <param name="markerImage">Marker image name.</param>
		/// <param name="markerImageTransparentColor">Marker image transparent color.</param>
		/// <param name="shadowSize">Marker shadow size.</param>
		/// <param name="shadowColor">Marker shadow color.</param>
		/// <param name="imageScaleRect">Rectangle to which marker image should be scaled.</param>
		internal void DrawMarkerRel(
			PointF point, 
			MarkerStyle markerStyle, 
			int markerSize, 
			Color markerColor, 
			Color markerBorderColor, 
			int markerBorderSize, 
			string markerImage, 
			Color markerImageTransparentColor, 
			int shadowSize, 
			Color shadowColor, 
			RectangleF imageScaleRect
			)
		{
			DrawMarkerAbs(this.GetAbsolutePoint(point), markerStyle, markerSize, markerColor, markerBorderColor, markerBorderSize, markerImage, markerImageTransparentColor, shadowSize, shadowColor, imageScaleRect, false);
		}
 
		/// <summary>
		/// Draw marker using absolute coordinates of the center.
		/// </summary>
		/// <param name="point">Coordinates of the center.</param>
		/// <param name="markerStyle">Marker style.</param>
		/// <param name="markerSize">Marker size.</param>
		/// <param name="markerColor">Marker color.</param>
		/// <param name="markerBorderColor">Marker border color.</param>
		/// <param name="markerBorderSize">Marker border size.</param>
		/// <param name="markerImage">Marker image name.</param>
		/// <param name="markerImageTransparentColor">Marker image transparent color.</param>
		/// <param name="shadowSize">Marker shadow size.</param>
		/// <param name="shadowColor">Marker shadow color.</param>
		/// <param name="imageScaleRect">Rectangle to which marker image should be scaled.</param>
		/// <param name="forceAntiAlias">Always use anti aliasing when drawing the marker.</param>
		internal void DrawMarkerAbs(
			PointF point, 
			MarkerStyle markerStyle, 
			int markerSize, 
			Color markerColor, 
			Color markerBorderColor, 
			int markerBorderSize, 
			string markerImage, 
			Color markerImageTransparentColor, 
			int shadowSize, 
			Color shadowColor, 
			RectangleF imageScaleRect, 
			bool forceAntiAlias
			)
		{
			// Hide border when zero width specified
			if(markerBorderSize <= 0)
			{
				markerBorderColor = Color.Transparent;
			}
 
			// Draw image instead of standart markers
			if(markerImage.Length > 0)
			{
				// Get image
                System.Drawing.Image image = _common.ImageLoader.LoadImage( markerImage );
 
                if (image != null)
                {
                    // Calculate image rectangle
                    RectangleF rect = RectangleF.Empty;
                    if (imageScaleRect == RectangleF.Empty)
                    {
                        SizeF size = new SizeF();
                        ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref size);
                        imageScaleRect.Width = size.Width;
                        imageScaleRect.Height = size.Height;
                    }
 
                    rect.X = point.X - imageScaleRect.Width / 2F;
                    rect.Y = point.Y - imageScaleRect.Height / 2F;
                    rect.Width = imageScaleRect.Width;
                    rect.Height = imageScaleRect.Height;
 
                    // Prepare image properties (transparent color)
                    ImageAttributes attrib = new ImageAttributes();
                    if (markerImageTransparentColor != Color.Empty)
                    {
                        attrib.SetColorKey(markerImageTransparentColor, markerImageTransparentColor, ColorAdjustType.Default);
                    }
 
                    // Draw image shadow
                    if (shadowSize != 0 && shadowColor != Color.Empty)
                    {
                        ImageAttributes attribShadow = new ImageAttributes();
                        attribShadow.SetColorKey(markerImageTransparentColor, markerImageTransparentColor, ColorAdjustType.Default);
                        ColorMatrix colorMatrix = new ColorMatrix();
                        colorMatrix.Matrix00 = 0.25f; // Red
                        colorMatrix.Matrix11 = 0.25f; // Green
                        colorMatrix.Matrix22 = 0.25f; // Blue
                        colorMatrix.Matrix33 = 0.5f; // alpha
                        colorMatrix.Matrix44 = 1.0f; // w
                        attribShadow.SetColorMatrix(colorMatrix);
 
                        this.DrawImage(image,
                            new Rectangle((int)rect.X + shadowSize, (int)rect.Y + shadowSize, (int)rect.Width, (int)rect.Height),
                            0, 0, image.Width, image.Height,
                            GraphicsUnit.Pixel,
                            attribShadow);
                    }
 
                    // Draw image
                    this.DrawImage(image,
                        new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height),
                        0, 0, image.Width, image.Height,
                        GraphicsUnit.Pixel,
                        attrib);
                }
			}
 
			// Draw standart marker using style, size and color
			else if(markerStyle != MarkerStyle.None && markerSize > 0 && markerColor != Color.Empty)
			{
				// Enable antialising
                SmoothingMode oldSmoothingMode = this.SmoothingMode;
				if(forceAntiAlias)
				{
                    this.SmoothingMode = SmoothingMode.AntiAlias;
				}
				
				// Create solid color brush
                using (SolidBrush brush = new SolidBrush(markerColor))
                {
                    // Calculate marker rectangle
                    RectangleF rect = RectangleF.Empty;
                    rect.X = point.X - ((float)markerSize) / 2F;
                    rect.Y = point.Y - ((float)markerSize) / 2F;
                    rect.Width = markerSize;
                    rect.Height = markerSize;
 
                    // Draw marker depending on style
                    switch (markerStyle)
                    {
                        case (MarkerStyle.Star4):
                        case (MarkerStyle.Star5):
                        case (MarkerStyle.Star6):
                        case (MarkerStyle.Star10):
                            {
                                // Set number of corners
                                int cornerNumber = 4;
                                if (markerStyle == MarkerStyle.Star5)
                                {
                                    cornerNumber = 5;
                                }
                                else if (markerStyle == MarkerStyle.Star6)
                                {
                                    cornerNumber = 6;
                                }
                                else if (markerStyle == MarkerStyle.Star10)
                                {
                                    cornerNumber = 10;
                                }
 
                                // Get star polygon
                                PointF[] points = CreateStarPolygon(rect, cornerNumber);
 
                                // Draw shadow
                                if (shadowSize != 0 && shadowColor != Color.Empty)
                                {
                                    Matrix translateMatrix = this.Transform.Clone();
                                    translateMatrix.Translate(shadowSize, shadowSize);
                                    Matrix oldMatrix = this.Transform;
                                    this.Transform = translateMatrix;
 
                                    this.FillPolygon(new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)), points);
 
                                    this.Transform = oldMatrix;
                                }
 
                                // Draw star
                                this.FillPolygon(brush, points);
                                this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
                                break;
                            }
                        case (MarkerStyle.Circle):
                            {
                                // Draw marker shadow
                                if (shadowSize != 0 && shadowColor != Color.Empty)
                                {
                                    if (!softShadows)
                                    {
                                        using (SolidBrush shadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
                                        {
                                            RectangleF shadowRect = rect;
                                            shadowRect.X += shadowSize;
                                            shadowRect.Y += shadowSize;
                                            this.FillEllipse(shadowBrush, shadowRect);
                                        }
                                    }
                                    else
                                    {
                                        // Add circle to the graphics path
                                        using (GraphicsPath path = new GraphicsPath())
                                        {
                                            path.AddEllipse(rect.X + shadowSize - 1, rect.Y + shadowSize - 1, rect.Width + 2, rect.Height + 2);
 
                                            // Create path brush
                                            using (PathGradientBrush shadowBrush = new PathGradientBrush(path))
                                            {
                                                shadowBrush.CenterColor = shadowColor;
 
                                                // Set the color along the entire boundary of the path
                                                Color[] colors = { Color.Transparent };
                                                shadowBrush.SurroundColors = colors;
                                                shadowBrush.CenterPoint = new PointF(point.X, point.Y);
 
                                                // Define brush focus scale
                                                PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
                                                if (focusScale.X < 0)
                                                {
                                                    focusScale.X = 0;
                                                }
                                                if (focusScale.Y < 0)
                                                {
                                                    focusScale.Y = 0;
                                                }
                                                shadowBrush.FocusScales = focusScale;
 
                                                // Draw shadow
                                                this.FillPath(shadowBrush, path);
                                            }
                                        }
                                    }
                                }
 
                                this.FillEllipse(brush, rect);
                                this.DrawEllipse(new Pen(markerBorderColor, markerBorderSize), rect);
                                break;
                            }
                        case (MarkerStyle.Square):
                            {
                                // Draw marker shadow
                                if (shadowSize != 0 && shadowColor != Color.Empty)
                                {
                                    FillRectangleShadowAbs(rect, shadowColor, shadowSize, shadowColor);
                                }
 
                                this.FillRectangle(brush, rect);
                                this.DrawRectangle(new Pen(markerBorderColor, markerBorderSize), (int)Math.Round(rect.X, 0), (int)Math.Round(rect.Y, 0), (int)Math.Round(rect.Width, 0), (int)Math.Round(rect.Height, 0));
                                break;
                            }
                        case (MarkerStyle.Cross):
                            {
                                // Calculate cross line width and size
                                float crossLineWidth = (float)Math.Ceiling(markerSize / 4F);
                                float crossSize = markerSize;// * (float)Math.Sin(45f/180f*Math.PI);
 
                                // Calculate cross coordinates
                                PointF[] points = new PointF[12];
                                points[0].X = point.X - crossSize / 2F;
                                points[0].Y = point.Y + crossLineWidth / 2F;
                                points[1].X = point.X - crossSize / 2F;
                                points[1].Y = point.Y - crossLineWidth / 2F;
 
                                points[2].X = point.X - crossLineWidth / 2F;
                                points[2].Y = point.Y - crossLineWidth / 2F;
                                points[3].X = point.X - crossLineWidth / 2F;
                                points[3].Y = point.Y - crossSize / 2F;
                                points[4].X = point.X + crossLineWidth / 2F;
                                points[4].Y = point.Y - crossSize / 2F;
 
                                points[5].X = point.X + crossLineWidth / 2F;
                                points[5].Y = point.Y - crossLineWidth / 2F;
                                points[6].X = point.X + crossSize / 2F;
                                points[6].Y = point.Y - crossLineWidth / 2F;
                                points[7].X = point.X + crossSize / 2F;
                                points[7].Y = point.Y + crossLineWidth / 2F;
 
                                points[8].X = point.X + crossLineWidth / 2F;
                                points[8].Y = point.Y + crossLineWidth / 2F;
                                points[9].X = point.X + crossLineWidth / 2F;
                                points[9].Y = point.Y + crossSize / 2F;
                                points[10].X = point.X - crossLineWidth / 2F;
                                points[10].Y = point.Y + crossSize / 2F;
                                points[11].X = point.X - crossLineWidth / 2F;
                                points[11].Y = point.Y + crossLineWidth / 2F;
 
                                // Rotate cross coordinates 45 degrees
                                Matrix rotationMatrix = new Matrix();
                                rotationMatrix.RotateAt(45, point);
                                rotationMatrix.TransformPoints(points);
 
                                // Draw shadow
                                if (shadowSize != 0 && shadowColor != Color.Empty)
                                {
                                    // Create translation matrix
                                    Matrix translateMatrix = this.Transform.Clone();
                                    translateMatrix.Translate(
                                        (softShadows) ? shadowSize + 1 : shadowSize,
                                        (softShadows) ? shadowSize + 1 : shadowSize);
                                    Matrix oldMatrix = this.Transform;
                                    this.Transform = translateMatrix;
 
                                    if (!softShadows)
                                    {
                                        using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
                                        {
                                            this.FillPolygon(softShadowBrush, points);
                                        }
                                    }
                                    else
                                    {
                                        // Add polygon to the graphics path
                                        using (GraphicsPath path = new GraphicsPath())
                                        {
                                            path.AddPolygon(points);
 
                                            // Create path brush
                                            using (PathGradientBrush shadowBrush = new PathGradientBrush(path))
                                            {
                                                shadowBrush.CenterColor = shadowColor;
 
                                                // Set the color along the entire boundary of the path
                                                Color[] colors = { Color.Transparent };
                                                shadowBrush.SurroundColors = colors;
                                                shadowBrush.CenterPoint = new PointF(point.X, point.Y);
 
                                                // Define brush focus scale
                                                PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
                                                if (focusScale.X < 0)
                                                {
                                                    focusScale.X = 0;
                                                }
                                                if (focusScale.Y < 0)
                                                {
                                                    focusScale.Y = 0;
                                                }
                                                shadowBrush.FocusScales = focusScale;
 
                                                // Draw shadow
                                                this.FillPath(shadowBrush, path);
                                            }
                                        }
                                    }
 
                                    this.Transform = oldMatrix;
                                }
 
                                // Create translation matrix
                                Matrix translateMatrixShape = this.Transform.Clone();
                                Matrix oldMatrixShape = this.Transform;
                                this.Transform = translateMatrixShape;
 
                                this.FillPolygon(brush, points);
                                this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
 
                                this.Transform = oldMatrixShape;
 
                                break;
                            }
                        case (MarkerStyle.Diamond):
                            {
                                PointF[] points = new PointF[4];
                                points[0].X = rect.X;
                                points[0].Y = rect.Y + rect.Height / 2F;
                                points[1].X = rect.X + rect.Width / 2F;
                                points[1].Y = rect.Top;
                                points[2].X = rect.Right;
                                points[2].Y = rect.Y + rect.Height / 2F;
                                points[3].X = rect.X + rect.Width / 2F;
                                points[3].Y = rect.Bottom;
 
                                // Draw shadow
                                if (shadowSize != 0 && shadowColor != Color.Empty)
                                {
                                    Matrix translateMatrix = this.Transform.Clone();
                                    translateMatrix.Translate((softShadows) ? 0 : shadowSize,
                                        (softShadows) ? 0 : shadowSize);
                                    Matrix oldMatrix = this.Transform;
                                    this.Transform = translateMatrix;
 
                                    if (!softShadows)
                                    {
                                        using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
                                        {
                                            this.FillPolygon(softShadowBrush, points);
                                        }
                                    }
                                    else
                                    {
                                        // Calculate diamond size
                                        float diamondSize = markerSize * (float)Math.Sin(45f / 180f * Math.PI);
 
                                        // Calculate diamond rectangle position
                                        RectangleF diamondRect = RectangleF.Empty;
                                        diamondRect.X = point.X - ((float)diamondSize) / 2F;
                                        diamondRect.Y = point.Y - ((float)diamondSize) / 2F - shadowSize;
                                        diamondRect.Width = diamondSize;
                                        diamondRect.Height = diamondSize;
 
                                        // Set rotation matrix to 45 
                                        translateMatrix.RotateAt(45, point);
                                        this.Transform = translateMatrix;
 
                                        FillRectangleShadowAbs(diamondRect, shadowColor, shadowSize, shadowColor);
                                    }
 
 
                                    this.Transform = oldMatrix;
                                }
 
                                this.FillPolygon(brush, points);
                                this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
                                break;
                            }
                        case (MarkerStyle.Triangle):
                            {
                                PointF[] points = new PointF[3];
                                points[0].X = rect.X;
                                points[0].Y = rect.Bottom;
                                points[1].X = rect.X + rect.Width / 2F;
                                points[1].Y = rect.Top;
                                points[2].X = rect.Right;
                                points[2].Y = rect.Bottom;
 
                                // Draw image shadow
                                if (shadowSize != 0 && shadowColor != Color.Empty)
                                {
                                    Matrix translateMatrix = this.Transform.Clone();
                                    translateMatrix.Translate((softShadows) ? shadowSize - 1 : shadowSize,
                                        (softShadows) ? shadowSize + 1 : shadowSize);
                                    Matrix oldMatrix = this.Transform;
                                    this.Transform = translateMatrix;
 
                                    if (!softShadows)
                                    {
                                        using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
                                        {
                                            this.FillPolygon(softShadowBrush, points);
                                        }
                                    }
                                    else
                                    {
                                        // Add polygon to the graphics path
                                        GraphicsPath path = new GraphicsPath();
                                        path.AddPolygon(points);
 
                                        // Create path brush
                                        PathGradientBrush shadowBrush = new PathGradientBrush(path);
                                        shadowBrush.CenterColor = shadowColor;
 
                                        // Set the color along the entire boundary of the path
                                        Color[] colors = { Color.Transparent };
                                        shadowBrush.SurroundColors = colors;
                                        shadowBrush.CenterPoint = new PointF(point.X, point.Y);
 
                                        // Define brush focus scale
                                        PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
                                        if (focusScale.X < 0)
                                        {
                                            focusScale.X = 0;
                                        }
                                        if (focusScale.Y < 0)
                                        {
                                            focusScale.Y = 0;
                                        }
                                        shadowBrush.FocusScales = focusScale;
 
                                        // Draw shadow
                                        this.FillPath(shadowBrush, path);
                                    }
 
                                    this.Transform = oldMatrix;
                                }
 
                                this.FillPolygon(brush, points);
                                this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
                                break;
                            }
                        default:
                            {
                                throw (new InvalidOperationException(SR.ExceptionGraphicsMarkerStyleUnknown));
                            }
                    }
                }
 
				// Restore SmoothingMode
				if(forceAntiAlias)
				{
					this.SmoothingMode = oldSmoothingMode;
				}
			}
		}
 
		#endregion
	
		#region String Methods
 
        /// <summary>
        /// Measures the specified string when drawn with the specified 
        /// Font object and formatted with the specified StringFormat object.
        /// </summary>
        /// <param name="text">String to measure.</param>
        /// <param name="font">Font object defines the text format of the string.</param>
        /// <param name="layoutArea">SizeF structure that specifies the maximum layout area for the text.</param>
        /// <param name="stringFormat">StringFormat object that represents formatting information, such as line spacing, for the string.</param>
        /// <param name="textOrientation">Text orientation.</param>
        /// <returns>This method returns a SizeF structure that represents the size, in pixels, of the string specified in the text parameter as drawn with the font parameter and the stringFormat parameter.</returns>
        internal SizeF MeasureString(
            string text,
            Font font,
            SizeF layoutArea,
            StringFormat stringFormat,
            TextOrientation textOrientation
            )
        {
            // Current implementation of the stacked text will simply insert a new
            // line character between all characters in the original string. This
            // apporach will not allow to show multiple lines of stacked text or 
            // correctly handle text wrapping. 
            if (textOrientation == TextOrientation.Stacked)
            {
                text = GetStackedText(text);
            }
            return this.MeasureString(text, font, layoutArea, stringFormat);
        }
 
        /// <summary>
        /// Measures the specified text string when drawn with 
        /// the specified Font object and formatted with the 
        /// specified StringFormat object.
        /// </summary>
        /// <param name="text">The string to measure</param>
        /// <param name="font">The Font object used to determine the size of the text string. </param>
        /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
        /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
        /// <param name="textOrientation">Text orientation.</param>
        /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
        internal SizeF MeasureStringRel(
            string text, 
            Font font, 
            SizeF layoutArea, 
            StringFormat stringFormat,
            TextOrientation textOrientation)
        {
            // Current implementation of the stacked text will simply insert a new
            // line character between all characters in the original string. This
            // apporach will not allow to show multiple lines of stacked text or 
            // correctly handle text wrapping. 
            if (textOrientation == TextOrientation.Stacked)
            {
                text = GetStackedText(text);
            }
            return this.MeasureStringRel(text, font, layoutArea, stringFormat);
        }
 
		/// <summary>
		/// Draws the specified text string at the specified location with the specified Brush and Font objects using the formatting properties of the specified StringFormat object.
		/// </summary>
		/// <param name="text">String to draw.</param>
		/// <param name="font">Font object that defines the text format of the string.</param>
		/// <param name="brush">Brush object that determines the color and texture of the drawn text.</param>
        /// <param name="rect">Position of the drawn text in pixels.</param>
		/// <param name="format">StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
        /// <param name="textOrientation">Text orientation.</param>
        internal void DrawString(
            string text,
            Font font,
            Brush brush,
            RectangleF rect,
            StringFormat format,
            TextOrientation textOrientation
            )
        {
            // Current implementation of the stacked text will simply insert a new
            // line character between all characters in the original string. This
            // apporach will not allow to show multiple lines of stacked text or 
            // correctly handle text wrapping. 
            if (textOrientation == TextOrientation.Stacked)
            {
                text = GetStackedText(text);
            }
            this.DrawString(text, font, brush, rect, format);
        }
 
        /// <summary>
        /// Draw a string.
        /// </summary>
        /// <param name="text">Text.</param>
        /// <param name="font">Text Font.</param>
        /// <param name="brush">Text Brush.</param>
        /// <param name="position">Text Position.</param>
        /// <param name="format">Format and text alignment.</param>
        /// <param name="angle">Text angle.</param>
        /// <param name="textOrientation">Text orientation.</param>
        internal void DrawStringRel(
            string text,
            System.Drawing.Font font,
            System.Drawing.Brush brush,
            PointF position,
            System.Drawing.StringFormat format,
            int angle,
            TextOrientation textOrientation
            )
        {
            // Current implementation of the stacked text will simply insert a new
            // line character between all characters in the original string. This
            // apporach will not allow to show multiple lines of stacked text or 
            // correctly handle text wrapping. 
            if (textOrientation == TextOrientation.Stacked)
            {
                text = GetStackedText(text);
            }
 
            this.DrawStringRel(text, font, brush, position, format, angle);
        }
 
        /// <summary>
        /// Draw a string.
        /// </summary>
        /// <param name="text">Text.</param>
        /// <param name="font">Text Font.</param>
        /// <param name="brush">Text Brush.</param>
        /// <param name="position">Text Position.</param>
        /// <param name="format">Format and text alignment.</param>
        /// <param name="textOrientation">Text orientation.</param>
        internal void DrawStringRel(
            string text,
            System.Drawing.Font font,
            System.Drawing.Brush brush,
            RectangleF position,
            System.Drawing.StringFormat format,
            TextOrientation textOrientation
            )
        {
            // Current implementation of the stacked text will simply insert a new
            // line character between all characters in the original string. This
            // apporach will not allow to show multiple lines of stacked text or 
            // correctly handle text wrapping. 
            if (textOrientation == TextOrientation.Stacked)
            {
                text = GetStackedText(text);
            }
 
            this.DrawStringRel(text, font, brush, position, format);
        }
 
        /// <summary>
        /// Function returned stacked text by inserting new line characters between
        /// all characters in the original string.
        /// </summary>
        /// <param name="text">Original text.</param>
        /// <returns>Stacked text.</returns>
        internal static string GetStackedText(string text)
        {
            string result = string.Empty;
            foreach (char ch in text)
            {
                result += ch;
                if (ch != '\n')
                {
                    result += '\n';
                }
            }
            return result;
        }
 
		/// <summary>
		/// Draw a string and fills it's background
		/// </summary>
		/// <param name="common">The Common elements object.</param>
		/// <param name="text">Text.</param>
		/// <param name="font">Text Font.</param>
		/// <param name="brush">Text Brush.</param>
		/// <param name="position">Text Position.</param>
		/// <param name="format">Format and text alignment.</param>
		/// <param name="angle">Text angle.</param>
		/// <param name="backPosition">Text background position.</param>
		/// <param name="backColor">Back Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="series">Series</param>
		/// <param name="point">Point</param>
		/// <param name="pointIndex">Point index in series</param>
		internal void DrawPointLabelStringRel( 
			CommonElements common,
			string text, 
			System.Drawing.Font font, 
			System.Drawing.Brush brush, 
			RectangleF position, 
			System.Drawing.StringFormat format, 
			int angle,
			RectangleF backPosition,
			Color backColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle,
			Series series,
			DataPoint point,
			int pointIndex)
		{
			// Start Svg/Flash Selection mode
			this.StartHotRegion( point, true );
 
			// Draw background
			DrawPointLabelBackground( 
				common,
				angle,
				PointF.Empty,
				backPosition,
				backColor, 
				borderColor, 
				borderWidth, 
				borderDashStyle,
				series,
				point,
				pointIndex);
 
			// End Svg/Flash Selection mode
			this.EndHotRegion( );
            
            point._lastLabelText = text;
            // Draw text
            if (IsRightToLeft)
            {
                // datapoint label alignments should appear as not RTL.
                using (StringFormat fmt = (StringFormat)format.Clone())
                {
                    if (fmt.Alignment == StringAlignment.Far)
                    {
                        fmt.Alignment = StringAlignment.Near;
                    }
                    else if (fmt.Alignment == StringAlignment.Near)
                    {
                        fmt.Alignment = StringAlignment.Far;
                    }
                    DrawStringRel(text,font,brush,position,fmt,angle);
                }
            }
            else
                DrawStringRel(text, font, brush, position, format, angle);
		}
 
		/// <summary>
		/// Draw a string and fills it's background
		/// </summary>
		/// <param name="common">The Common elements object.</param>
		/// <param name="text">Text.</param>
		/// <param name="font">Text Font.</param>
		/// <param name="brush">Text Brush.</param>
		/// <param name="position">Text Position.</param>
		/// <param name="format">Format and text alignment.</param>
		/// <param name="angle">Text angle.</param>
		/// <param name="backPosition">Text background position.</param>
		/// <param name="backColor">Back Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="series">Series</param>
		/// <param name="point">Point</param>
		/// <param name="pointIndex">Point index in series</param>
		internal void DrawPointLabelStringRel( 
			CommonElements common,
			string text, 
			System.Drawing.Font font, 
			System.Drawing.Brush brush, 
			PointF position, 
			System.Drawing.StringFormat format, 
			int angle,
			RectangleF backPosition,
			Color backColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle,
			Series series,
			DataPoint point,
			int pointIndex)
		{
			// Start Svg/Flash Selection mode
			this.StartHotRegion( point, true );
 
			// Draw background
			DrawPointLabelBackground( 
				common,
				angle,
				position, 
				backPosition,
				backColor, 
				borderColor, 
				borderWidth, 
				borderDashStyle,
				series,
				point,
				pointIndex);
 
			// End Svg/Flash Selection mode
			this.EndHotRegion( );
 
            point._lastLabelText = text;
            // Draw text
            if (IsRightToLeft)
            {
                // datapoint label alignments should appear as not RTL
                using (StringFormat fmt = (StringFormat)format.Clone())
                {
                    if (fmt.Alignment == StringAlignment.Far)
                    {
                        fmt.Alignment = StringAlignment.Near;
                    }
                    else if (fmt.Alignment == StringAlignment.Near)
                    {
                        fmt.Alignment = StringAlignment.Far;
                    }
                    DrawStringRel(text,font,brush,position,fmt,angle);
                }
            }
            else
                DrawStringRel(text,font,brush,position,format,angle);
		}
 
		/// <summary>
		/// Draw a string and fills it's background
		/// </summary>
		/// <param name="common">The Common elements object.</param>
		/// <param name="angle">Text angle.</param>
		/// <param name="textPosition">Text position.</param>
		/// <param name="backPosition">Text background position.</param>
		/// <param name="backColor">Back Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="series">Series</param>
		/// <param name="point">Point</param>
		/// <param name="pointIndex">Point index in series</param>
		private void DrawPointLabelBackground( 
			CommonElements common,
			int angle,
			PointF textPosition,
			RectangleF backPosition,
			Color backColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle,
			Series series,
			DataPoint point,
			int pointIndex)
		{
			// Draw background
			if(!backPosition.IsEmpty)
			{
				RectangleF backPositionAbs = this.Round(this.GetAbsoluteRectangle(backPosition));
 
				// Get rotation point
				PointF rotationPoint = PointF.Empty;
				if(textPosition.IsEmpty)
				{
					rotationPoint = new PointF(backPositionAbs.X + backPositionAbs.Width/2f, backPositionAbs.Y + backPositionAbs.Height/2f);
				}
				else
				{
					rotationPoint = this.GetAbsolutePoint(textPosition);
				}
 
				// Create a matrix and rotate it.
				_myMatrix = this.Transform.Clone();
				_myMatrix.RotateAt( angle, rotationPoint );
 
				// Save old state
				GraphicsState graphicsState = this.Save();
 
				// Set transformatino
				this.Transform = _myMatrix;
 
                // Check for empty colors
				if( !backColor.IsEmpty ||
					!borderColor.IsEmpty)
				{
					// Fill box around the label
					using(Brush	brush = new SolidBrush(backColor))
					{
						this.FillRectangle(brush, backPositionAbs);
					}
 
                    // deliant: Fix VSTS #156433	(2)	Data Label Border in core always shows when the style is set to NotSet	
                    // Draw box border
					if(  borderWidth > 0 &&
                        !borderColor.IsEmpty && borderDashStyle != ChartDashStyle.NotSet)
					{
                        AntiAliasingStyles saveAntiAliasing = this.AntiAliasing;
                        try
                        {
                            this.AntiAliasing = AntiAliasingStyles.None;						
                            using(Pen pen = new Pen(borderColor, borderWidth))
						    {
							    pen.DashStyle = GetPenStyle( borderDashStyle );
							    this.DrawRectangle(
								    pen, 
								    backPositionAbs.X, 
								    backPositionAbs.Y, 
								    backPositionAbs.Width, 
								    backPositionAbs.Height);
						    }
                        }
                        finally
                        {
                            this.AntiAliasing = saveAntiAliasing;
                        }
					}
				}
				else
				{
					// Draw invisible rectangle to handle tooltips
					using(Brush	brush = new SolidBrush(Color.Transparent))
					{
						this.FillRectangle(brush, backPositionAbs);
					}
				}
			
 
				// Restore old state
				this.Restore(graphicsState);
 
				// Add point label hot region
				if( common != null &&
					common.ProcessModeRegions)
				{
#if !Microsoft_CONTROL
					// Remember all point attributes
                    string oldToolTip = point.IsCustomPropertySet( CommonCustomProperties.ToolTip) ?  point.ToolTip : null;
					string oldUrl = point.IsCustomPropertySet( CommonCustomProperties.Url) ?  point.Url : null;
					string oldMapAreaAttributes = point.IsCustomPropertySet( CommonCustomProperties.MapAreaAttributes) ?  point.MapAreaAttributes : null;
                    string oldPostback = point.IsCustomPropertySet( CommonCustomProperties.PostBackValue) ?  point.PostBackValue : null;
                    object oldTag = point.Tag;
                    // Set label attributes into the point attribute.
					// Workaround for the AddHotRegion method limitation.
					point.ToolTip = point.LabelToolTip;
					point.Url = point.LabelUrl;
					point.MapAreaAttributes = point.LabelMapAreaAttributes;
                    point.PostBackValue = point.PostBackValue;
#endif // !Microsoft_CONTROL
 
                    // Insert area
					if(angle == 0)
					{
						common.HotRegionsList.AddHotRegion( 
							backPosition,
							point,
							series.Name,
							pointIndex );
					}
					else
					{
						// Convert rectangle to the graphics path and apply rotation transformation
                        using (GraphicsPath path = new GraphicsPath())
                        {
                            path.AddRectangle(backPositionAbs);
                            path.Transform(_myMatrix);
 
                            // Add hot region
                            common.HotRegionsList.AddHotRegion(
                                path,
                                false,
                                this,
                                point,
                                series.Name,
                                pointIndex);
                        }
					}
 
#if !Microsoft_CONTROL
					// Restore all point attributes
                    if (oldToolTip != null) point.ToolTip = oldToolTip; else point.ResetToolTip();
                    if (oldUrl != null) point.Url = oldUrl; else point.ResetUrl();
                    if (oldMapAreaAttributes != null) point.MapAreaAttributes = oldMapAreaAttributes; else point.ResetMapAreaAttributes();
                    if (oldPostback != null) point.PostBackValue = oldPostback; else point.ResetPostBackValue();
                    point.Tag = oldTag;
#endif // !Microsoft_CONTROL
 
					// Set new hot region element type 
                    if (common.HotRegionsList.List != null && common.HotRegionsList.List.Count > 0)
					{
						((HotRegion)common.HotRegionsList.List[common.HotRegionsList.List.Count - 1]).Type = 
							ChartElementType.DataPointLabel;
					}
				}
			}
		}
 
		/// <summary>
		/// Draw a string.
		/// </summary>
		/// <param name="text">Text.</param>
		/// <param name="font">Text Font.</param>
		/// <param name="brush">Text Brush.</param>
		/// <param name="position">Text Position.</param>
		/// <param name="format">Format and text alignment.</param>
		/// <param name="angle">Text angle.</param>
		internal void DrawStringRel( 
			string text, 
			System.Drawing.Font font, 
			System.Drawing.Brush brush, 
			PointF position, 
			System.Drawing.StringFormat format, 
			int angle 
			)
		{
			DrawStringAbs( 
				text, 
				font, 
				brush, 
				GetAbsolutePoint(position), 
				format, 
				angle);
		}
 
		/// <summary>
		/// Draw a string.
		/// </summary>
		/// <param name="text">Text.</param>
		/// <param name="font">Text Font.</param>
		/// <param name="brush">Text Brush.</param>
		/// <param name="absPosition">Text Position.</param>
		/// <param name="format">Format and text alignment.</param>
		/// <param name="angle">Text angle.</param>
		internal void DrawStringAbs( 
			string text, 
			System.Drawing.Font font, 
			System.Drawing.Brush brush, 
			PointF absPosition, 
			System.Drawing.StringFormat format, 
			int angle 
			)
		{
			// Create a matrix and rotate it.
			_myMatrix = this.Transform.Clone();
			_myMatrix.RotateAt(angle, absPosition);
    
			// Save aold state
			GraphicsState graphicsState = this.Save();
 
			// Set Angle
			this.Transform = _myMatrix;
 
			// Draw text with anti-aliasing
			/*
			if( (AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
				this.TextRenderingHint = TextRenderingHint.AntiAlias;
			else
				this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
			*/
 
			// Draw a string
			this.DrawString( text, font, brush, absPosition , format );
 
			// Restore old state
			this.Restore(graphicsState);
		}
 
        /// <summary>
        /// This method is used by the axis title hot region generation code. 
        /// It transforms the centered rectangle the same way as the Axis title text.
        /// </summary>
        /// <param name="center">Title center</param>
        /// <param name="size">Title text size</param>
        /// <param name="angle">Title rotation angle</param>
        /// <returns></returns>
        internal GraphicsPath GetTranformedTextRectPath(PointF center, SizeF size, int angle)
        {
            // Text hot area is 10px greater than the size of text
            size.Width += 10; 
            size.Height += 10;
            
            // Get the absolute center and create the centered rectangle points
            PointF absCenter = GetAbsolutePoint(center);            
            PointF[] points = new PointF[] {
                new PointF(absCenter.X - size.Width / 2f, absCenter.Y - size.Height / 2f), 
                new PointF(absCenter.X + size.Width / 2f, absCenter.Y - size.Height / 2f), 
                new PointF(absCenter.X + size.Width / 2f, absCenter.Y + size.Height / 2f), 
                new PointF(absCenter.X - size.Width / 2f, absCenter.Y + size.Height / 2f)};
 
            //Prepare the same tranformation matrix as used for the axis title
            Matrix matrix = this.Transform.Clone();
            matrix.RotateAt(angle, absCenter);
            //Tranform the rectangle points
            matrix.TransformPoints(points);
 
            //Return the path consisting of the rect points
            GraphicsPath path = new GraphicsPath();
            path.AddLines(points);
            path.CloseAllFigures();
            return path;
        }
 
 
 
 
		/// <summary>
		/// Draw label string.
		/// </summary>
		/// <param name="axis">Label axis.</param>
		/// <param name="labelRowIndex">Label text row index (0-10).</param>
		/// <param name="labelMark">Second row labels mark style.</param>
		/// <param name="markColor">Label mark line color.</param>
		/// <param name="text">Label text.</param>
		/// <param name="image">Label image name.</param>
		/// <param name="imageTransparentColor">Label image transparent color.</param>
		/// <param name="font">Text bont.</param>
		/// <param name="brush">Text brush.</param>
		/// <param name="position">Text position rectangle.</param>
		/// <param name="format">Label text format.</param>
		/// <param name="angle">Label text angle.</param>
		/// <param name="boundaryRect">Specifies the rectangle where the label text MUST be fitted.</param>
		/// <param name="label">Custom Label Item</param>
		/// <param name="truncatedLeft">Label is truncated on the left.</param>
		/// <param name="truncatedRight">Label is truncated on the right.</param>
		internal void DrawLabelStringRel( 
			Axis axis, 
			int labelRowIndex, 
			LabelMarkStyle labelMark, 
			Color markColor,
			string text, 
			string image,
			Color imageTransparentColor,
			System.Drawing.Font font, 
			System.Drawing.Brush brush, 
			RectangleF position, 
			System.Drawing.StringFormat format, 
			int angle, 
			RectangleF boundaryRect,
			CustomLabel label,
			bool truncatedLeft,
			bool truncatedRight)
		{
			Matrix oldTransform;
            using (StringFormat drawingFormat = (StringFormat)format.Clone())
            {
                SizeF labelSize = SizeF.Empty;
 
                // Check that rectangle is not empty
                if (position.Width == 0 || position.Height == 0)
                {
                    return;
                }
 
                // Find absolute position
                RectangleF absPosition = this.GetAbsoluteRectangle(position);
 
                // Make sure the rectangle is not empty
                if (absPosition.Width < 1f)
                {
                    absPosition.Width = 1f;
                }
                if (absPosition.Height < 1f)
                {
                    absPosition.Height = 1f;
                }
 
#if DEBUG
                // TESTING CODE: Shows labels rectangle position.
                //			Rectangle rr = Rectangle.Round(absPosition);
                //			rr.Width = (int)Math.Round(absPosition.Right) - rr.X;
                //			rr.Height = (int)Math.Round(absPosition.Bottom) - rr.Y;
                //			this.DrawRectangle(Pens.Red,rr.X, rr.Y, rr.Width, rr.Height);
#endif // DEBUG
 
                CommonElements common = axis.Common;
                if (common.ProcessModeRegions)
                {
                    common.HotRegionsList.AddHotRegion(Rectangle.Round(absPosition), label, ChartElementType.AxisLabels, false, true);
                }
 
                //********************************************************************
                //** Draw labels in the second row
                //********************************************************************
                if (labelRowIndex > 0)
                {
                    drawingFormat.LineAlignment = StringAlignment.Center;
                    drawingFormat.Alignment = StringAlignment.Center;
                    angle = 0;
 
                    if (axis.AxisPosition == AxisPosition.Left)
                    {
                        angle = -90;
                    }
                    else if (axis.AxisPosition == AxisPosition.Right)
                    {
                        angle = 90;
                    }
                    else if (axis.AxisPosition == AxisPosition.Top)
                    {
                    }
                    else if (axis.AxisPosition == AxisPosition.Bottom)
                    {
                    }
                }
 
                //********************************************************************
                //** Calculate rotation point
                //********************************************************************
                PointF rotationPoint = PointF.Empty;
                if (axis.AxisPosition == AxisPosition.Left)
                {
                    rotationPoint.X = absPosition.Right;
                    rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
                }
                else if (axis.AxisPosition == AxisPosition.Right)
                {
                    rotationPoint.X = absPosition.Left;
                    rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
                }
                else if (axis.AxisPosition == AxisPosition.Top)
                {
                    rotationPoint.X = absPosition.X + absPosition.Width / 2F;
                    rotationPoint.Y = absPosition.Bottom;
                }
                else if (axis.AxisPosition == AxisPosition.Bottom)
                {
                    rotationPoint.X = absPosition.X + absPosition.Width / 2F;
                    rotationPoint.Y = absPosition.Top;
                }
 
                //********************************************************************
                //** Adjust rectangle for horisontal axis
                //********************************************************************
                if ((axis.AxisPosition == AxisPosition.Top || axis.AxisPosition == AxisPosition.Bottom) &&
                    angle != 0)
                {
                    // Get rectangle center
                    rotationPoint.X = absPosition.X + absPosition.Width / 2F;
                    rotationPoint.Y = (axis.AxisPosition == AxisPosition.Top) ? absPosition.Bottom : absPosition.Y;
 
                    // Rotate rectangle 90 degrees
                    RectangleF newRect = RectangleF.Empty;
                    newRect.X = absPosition.X + absPosition.Width / 2F;
                    newRect.Y = absPosition.Y - absPosition.Width / 2F;
                    newRect.Height = absPosition.Width;
                    newRect.Width = absPosition.Height;
 
                    // Adjust values for bottom axis
                    if (axis.AxisPosition == AxisPosition.Bottom)
                    {
                        if (angle < 0)
                        {
                            newRect.X -= newRect.Width;
                        }
 
                        // Replace string alignment
                        drawingFormat.Alignment = StringAlignment.Near;
                        if (angle < 0)
                        {
                            drawingFormat.Alignment = StringAlignment.Far;
                        }
                        drawingFormat.LineAlignment = StringAlignment.Center;
                    }
 
                    // Adjust values for bottom axis
                    if (axis.AxisPosition == AxisPosition.Top)
                    {
                        newRect.Y += absPosition.Height;
                        if (angle > 0)
                        {
                            newRect.X -= newRect.Width;
                        }
 
                        // Replace string alignment
                        drawingFormat.Alignment = StringAlignment.Far;
                        if (angle < 0)
                        {
                            drawingFormat.Alignment = StringAlignment.Near;
                        }
                        drawingFormat.LineAlignment = StringAlignment.Center;
                    }
 
                    // Set new label rect
                    absPosition = newRect;
                }
 
                //********************************************************************
                //** 90 degrees is a special case for vertical axes
                //********************************************************************
                if ((axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right) &&
                    (angle == 90 || angle == -90))
                {
                    // Get rectangle center
                    rotationPoint.X = absPosition.X + absPosition.Width / 2F;
                    rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
 
                    // Rotate rectangle 90 degrees
                    RectangleF newRect = RectangleF.Empty;
                    newRect.X = rotationPoint.X - absPosition.Height / 2F;
                    newRect.Y = rotationPoint.Y - absPosition.Width / 2F;
                    newRect.Height = absPosition.Width;
                    newRect.Width = absPosition.Height;
                    absPosition = newRect;
 
                    // Replace string alignment
                    StringAlignment align = drawingFormat.Alignment;
                    drawingFormat.Alignment = drawingFormat.LineAlignment;
                    drawingFormat.LineAlignment = align;
                    if (angle == 90)
                    {
                        if (drawingFormat.LineAlignment == StringAlignment.Far)
                            drawingFormat.LineAlignment = StringAlignment.Near;
                        else if (drawingFormat.LineAlignment == StringAlignment.Near)
                            drawingFormat.LineAlignment = StringAlignment.Far;
                    }
                    if (angle == -90)
                    {
                        if (drawingFormat.Alignment == StringAlignment.Far)
                            drawingFormat.Alignment = StringAlignment.Near;
                        else if (drawingFormat.Alignment == StringAlignment.Near)
                            drawingFormat.Alignment = StringAlignment.Far;
                    }
                }
 
                //********************************************************************
                //** Create a matrix and rotate it.
                //********************************************************************
                oldTransform = null;
                if (angle != 0)
                {
                    _myMatrix = this.Transform.Clone();
                    _myMatrix.RotateAt(angle, rotationPoint);
 
                    // Old angle
                    oldTransform = this.Transform;
 
                    // Set Angle
                    this.Transform = _myMatrix;
                }
 
                //********************************************************************
                //** Measure string exact rectangle and adjust label bounding rectangle
                //********************************************************************
                RectangleF labelRect = Rectangle.Empty;
                float offsetY = 0f;
                float offsetX = 0f;
                
                // Measure text size
                labelSize = this.MeasureString(text.Replace("\\n", "\n"), font, absPosition.Size, drawingFormat);
 
                // Calculate text rectangle
                labelRect.Width = labelSize.Width;
                labelRect.Height = labelSize.Height;
                if (drawingFormat.Alignment == StringAlignment.Far)
                {
                    labelRect.X = absPosition.Right - labelSize.Width;
                }
                else if (drawingFormat.Alignment == StringAlignment.Near)
                {
                    labelRect.X = absPosition.X;
                }
                else if (drawingFormat.Alignment == StringAlignment.Center)
                {
                    labelRect.X = absPosition.X + absPosition.Width / 2F - labelSize.Width / 2F;
                }
 
                if (drawingFormat.LineAlignment == StringAlignment.Far)
                {
                    labelRect.Y = absPosition.Bottom - labelSize.Height;
                }
                else if (drawingFormat.LineAlignment == StringAlignment.Near)
                {
                    labelRect.Y = absPosition.Y;
                }
                else if (drawingFormat.LineAlignment == StringAlignment.Center)
                {
                    labelRect.Y = absPosition.Y + absPosition.Height / 2F - labelSize.Height / 2F;
                }
 
                //If the angle is not vertical or horizontal
                if (angle != 0 && angle != 90 && angle != -90)
                {
                    // Adjust label rectangle so it will not overlap the plotting area
                    offsetY = (float)Math.Sin((90 - angle) / 180F * Math.PI) * labelRect.Height / 2F;
                    offsetX = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * labelRect.Height / 2F;
 
                    if (axis.AxisPosition == AxisPosition.Left)
                    {
                        _myMatrix.Translate(-offsetX, 0);
                    }
                    else if (axis.AxisPosition == AxisPosition.Right)
                    {
                        _myMatrix.Translate(offsetX, 0);
                    }
                    else if (axis.AxisPosition == AxisPosition.Top)
                    {
                        _myMatrix.Translate(0, -offsetY);
                    }
                    else if (axis.AxisPosition == AxisPosition.Bottom)
                    {
                        _myMatrix.Translate(0, offsetY);
                    }
 
                    // Adjust label rectangle so it will be inside boundary
                    if (boundaryRect != RectangleF.Empty)
                    {
                        Region region = new Region(labelRect);
                        region.Transform(_myMatrix);
 
                        // Extend boundary rectangle to the chart picture border
                        if (axis.AxisPosition == AxisPosition.Left)
                        {
                            boundaryRect.Width += boundaryRect.X;
                            boundaryRect.X = 0;
                        }
                        else if (axis.AxisPosition == AxisPosition.Right)
                        {
                            boundaryRect.Width = this._common.Width - boundaryRect.X;
                        }
                        else if (axis.AxisPosition == AxisPosition.Top)
                        {
                            boundaryRect.Height += boundaryRect.Y;
                            boundaryRect.Y = 0;
                        }
                        else if (axis.AxisPosition == AxisPosition.Bottom)
                        {
                            boundaryRect.Height = this._common.Height - boundaryRect.Y;
                        }
 
                        // Exclude boundary rectangle from the label rectangle
                        region.Exclude(this.GetAbsoluteRectangle(boundaryRect));
 
                        // If any part of the label was outside bounding rectangle
                        if (!region.IsEmpty(Graphics))
                        {
                            this.Transform = oldTransform;
                            RectangleF truncateRect = region.GetBounds(Graphics);
 
                            float sizeChange = truncateRect.Width / (float)Math.Cos(Math.Abs(angle) / 180F * Math.PI);
                            if (axis.AxisPosition == AxisPosition.Left)
                            {
                                sizeChange -= labelRect.Height * (float)Math.Tan(Math.Abs(angle) / 180F * Math.PI);
                                absPosition.Y = labelRect.Y;
                                absPosition.X = labelRect.X + sizeChange;
                                absPosition.Width = labelRect.Width - sizeChange;
                                absPosition.Height = labelRect.Height;
                            }
                            else if (axis.AxisPosition == AxisPosition.Right)
                            {
                                sizeChange -= labelRect.Height * (float)Math.Tan(Math.Abs(angle) / 180F * Math.PI);
                                absPosition.Y = labelRect.Y;
                                absPosition.X = labelRect.X;
                                absPosition.Width = labelRect.Width - sizeChange;
                                absPosition.Height = labelRect.Height;
                            }
                            else if (axis.AxisPosition == AxisPosition.Top)
                            {
                                absPosition.Y = labelRect.Y;
                                absPosition.X = labelRect.X;
                                absPosition.Width = labelRect.Width - sizeChange;
                                absPosition.Height = labelRect.Height;
                                if (angle > 0)
                                {
                                    absPosition.X += sizeChange;
                                }
                            }
                            else if (axis.AxisPosition == AxisPosition.Bottom)
                            {
                                absPosition.Y = labelRect.Y;
                                absPosition.X = labelRect.X;
                                absPosition.Width = labelRect.Width - sizeChange;
                                absPosition.Height = labelRect.Height;
                                if (angle < 0)
                                {
                                    absPosition.X += sizeChange;
                                }
                            }
                        }
                    }
 
                    // Update transformation matrix
                    this.Transform = _myMatrix;
                }
 
                //********************************************************************
                //** Reserve space on the left for the label iamge
                //********************************************************************
                RectangleF absPositionWithoutImage = new RectangleF(absPosition.Location, absPosition.Size);
                
                System.Drawing.Image labelImage = null;
                SizeF imageAbsSize = new SizeF();
 
                if (image.Length > 0)
                {
                    labelImage = axis.Common.ImageLoader.LoadImage(label.Image);
 
                    if (labelImage != null)
                    {
                        ImageLoader.GetAdjustedImageSize(labelImage, this.Graphics, ref imageAbsSize);
 
                        // Adjust label position using image size
                        absPositionWithoutImage.Width -= imageAbsSize.Width;
                        absPositionWithoutImage.X += imageAbsSize.Width;
                    }
 
                    if (absPositionWithoutImage.Width < 1f)
                    {
                        absPositionWithoutImage.Width = 1f;
                    }
 
                }
 
                //********************************************************************
                //** Draw tick marks for labels in second row
                //********************************************************************
                if (labelRowIndex > 0 && labelMark != LabelMarkStyle.None)
                {
                    // Make sure that me know the exact size of the text
                    labelSize = this.MeasureString(
                        text.Replace("\\n", "\n"),
                        font,
                        absPositionWithoutImage.Size,
                        drawingFormat);
 
                    // Adjust for label image
                    SizeF labelSizeWithImage = new SizeF(labelSize.Width, labelSize.Height);
                    if (labelImage != null)
                    {
                        labelSizeWithImage.Width += imageAbsSize.Width;
                    }
 
                    // Draw mark
                    DrawSecondRowLabelMark(
                        axis,
                        markColor,
                        absPosition,
                        labelSizeWithImage,
                        labelMark,
                        truncatedLeft,
                        truncatedRight,
                        oldTransform);
                }
 
                //********************************************************************
                //** Make sure that one line label will not disapear with LineLimit
                //** flag on.
                //********************************************************************
                if ((drawingFormat.FormatFlags & StringFormatFlags.LineLimit) != 0)
                {
                    // Measure string height out of one character
                    drawingFormat.FormatFlags ^= StringFormatFlags.LineLimit;
                    SizeF size = this.MeasureString("I", font, absPosition.Size, drawingFormat);
 
                    // If height of one characte is more than rectangle heigjt - remove LineLimit flag
                    if (size.Height < absPosition.Height)
                    {
                        drawingFormat.FormatFlags |= StringFormatFlags.LineLimit;
                    }
                }
                else
                {
                    // Set NoClip flag
                    if ((drawingFormat.FormatFlags & StringFormatFlags.NoClip) != 0)
                    {
                        drawingFormat.FormatFlags ^= StringFormatFlags.NoClip;
                    }
 
                    // Measure string height out of one character without clipping
                    SizeF size = this.MeasureString("I", font, absPosition.Size, drawingFormat);
 
                    // Clear NoClip flag
                    drawingFormat.FormatFlags ^= StringFormatFlags.NoClip;
 
                    // If height of one characte is more than rectangle heigt - set NoClip flag
                    if (size.Height > absPosition.Height)
                    {
                        float delta = size.Height - absPosition.Height;
                        absPosition.Y -= delta / 2f;
                        absPosition.Height += delta;
                    }
                }
 
                //********************************************************************
                //** Draw a string
                //********************************************************************
                if (IsRightToLeft)
                {
                    // label alignment on the axis should appear as not RTL. 
                    using (StringFormat fmt = (StringFormat)drawingFormat.Clone())
                    {
 
                        if (fmt.Alignment == StringAlignment.Far)
                        {
                            fmt.Alignment = StringAlignment.Near;
                        }
                        else if (fmt.Alignment == StringAlignment.Near)
                        {
                            fmt.Alignment = StringAlignment.Far;
                        }
                        this.DrawString(text.Replace("\\n", "\n"), font, brush,
                        absPositionWithoutImage,
                        fmt);
 
                    }
                }
                else
                    this.DrawString(text.Replace("\\n", "\n"), font, brush,
                    absPositionWithoutImage,
                    drawingFormat);
 
                // Add separate hot region for the label
                if (common.ProcessModeRegions)
                {
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        path.AddRectangle(labelRect);
                        path.Transform(this.Transform);
                        string url = string.Empty;
                        string mapAreaAttributes = string.Empty;
                        string postbackValue = string.Empty;
#if !Microsoft_CONTROL
                        url = label.Url;
                        mapAreaAttributes = label.MapAreaAttributes;
                        postbackValue = label.PostBackValue;
#endif // !Microsoft_CONTROL
                        common.HotRegionsList.AddHotRegion(
                            this,
                            path,
                            false,
                            label.ToolTip,
                            url,
                            mapAreaAttributes,
                            postbackValue,
                            label,
                            ChartElementType.AxisLabels);
                    }
                }
 
                //********************************************************************
                //** Draw an image
                //********************************************************************
                if (labelImage != null)
                {
                    // Make sure we no the text size
                    if (labelSize.IsEmpty)
                    {
                        labelSize = this.MeasureString(
                            text.Replace("\\n", "\n"),
                            font,
                            absPositionWithoutImage.Size,
                            drawingFormat);
                    }
 
                    // Calculate image rectangle
                    RectangleF imageRect = new RectangleF(
                        absPosition.X + (absPosition.Width - imageAbsSize.Width - labelSize.Width) / 2,
                        absPosition.Y + (absPosition.Height - imageAbsSize.Height) / 2,
                        imageAbsSize.Width,
                        imageAbsSize.Height);
 
                    if (drawingFormat.LineAlignment == StringAlignment.Center)
                    {
                        imageRect.Y = absPosition.Y + (absPosition.Height - imageAbsSize.Height) / 2;
                    }
                    else if (drawingFormat.LineAlignment == StringAlignment.Far)
                    {
                        imageRect.Y = absPosition.Bottom - (labelSize.Height + imageAbsSize.Height) / 2;
                    }
                    else if (drawingFormat.LineAlignment == StringAlignment.Near)
                    {
                        imageRect.Y = absPosition.Top + (labelSize.Height - imageAbsSize.Height) / 2;
                    }
 
                    if (drawingFormat.Alignment == StringAlignment.Center)
                    {
                        imageRect.X = absPosition.X + (absPosition.Width - imageAbsSize.Width - labelSize.Width) / 2;
                    }
                    else if (drawingFormat.Alignment == StringAlignment.Far)
                    {
                        imageRect.X = absPosition.Right - imageAbsSize.Width - labelSize.Width;
                    }
                    else if (drawingFormat.Alignment == StringAlignment.Near)
                    {
                        imageRect.X = absPosition.X;
                    }
 
                    // Create image attribute
                    ImageAttributes attrib = new ImageAttributes();
                    if (imageTransparentColor != Color.Empty)
                    {
                        attrib.SetColorKey(imageTransparentColor, imageTransparentColor, ColorAdjustType.Default);
                    }
 
                    // Draw image
                    this.DrawImage(
                        labelImage,
                        Rectangle.Round(imageRect),
                        0, 0, labelImage.Width, labelImage.Height,
                        GraphicsUnit.Pixel,
                        attrib);
 
                    // Add separate hot region for the label image
                    if (common.ProcessModeRegions)
                    {
                        using (GraphicsPath path = new GraphicsPath())
                        {
                            path.AddRectangle(imageRect);
                            path.Transform(this.Transform);
                            string imageUrl = string.Empty;
                            string imageMapAreaAttributes = string.Empty;
                            string postbackValue = string.Empty;
#if !Microsoft_CONTROL
                            imageUrl = label.ImageUrl;
                            imageMapAreaAttributes = label.ImageMapAreaAttributes;
                            postbackValue = label.PostBackValue;
#endif // !Microsoft_CONTROL
                            common.HotRegionsList.AddHotRegion(
                                this,
                                path,
                                false,
                                string.Empty,
                                imageUrl,
                                imageMapAreaAttributes,
                                postbackValue,
                                label,
                                ChartElementType.AxisLabelImage);
                        }
                    }
                }
            }
 
			// Set Old Angle
			if(oldTransform != null)
			{
				this.Transform = oldTransform;
			}
		}
 
		/// <summary>
		/// Draw box marks for the labels in second row
		/// </summary>
		/// <param name="axis">Axis object.</param>
		/// <param name="markColor">Label mark color.</param>
		/// <param name="absPosition">Absolute position of the text.</param>
		/// <param name="truncatedLeft">Label is truncated on the left.</param>
		/// <param name="truncatedRight">Label is truncated on the right.</param>
		/// <param name="originalTransform">Original transformation matrix.</param>
		private void DrawSecondRowLabelBoxMark(
			Axis axis, 
			Color markColor,
			RectangleF absPosition, 
			bool truncatedLeft,
			bool truncatedRight,
			Matrix originalTransform)
		{
			// Remeber current and then reset original matrix
			Matrix curentMatrix = this.Transform;
			if(originalTransform != null)
			{
				this.Transform = originalTransform;
			}
 
			// Calculate center of the text rectangle
			PointF	centerNotRound = new PointF(absPosition.X + absPosition.Width/2F, absPosition.Y + absPosition.Height/2F);
 
			// Rotate rectangle 90 degrees
			if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
			{
				RectangleF newRect = RectangleF.Empty;
				newRect.X = centerNotRound.X - absPosition.Height / 2F;
				newRect.Y = centerNotRound.Y - absPosition.Width / 2F;
				newRect.Height = absPosition.Width;
				newRect.Width = absPosition.Height;
				absPosition = newRect;
			}
 
			// Get axis position
			float axisPosRelative = (float)axis.GetAxisPosition(true);
			PointF axisPositionAbs = new PointF(axisPosRelative, axisPosRelative);
			axisPositionAbs = this.GetAbsolutePoint(axisPositionAbs);
 
			// Round position to achieve crisp lines with antialiasing
			Rectangle absPositionRounded = Rectangle.Round(absPosition);
 
			// Make sure the right and bottom position is not shifted during rounding
			absPositionRounded.Width = (int)Math.Round(absPosition.Right) - absPositionRounded.X;
			absPositionRounded.Height = (int)Math.Round(absPosition.Bottom) - absPositionRounded.Y;
 
			// Create pen
			Pen	markPen = new Pen(
				(markColor.IsEmpty) ? axis.MajorTickMark.LineColor : markColor, 
				axis.MajorTickMark.LineWidth);
 
			// Set pen style
			markPen.DashStyle = GetPenStyle( axis.MajorTickMark.LineDashStyle );
 
			// Draw top/bottom lines
			if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
			{
				this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Top, absPositionRounded.Left, absPositionRounded.Bottom);
				this.DrawLine(markPen, absPositionRounded.Right, absPositionRounded.Top, absPositionRounded.Right, absPositionRounded.Bottom);
			}
			else
			{
				this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Top, absPositionRounded.Right, absPositionRounded.Top);
				this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Bottom, absPositionRounded.Right, absPositionRounded.Bottom);
			}
 
			// Draw left line
			if(!truncatedLeft)
			{
				if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
				{
					this.DrawLine(
						markPen, 
						(axis.AxisPosition == AxisPosition.Left) ? absPositionRounded.Left : absPositionRounded.Right, 
						absPositionRounded.Bottom, 
						axisPositionAbs.X, 
						absPositionRounded.Bottom);
				}
				else
				{
					this.DrawLine(
						markPen, 
						absPositionRounded.Left, 
						(axis.AxisPosition == AxisPosition.Top) ? absPositionRounded.Top : absPositionRounded.Bottom, 
						absPositionRounded.Left, 
						axisPositionAbs.Y);
				}
			}
 
			// Draw right line
			if(!truncatedRight)
			{
				if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
				{
					this.DrawLine(
						markPen, 
						(axis.AxisPosition == AxisPosition.Left) ? absPositionRounded.Left : absPositionRounded.Right, 
						absPositionRounded.Top, 
						axisPositionAbs.X, 
						absPositionRounded.Top);
				}
				else
				{
					this.DrawLine(
						markPen, 
						absPositionRounded.Right, 
						(axis.AxisPosition == AxisPosition.Top) ? absPositionRounded.Top : absPositionRounded.Bottom, 
						absPositionRounded.Right, 
						axisPositionAbs.Y);
				}
			}
 
			// Dispose Pen
			if( markPen != null )
			{
				markPen.Dispose();
			}
 
			// Restore currentmatrix
			if(originalTransform != null)
			{
				this.Transform = curentMatrix;
			}
		}
 
 
		/// <summary>
		/// Draw marks for the labels in second row
		/// </summary>
		/// <param name="axis">Axis object.</param>
		/// <param name="markColor">Label mark color.</param>
		/// <param name="absPosition">Absolute position of the text.</param>
		/// <param name="labelSize">Exact mesured size of the text.</param>
		/// <param name="labelMark">Label mark style to draw.</param>
		/// <param name="truncatedLeft">Label is truncated on the left.</param>
		/// <param name="truncatedRight">Label is truncated on the right.</param>
		/// <param name="oldTransform">Original transformation matrix.</param>
		private void DrawSecondRowLabelMark(
			Axis axis, 
			Color markColor,
			RectangleF absPosition, 
			SizeF labelSize, 
			LabelMarkStyle labelMark,
			bool truncatedLeft,
			bool truncatedRight,
			Matrix oldTransform)
		{
			// Do not draw marking line if width is 0 and style or color are not set
			if( axis.MajorTickMark.LineWidth == 0 || 
				axis.MajorTickMark.LineDashStyle == ChartDashStyle.NotSet ||
				axis.MajorTickMark.LineColor == Color.Empty)
			{
				return;
			}
 
			// Remember SmoothingMode and turn off anti aliasing for 
			// vertical or horizontal lines of the label markers.
			SmoothingMode oldSmoothingMode = this.SmoothingMode;
			this.SmoothingMode = SmoothingMode.None;
 
 
			// Draw box marker
			if(labelMark == LabelMarkStyle.Box)
			{
				DrawSecondRowLabelBoxMark(
					axis, 
					markColor,
					absPosition, 
					truncatedLeft,
					truncatedRight,
					oldTransform);
			}
			else
 
			{
				// Calculate center of the text rectangle
				Point	center = Point.Round(new PointF(absPosition.X + absPosition.Width/2F, absPosition.Y + absPosition.Height/2F));
 
				// Round position to achieve crisp lines with antialiasing
				Rectangle absPositionRounded = Rectangle.Round(absPosition);
 
				// Make sure the right and bottom position is not shifted during rounding
				absPositionRounded.Width = (int)Math.Round(absPosition.Right) - absPositionRounded.X;
				absPositionRounded.Height = (int)Math.Round(absPosition.Bottom) - absPositionRounded.Y;
 
 
				// Arrays of points for the left and right marking lines
				PointF[]	leftLine = new PointF[3];
				PointF[]	rightLine = new PointF[3];
 
				// Calculate marking lines coordinates
				leftLine[0].X = absPositionRounded.Left;
				leftLine[0].Y = absPositionRounded.Bottom;
				leftLine[1].X = absPositionRounded.Left;
				leftLine[1].Y = center.Y;
				leftLine[2].X = (float)Math.Round((double)center.X - labelSize.Width/2F - 1F);
				leftLine[2].Y = center.Y;
 
				rightLine[0].X = absPositionRounded.Right;
				rightLine[0].Y = absPositionRounded.Bottom;
				rightLine[1].X = absPositionRounded.Right;
				rightLine[1].Y = center.Y;
				rightLine[2].X = (float)Math.Round((double)center.X + labelSize.Width/2F - 1F);
				rightLine[2].Y = center.Y;
 
				if(axis.AxisPosition == AxisPosition.Bottom)
				{
					leftLine[0].Y = absPositionRounded.Top;
					rightLine[0].Y = absPositionRounded.Top;
				}
 
				// Remove third point to draw only side marks
				if(labelMark == LabelMarkStyle.SideMark)
				{
					leftLine[2] = leftLine[1];
					rightLine[2] = rightLine[1];
				}
 
				if(truncatedLeft)
				{
					leftLine[0] = leftLine[1];
				}
				if(truncatedRight)
				{
					rightLine[0] = rightLine[1];
				}
 
				// Create pen
				Pen	markPen = new Pen(
					(markColor.IsEmpty) ? axis.MajorTickMark.LineColor : markColor, 
					axis.MajorTickMark.LineWidth);
 
				// Set pen style
				markPen.DashStyle = GetPenStyle( axis.MajorTickMark.LineDashStyle );
 
				// Draw marking lines
				this.DrawLines(markPen, leftLine);
				this.DrawLines(markPen, rightLine);
 
				// Dispose Pen
				if( markPen != null )
				{
					markPen.Dispose();
				}
			}
 
			// Restore previous SmoothingMode
			this.SmoothingMode = oldSmoothingMode;
		}
 
		/// <summary>
		/// Measures the specified text string when drawn with 
		/// the specified Font object and formatted with the 
		/// specified StringFormat object.
		/// </summary>
		/// <param name="text">The string to measure</param>
		/// <param name="font">The Font object used to determine the size of the text string. </param>
		/// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
		internal SizeF MeasureStringRel( string text, Font font )
		{
			SizeF newSize;
 
			// Measure string
			newSize = this.MeasureString( text, font );
 
			// Convert to relative Coordinates
			return GetRelativeSize( newSize );
		}
 
		/// <summary>
		/// Measures the specified text string when drawn with 
		/// the specified Font object and formatted with the 
		/// specified StringFormat object.
		/// </summary>
		/// <param name="text">The string to measure</param>
		/// <param name="font">The Font object used to determine the size of the text string. </param>
		/// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
		/// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
		/// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
		internal SizeF MeasureStringRel( string text, Font font, SizeF layoutArea, StringFormat stringFormat )
		{
			SizeF size, newSize;
 
			// Get absolute coordinates
			size = GetAbsoluteSize( layoutArea );
 
			newSize = this.MeasureString( text, font, size, stringFormat );
 
			// Convert to relative Coordinates
			return GetRelativeSize( newSize );
		}
 
		/// <summary>
		/// Measures the specified text string when drawn with 
		/// the specified Font object and formatted with the 
		/// specified StringFormat object.
		/// </summary>
		/// <param name="text">The string to measure</param>
		/// <param name="font">The Font object used to determine the size of the text string. </param>
		/// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
		internal Size MeasureStringAbs( string text, Font font )
		{
			// Measure string
			SizeF size = this.MeasureString( text, font );
			return new Size( (int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));
		}
 
		/// <summary>
		/// Measures the specified text string when drawn with 
		/// the specified Font object and formatted with the 
		/// specified StringFormat object.
		/// </summary>
		/// <param name="text">The string to measure</param>
		/// <param name="font">The Font object used to determine the size of the text string. </param>
		/// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
		/// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
		/// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
		internal Size MeasureStringAbs( string text, Font font, SizeF layoutArea, StringFormat stringFormat )
		{
			SizeF size = this.MeasureString( text, font, layoutArea, stringFormat );
			return new Size( (int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));
		}
 
		/// <summary>
		/// Draws the specified text string at the specified location 
		/// with the specified Brush object and font. The formatting 
		/// properties in the specified StringFormat object are applied 
		/// to the text.
		/// </summary>
		/// <param name="text">A string object that specifies the text to draw.</param>
		/// <param name="font">A Font object that specifies the font face and size with which to draw the text.</param>
		/// <param name="brush">A Brush object that determines the color and/or texture of the drawn text.</param>
		/// <param name="layoutRectangle">A RectangleF structure that specifies the location of the drawn text.</param>
		/// <param name="format">A StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
		internal void DrawStringRel( string text, Font font, Brush brush,	RectangleF layoutRectangle,	StringFormat format	)
		{
			RectangleF rect;
 
			// Check that rectangle is not empty
			if(layoutRectangle.Width == 0 || layoutRectangle.Height == 0)
			{
				return;
			}
 
			// Get absolute coordinates
			rect = GetAbsoluteRectangle( layoutRectangle );
 
			// Draw text with anti-aliasing
			/*
			if( (this.AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
			{
				this.TextRenderingHint = TextRenderingHint.AntiAlias;
			}
			else
			{
				this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
			}
			*/
 
			this.DrawString( text, font, brush, rect, format );
		}
 
		
		/// <summary>
		/// Draws the specified text string at the specified location 
		/// with the specified angle and with the specified Brush object and font. The 
		/// formatting properties in the specified StringFormat object are applied 
		/// to the text.
		/// </summary>
		/// <param name="text">A string object that specifies the text to draw.</param>
		/// <param name="font">A Font object that specifies the font face and size with which to draw the text.</param>
		/// <param name="brush">A Brush object that determines the color and/or texture of the drawn text.</param>
		/// <param name="layoutRectangle">A RectangleF structure that specifies the location of the drawn text.</param>
		/// <param name="format">A StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
		/// <param name="angle">A angle of the text</param>
		internal void DrawStringRel( 
			string text, 
			Font font, 
			Brush brush,	
			RectangleF layoutRectangle,	
			StringFormat format, 
			int angle	
			)
		{
			RectangleF rect;
			SizeF size;
			Matrix oldTransform;
			PointF rotationCenter = PointF.Empty;
 
			// Check that rectangle is not empty
			if(layoutRectangle.Width == 0 || layoutRectangle.Height == 0)
			{
				return;
			}
 
			// Get absolute coordinates
			rect = GetAbsoluteRectangle( layoutRectangle );
 
			size = this.MeasureString( text, font, rect.Size, format );
 
 
			// Find the center of rotation
			if( format.Alignment == StringAlignment.Near )
			{ // Near
				rotationCenter.X = rect.X + size.Width / 2;
				rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
			}
			else if( format.Alignment == StringAlignment.Far )
			{ // Far
				rotationCenter.X = rect.Right - size.Width / 2;
				rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
			}
			else
			{ // Center
				rotationCenter.X = ( rect.Left + rect.Right ) / 2;
				rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
			}
			// Create a matrix and rotate it.
			_myMatrix = this.Transform.Clone();
			_myMatrix.RotateAt( angle, rotationCenter);
 
			// Old angle
			oldTransform = this.Transform;
 
			// Set Angle
			this.Transform = _myMatrix;
 
			// Draw text with anti-aliasing
			/*
			if( (AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
			{
				this.TextRenderingHint = TextRenderingHint.AntiAlias;
			}
			else
			{
				this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
			}
			*/
 
			this.DrawString( text, font, brush, rect, format );
 
			// Set Old Angle
			this.Transform = oldTransform;
		}
 
		#endregion
 
		#region Rectangle Methods
 
		/// <summary>
		/// Draws different shadows to create bar styles.
		/// </summary>
		/// <param name="barDrawingStyle">Bar drawing style.</param>
		/// <param name="isVertical">True if a vertical bar.</param>
		/// <param name="rect">Rectangle position.</param>
		internal void DrawRectangleBarStyle(BarDrawingStyle barDrawingStyle, bool isVertical, RectangleF rect)
		{
			// Check if non-default bar drawing style is specified
			if(barDrawingStyle != BarDrawingStyle.Default)
			{
				// Check column/bar size
				if(rect.Width > 0 && rect.Height > 0)
				{
					// Draw gradient(s)
					if(barDrawingStyle == BarDrawingStyle.Cylinder)
					{
						// Calculate gradient position
						RectangleF gradientRect = rect;
						if(isVertical)
						{
							gradientRect.Width *= 0.3f;
						}
						else
						{
							gradientRect.Height *= 0.3f;
						}
						if(gradientRect.Width > 0 && gradientRect.Height > 0)
						{
							this.FillRectangleAbs( 
								gradientRect, 
								Color.Transparent,
								ChartHatchStyle.None, 
								string.Empty, 
								ChartImageWrapMode.Scaled, 
								Color.Empty,
								ChartImageAlignmentStyle.Center,
								(isVertical) ? GradientStyle.LeftRight : GradientStyle.TopBottom, 
								Color.FromArgb(120, Color.White),
								Color.Empty, 
								0, 
								ChartDashStyle.NotSet, 
								PenAlignment.Inset );
 
						
							if(isVertical)
							{
								gradientRect.X += gradientRect.Width + 1f;
								gradientRect.Width = rect.Right - gradientRect.X;
							}
							else
							{
								gradientRect.Y += gradientRect.Height + 1f;
								gradientRect.Height = rect.Bottom - gradientRect.Y;
							}
 
							this.FillRectangleAbs( 
								gradientRect, 
								Color.FromArgb(120, Color.White),
								ChartHatchStyle.None, 
								string.Empty, 
								ChartImageWrapMode.Scaled, 
								Color.Empty,
								ChartImageAlignmentStyle.Center,
								(isVertical) ? GradientStyle.LeftRight : GradientStyle.TopBottom, 
								Color.FromArgb(150, Color.Black),
								Color.Empty, 
								0, 
								ChartDashStyle.NotSet, 
								PenAlignment.Inset );
 
						}
					}
					else if(barDrawingStyle == BarDrawingStyle.Emboss)
					{
						// Calculate width of shadows used to create the effect
						float shadowSize = 3f;
						if(rect.Width < 6f || rect.Height < 6f)
						{
							shadowSize = 1f;
						}
						else if(rect.Width < 15f || rect.Height < 15f)
						{
							shadowSize = 2f;
						}
 
						// Create and draw left/top path
						using(GraphicsPath path = new GraphicsPath())
						{
							// Add shadow polygon to the path
							PointF[] points = new PointF[] {
															   new PointF(rect.Left, rect.Bottom),
															   new PointF(rect.Left, rect.Top),
															   new PointF(rect.Right, rect.Top),
															   new PointF(rect.Right - shadowSize, rect.Top + shadowSize),
															   new PointF(rect.Left + shadowSize, rect.Top + shadowSize),
															   new PointF(rect.Left + shadowSize, rect.Bottom - shadowSize) };
							path.AddPolygon(points);
 
							// Create brush
							using(SolidBrush leftTopBrush = new SolidBrush(Color.FromArgb(100, Color.White)))
							{
								// Fill shadow path on the left-bottom side of the bar
								this.FillPath(leftTopBrush, path);
							}
						}
 
						// Create and draw top/right path
						using(GraphicsPath path = new GraphicsPath())
						{
							// Add shadow polygon to the path
							PointF[] points = new PointF[] {
															   new PointF(rect.Right, rect.Top),
															   new PointF(rect.Right, rect.Bottom),
															   new PointF(rect.Left, rect.Bottom),
															   new PointF(rect.Left + shadowSize, rect.Bottom - shadowSize),
															   new PointF(rect.Right - shadowSize, rect.Bottom - shadowSize),
															   new PointF(rect.Right - shadowSize, rect.Top + shadowSize) };
							path.AddPolygon(points);
 
							// Create brush
							using(SolidBrush bottomRightBrush = new SolidBrush(Color.FromArgb(80, Color.Black)))
							{
								// Fill shadow path on the left-bottom side of the bar
								this.FillPath(bottomRightBrush, path);
							}
						}
					}
					else if(barDrawingStyle == BarDrawingStyle.LightToDark)
					{
						// Calculate width of shadows used to create the effect
						float shadowSize = 4f;
						if(rect.Width < 6f || rect.Height < 6f)
						{
							shadowSize = 2f;
						}
						else if(rect.Width < 15f || rect.Height < 15f)
						{
							shadowSize = 3f;
						}
 
						// Calculate gradient position
						RectangleF gradientRect = rect;
						gradientRect.Inflate(-shadowSize, -shadowSize);
						if(isVertical)
						{
							gradientRect.Height = (float)Math.Floor(gradientRect.Height / 3f);
						}
						else
						{
							gradientRect.X = gradientRect.Right - (float)Math.Floor(gradientRect.Width / 3f);
							gradientRect.Width = (float)Math.Floor(gradientRect.Width / 3f);
						}
						if(gradientRect.Width > 0 && gradientRect.Height > 0)
						{
							this.FillRectangleAbs( 
								gradientRect, 
								(isVertical) ? Color.FromArgb(120, Color.White) : Color.Transparent, 
								ChartHatchStyle.None, 
								string.Empty, 
								ChartImageWrapMode.Scaled, 
								Color.Empty,
								ChartImageAlignmentStyle.Center,
								(isVertical) ? GradientStyle.TopBottom : GradientStyle.LeftRight, 
								(isVertical) ? Color.Transparent : Color.FromArgb(120, Color.White), 
								Color.Empty, 
								0, 
								ChartDashStyle.NotSet, 
								PenAlignment.Inset );
 
							gradientRect = rect;
							gradientRect.Inflate(-shadowSize, -shadowSize);
							if(isVertical)
							{
								gradientRect.Y = gradientRect.Bottom - (float)Math.Floor(gradientRect.Height / 3f);
								gradientRect.Height = (float)Math.Floor(gradientRect.Height / 3f);
							}
							else
							{
								gradientRect.Width = (float)Math.Floor(gradientRect.Width / 3f);
							}
 
 
							this.FillRectangleAbs( 
								gradientRect, 
								(!isVertical) ? Color.FromArgb(80, Color.Black) : Color.Transparent, 
								ChartHatchStyle.None, 
								string.Empty, 
								ChartImageWrapMode.Scaled, 
								Color.Empty,
								ChartImageAlignmentStyle.Center,
								(isVertical) ? GradientStyle.TopBottom : GradientStyle.LeftRight, 
								(!isVertical) ? Color.Transparent : Color.FromArgb(80, Color.Black), 
								Color.Empty, 
								0, 
								ChartDashStyle.NotSet, 
								PenAlignment.Inset );
 
						}
					}
					else if(barDrawingStyle == BarDrawingStyle.Wedge)
					{
						// Calculate wedge size to fit the rectangle
						float size = (isVertical) ? rect.Width / 2f : rect.Height / 2f;
						if(isVertical && 2f * size > rect.Height)
						{
							size = rect.Height/2f;
						}
						if(!isVertical && 2f * size > rect.Width)
						{
							size = rect.Width/2f;
						}
 
						// Draw left/bottom shadow
						RectangleF gradientRect = rect;
						using(GraphicsPath path = new GraphicsPath())
						{
							if(isVertical)
							{
								path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size, gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size);
								path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size, gradientRect.Right, gradientRect.Bottom);
								path.AddLine(gradientRect.Right, gradientRect.Bottom, gradientRect.Right, gradientRect.Y);
							}
							else
							{
								path.AddLine(gradientRect.X + size, gradientRect.Y + gradientRect.Height/2f, gradientRect.Right - size, gradientRect.Y + gradientRect.Height/2f);
								path.AddLine(gradientRect.Right - size, gradientRect.Y + gradientRect.Height/2f, gradientRect.Right, gradientRect.Bottom);
								path.AddLine(gradientRect.Right, gradientRect.Bottom, gradientRect.Left, gradientRect.Bottom);
							}
							path.CloseAllFigures();
 
							// Create brush and fill path
							using(SolidBrush brush = new SolidBrush(Color.FromArgb(90, Color.Black)))
							{
								this.FillPath(brush, path);
							}
						}
 
						// Draw top/right triangle
						using(GraphicsPath path = new GraphicsPath())
						{
							if(isVertical)
							{
								path.AddLine(gradientRect.X, gradientRect.Y, gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size);
								path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size, gradientRect.Right, gradientRect.Y);
							}
							else
							{
								path.AddLine(gradientRect.Right, gradientRect.Y, gradientRect.Right - size, gradientRect.Y + gradientRect.Height / 2f);
								path.AddLine(gradientRect.Right - size, gradientRect.Y + gradientRect.Height / 2f, gradientRect.Right, gradientRect.Bottom);
							}
 
							// Create brush and fill path
							using(SolidBrush brush = new SolidBrush(Color.FromArgb(50, Color.Black)))
							{
								// Fill shadow path on the left-bottom side of the bar
								this.FillPath(brush, path);
 
								// Draw Lines
								using(Pen penDark = new Pen(Color.FromArgb(20, Color.Black), 1))
								{
									this.DrawPath(penDark, path);
									if(isVertical)
									{
										this.DrawLine(
											penDark, 
											rect.X + rect.Width/2f, 
											rect.Y + size,
											rect.X + rect.Width/2f, 
											rect.Bottom - size);
									}
									else
									{
										this.DrawLine(
											penDark, 
											rect.X + size, 
											rect.Y + rect.Height/2f,
											rect.X + size, 
											rect.Bottom - rect.Height/2f);
									}
								}
 
								// Draw Lines
								using(Pen pen = new Pen(Color.FromArgb(40, Color.White), 1))
								{
									this.DrawPath(pen, path);
									if(isVertical)
									{
										this.DrawLine(
											pen, 
											rect.X + rect.Width/2f, 
											rect.Y + size,
											rect.X + rect.Width/2f, 
											rect.Bottom - size);
									}
									else
									{
										this.DrawLine(
											pen, 
											rect.X + size, 
											rect.Y + rect.Height/2f,
											rect.X + size, 
											rect.Bottom - rect.Height/2f);
									}
								}
							}
						}
 
						// Draw bottom/left triangle
						using(GraphicsPath path = new GraphicsPath())
						{
							if(isVertical)
							{
								path.AddLine(gradientRect.X, gradientRect.Bottom, gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size);
								path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size, gradientRect.Right, gradientRect.Bottom);
							}
							else
							{
								path.AddLine(gradientRect.X, gradientRect.Y, gradientRect.X + size, gradientRect.Y + gradientRect.Height / 2f);
								path.AddLine(gradientRect.X + size, gradientRect.Y + gradientRect.Height / 2f, gradientRect.X, gradientRect.Bottom);
							}
 
							// Create brush
							using(SolidBrush brush = new SolidBrush(Color.FromArgb(50, Color.Black)))
							{
								// Fill shadow path on the left-bottom side of the bar
								this.FillPath(brush, path);
 
								// Draw edges
								using(Pen penDark = new Pen(Color.FromArgb(20, Color.Black), 1))
								{
									this.DrawPath(penDark, path);
								}
								using(Pen pen = new Pen(Color.FromArgb(40, Color.White), 1))
								{
									this.DrawPath(pen, path);
								}
							}
						}
					}
				}
			}
		}
 
		/// <summary>
		/// Draw a bar with shadow.
		/// </summary>
		/// <param name="rectF">Size of rectangle</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch style</param>
		/// <param name="backImage">Back Image</param>
		/// <param name="backImageWrapMode">Image mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment</param>
		/// <param name="backGradientStyle">Gradient type </param>
		/// <param name="backSecondaryColor">Gradient End Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="shadowColor">Shadow Color</param>
		/// <param name="shadowOffset">Shadow Offset</param>
		/// <param name="penAlignment">Pen Alignment</param>
		/// <param name="barDrawingStyle">Bar drawing style.</param>
		/// <param name="isVertical">True if a vertical bar.</param>
		internal void FillRectangleRel( RectangleF rectF, 
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			ChartImageAlignmentStyle backImageAlign,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle, 
			Color shadowColor, 
			int shadowOffset,
			PenAlignment penAlignment,
			BarDrawingStyle barDrawingStyle,
			bool isVertical)
		{
			this.FillRectangleRel( 
				rectF, 
				backColor, 
				backHatchStyle, 
				backImage, 
				backImageWrapMode, 
				backImageTransparentColor,
				backImageAlign,
				backGradientStyle, 
				backSecondaryColor, 
				borderColor, 
				borderWidth, 
				borderDashStyle, 
				shadowColor, 
				shadowOffset,
				penAlignment,
				false,
				0,
				false,
				barDrawingStyle,
				isVertical);
		}
 
		/// <summary>
		/// Draw a bar with shadow.
		/// </summary>
		/// <param name="rectF">Size of rectangle</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch style</param>
		/// <param name="backImage">Back Image</param>
		/// <param name="backImageWrapMode">Image mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment</param>
		/// <param name="backGradientStyle">Gradient type </param>
		/// <param name="backSecondaryColor">Gradient End Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="shadowColor">Shadow Color</param>
		/// <param name="shadowOffset">Shadow Offset</param>
		/// <param name="penAlignment">Pen Alignment</param>
		internal void FillRectangleRel( RectangleF rectF, 
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			ChartImageAlignmentStyle backImageAlign,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle, 
			Color shadowColor, 
			int shadowOffset,
			PenAlignment penAlignment )
		{
			this.FillRectangleRel( 
				rectF, 
				backColor, 
				backHatchStyle, 
				backImage, 
				backImageWrapMode, 
				backImageTransparentColor,
				backImageAlign,
				backGradientStyle, 
				backSecondaryColor, 
				borderColor, 
				borderWidth, 
				borderDashStyle, 
				shadowColor, 
				shadowOffset,
				penAlignment,
				false,
				0,
				false,
				BarDrawingStyle.Default,
				true);
		}
 
		/// <summary>
		/// Draws rectangle or circle (inside rectangle) with shadow.
		/// </summary>
		/// <param name="rectF">Size of rectangle</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch style</param>
		/// <param name="backImage">Back Image</param>
		/// <param name="backImageWrapMode">Image mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment</param>
		/// <param name="backGradientStyle">Gradient type </param>
		/// <param name="backSecondaryColor">Gradient End Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="shadowColor">Shadow Color</param>
		/// <param name="shadowOffset">Shadow Offset</param>
		/// <param name="penAlignment">Pen Alignment</param>
		/// <param name="circular">Draw circular shape inside the rectangle.</param>
		/// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
		/// <param name="circle3D">3D Circle must be drawn.</param>
		internal void FillRectangleRel( RectangleF rectF, 
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			ChartImageAlignmentStyle backImageAlign,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle, 
			Color shadowColor, 
			int shadowOffset,
			PenAlignment penAlignment,
			bool circular,
			int	circularSectorsCount,
			bool circle3D)
		{
			this.FillRectangleRel( 
				rectF, 
				backColor, 
				backHatchStyle, 
				backImage, 
				backImageWrapMode, 
				backImageTransparentColor,
				backImageAlign,
				backGradientStyle, 
				backSecondaryColor, 
				borderColor, 
				borderWidth, 
				borderDashStyle, 
				shadowColor, 
				shadowOffset,
				penAlignment,
                circular,
                circularSectorsCount,
                circle3D,
				BarDrawingStyle.Default,
				true);
		}
 
		
		/// <summary>
		/// Draws rectangle or circle (inside rectangle) with shadow.
		/// </summary>
		/// <param name="rectF">Size of rectangle</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch style</param>
		/// <param name="backImage">Back Image</param>
		/// <param name="backImageWrapMode">Image mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment</param>
		/// <param name="backGradientStyle">Gradient type </param>
		/// <param name="backSecondaryColor">Gradient End Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="shadowColor">Shadow Color</param>
		/// <param name="shadowOffset">Shadow Offset</param>
		/// <param name="penAlignment">Pen Alignment</param>
		/// <param name="circular">Draw circular shape inside the rectangle.</param>
		/// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
		/// <param name="circle3D">3D Circle must be drawn.</param>
		/// <param name="barDrawingStyle">Bar drawing style.</param>
		/// <param name="isVertical">True if a vertical bar.</param>
		internal void FillRectangleRel( RectangleF rectF, 
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			ChartImageAlignmentStyle backImageAlign,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle, 
			Color shadowColor, 
			int shadowOffset,
			PenAlignment penAlignment,
			bool circular,
			int	circularSectorsCount,
			bool circle3D,
			BarDrawingStyle barDrawingStyle,
			bool isVertical)
		{
			Brush brush = null;
			Brush backBrush = null;
 
			// Remember SmoothingMode and turn off anti aliasing
			SmoothingMode oldSmoothingMode = this.SmoothingMode;
			if(!circular)
			{
				this.SmoothingMode = SmoothingMode.Default;
			}
 
			// Color is empty
			if( backColor.IsEmpty ) 
			{
				backColor = Color.White;
			}
 
			if( backSecondaryColor.IsEmpty ) 
			{
				backSecondaryColor = Color.White;
			}
 
			if( borderColor.IsEmpty || borderDashStyle == ChartDashStyle.NotSet) 
			{
				borderWidth = 0;
			}
		
			// Get absolute coordinates
			RectangleF rect = GetAbsoluteRectangle( rectF );
			
			// Rectangle width and height can not be very small value
			if( rect.Width < 1.0F && rect.Width > 0.0F )
			{
				rect.Width = 1.0F;
			}
 
			if( rect.Height < 1.0F && rect.Height > 0.0F )
			{
				rect.Height = 1.0F;
			}
 
			// Round the values
			rect = Round( rect );
 
			// For inset alignment resize fill rectangle
			RectangleF fillRect;
			if( penAlignment == PenAlignment.Inset  &&
				borderWidth > 0)
			{
				// SVG and Metafiles do not support inset pen styles - use same rectangle
				if( this.ActiveRenderingType == RenderingType.Svg ||
					this.IsMetafile)
				{
					fillRect = new RectangleF( rect.X, rect.Y, rect.Width, rect.Height);
				}
                else if (this.Graphics.Transform.Elements[0] != 1f ||
                    this.Graphics.Transform.Elements[3] != 1f)
                {
                    // Do not reduce filling rectangle if scaling is used in the graphics
                    // transformations. Rounding may cause a 1 pixel gap between the border 
                    // and the filling.
                    fillRect = new RectangleF( rect.X, rect.Y, rect.Width, rect.Height);
                }
				else
				{
					// The fill rectangle is resized because of border size.
					fillRect = new RectangleF( 
						rect.X + borderWidth, 
						rect.Y + borderWidth, 
						rect.Width - borderWidth * 2f + 1, 
						rect.Height - borderWidth * 2f + 1);
				}
			}
			else
			{
				// The fill rectangle is same
				fillRect = rect;
			}
 
			// Fix for issue #6714:
			// Make sure the rectangle coordinates fit the control. In same cases rectangle width or
			// hight ca be extremly large. Drawing such a rectangle may cause an overflow exception. 
			// The code below restricts the maximum size to double the chart size. See issue 
			// description for more information. -AG.
			if(fillRect.Width > 2f * this._width)
			{
				fillRect.Width = 2f * this._width;
			}
			if(fillRect.Height > 2f * this._height)
			{
				fillRect.Height = 2f * this._height;
			}
 
 
			if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
			{
				backBrush = brush;
				brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor);
			}
			else if( backHatchStyle != ChartHatchStyle.None )
			{
				brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
			}
			else if( backGradientStyle != GradientStyle.None )
			{
				// If a gradient type  is set create a brush with gradient
				brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
			}
			else
			{
				// Set a bar color.
				if(backColor == Color.Empty || backColor == Color.Transparent)
				{
					brush = null;
				}
				else
				{
					brush = new SolidBrush(backColor);
				}
			}
 
			// Draw shadow
			FillRectangleShadowAbs( rect, shadowColor, shadowOffset, backColor, circular, circularSectorsCount );
 
			// Draw rectangle image
			if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
			{
				// Load image
                System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
 
				// Prepare image properties (transparent color)
				ImageAttributes attrib = new ImageAttributes();
				if(backImageTransparentColor != Color.Empty)
				{
					attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
				}
 
				// Draw scaled image
				RectangleF imageRect = new RectangleF();
				imageRect.X = fillRect.X;
				imageRect.Y = fillRect.Y;
				imageRect.Width = fillRect.Width;
				imageRect.Height = fillRect.Height;
 
                SizeF imageAbsSize = new SizeF();
 
				// Calculate unscaled image position
				if(backImageWrapMode == ChartImageWrapMode.Unscaled)
				{
                    ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageAbsSize);
 
                    // Calculate image position
                    imageRect.Width = Math.Min(fillRect.Width, imageAbsSize.Width);
                    imageRect.Height = Math.Min(fillRect.Height, imageAbsSize.Height);
 
                   	// Adjust position with alignment property
					if(imageRect.Width < fillRect.Width)
					{
						if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
							backImageAlign == ChartImageAlignmentStyle.Right ||
							backImageAlign == ChartImageAlignmentStyle.TopRight)
						{
							imageRect.X = fillRect.Right - imageRect.Width;
						}
						else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
							backImageAlign == ChartImageAlignmentStyle.Center ||
							backImageAlign == ChartImageAlignmentStyle.Top)
						{
							imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
						}
					}
					if(imageRect.Height < fillRect.Height)
					{
						if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
							backImageAlign == ChartImageAlignmentStyle.Bottom ||
							backImageAlign == ChartImageAlignmentStyle.BottomLeft)
						{
							imageRect.Y = fillRect.Bottom - imageRect.Height;
						}
						else if(backImageAlign == ChartImageAlignmentStyle.Left ||
							backImageAlign == ChartImageAlignmentStyle.Center ||
							backImageAlign == ChartImageAlignmentStyle.Right)
						{
							imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
						}
					}
 
				}
 
				// Fill background with brush
				if(brush != null)
				{
					if(circular)
						this.DrawCircleAbs( null, brush, fillRect, circularSectorsCount, circle3D );
					else
						this.FillRectangle( brush, fillRect );
				}
                 
                // Draw image
				this.DrawImage(image, 
					new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
					0, 0,
                    (backImageWrapMode == ChartImageWrapMode.Unscaled) ? imageRect.Width * image.Width / imageAbsSize.Width : image.Width,
                    (backImageWrapMode == ChartImageWrapMode.Unscaled) ? imageRect.Height * image.Height / imageAbsSize.Height : image.Height,
					GraphicsUnit.Pixel, 
					attrib);
			}
				// Draw rectangle
			else
			{
				if(backBrush != null && backImageTransparentColor != Color.Empty)
				{
					// Fill background with brush
					if(circular)
						this.DrawCircleAbs( null, backBrush, fillRect, circularSectorsCount, circle3D );
					else
						this.FillRectangle( backBrush, fillRect );
				}
 
				if(brush != null)
				{
					if(circular)
						this.DrawCircleAbs( null, brush, fillRect, circularSectorsCount, circle3D );
					else
						this.FillRectangle( brush, fillRect );
				}
			}
 
			// Draw different bar style
			this.DrawRectangleBarStyle(barDrawingStyle, isVertical, fillRect);
 
			// Draw border
			if( borderWidth > 0 && borderDashStyle != ChartDashStyle.NotSet)
			{
				// Set a border line color
				if(_pen.Color != borderColor)
				{
					_pen.Color = borderColor;
				}
			
				// Set a border line width
				if(_pen.Width != borderWidth)
				{
					_pen.Width = borderWidth;
				}
 
				// Set pen alignment
				if(_pen.Alignment != penAlignment)
				{
					_pen.Alignment = penAlignment;
				}
 
				// Set a border line style
				if(_pen.DashStyle != GetPenStyle( borderDashStyle ))
				{
					_pen.DashStyle = GetPenStyle( borderDashStyle );
				}
 
				// Draw border
				if(circular)
				{
					this.DrawCircleAbs( _pen, null, rect, circularSectorsCount, false );
				}
				else
				{
					// NOTE: Rectangle with single pixel inset border is drawn 1 pixel larger 
					// in the .Net Framework. Increase size by 1 pixel to solve the issue.
					if(_pen.Alignment == PenAlignment.Inset && _pen.Width > 1f)
					{
						rect.Width += 1;
						rect.Height += 1;
					}
 
					// Draw rectangle
					this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width, rect.Height );
				}
			}
 
			// Dispose Image and Gradient
			if(brush != null)
			{
				brush.Dispose();
			}
 
			// Return old smoothing mode
			this.SmoothingMode = oldSmoothingMode;
		}
 
		/// <summary>
		/// Draw Shadow for a bar
		/// </summary>
		/// <param name="rect">Bar rectangle</param>
		/// <param name="shadowColor">Shadow Color</param>
		/// <param name="shadowOffset">Shadow Offset</param>
		/// <param name="backColor">Back Color</param>
        internal void FillRectangleShadowAbs( 
			RectangleF rect, 
			Color shadowColor, 
			float shadowOffset, 
			Color backColor)
		{
			FillRectangleShadowAbs( 
				rect, 
				shadowColor, 
				shadowOffset, 
				backColor,
				false,
				0);
		}
 
        /// <summary>
        /// Draw Shadow for a bar
        /// </summary>
        /// <param name="rect">Bar rectangle</param>
        /// <param name="shadowColor">Shadow Color</param>
        /// <param name="shadowOffset">Shadow Offset</param>
        /// <param name="backColor">Back Color</param>
        /// <param name="circular">Draw circular shape inside the rectangle.</param>
        /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
		internal void FillRectangleShadowAbs( 
			RectangleF rect, 
			Color shadowColor, 
			float shadowOffset, 
			Color backColor,
			bool circular,
			int	circularSectorsCount)
		{
			// Do not draw shadoe for empty rectangle
			if(rect.Height == 0 || rect.Width == 0 || shadowOffset == 0)
			{
				return;
			}
 
            // Do not draw  shadow if color is IsEmpty or offset is 0
            if (shadowOffset == 0 || shadowColor == Color.Empty)
            {
                return;
            }
 
            // For non-circualr shadow with transparent background - use clipping
            bool clippingUsed = false;
            Region oldClipRegion = null;
            if (!circular && backColor == Color.Transparent)
            {
                clippingUsed = true;
                oldClipRegion = this.Clip;
                Region region = new Region();
                region.MakeInfinite();
                region.Xor(rect);
                this.Clip = region;
            }
            
			// Draw usual or "soft" shadows
			if(!softShadows || circularSectorsCount > 2)
			{
				RectangleF absolute;
				RectangleF offset = RectangleF.Empty;
 
				absolute = Round( rect );
 
				// Change shadow color
                using (SolidBrush shadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(backColor.A / 2, shadowColor)))
                {
                    // Shadow Position
                    offset.X = absolute.X + shadowOffset;
                    offset.Y = absolute.Y + shadowOffset;
                    offset.Width = absolute.Width;
                    offset.Height = absolute.Height;
 
                    // Draw rectangle
                    if (circular)
                        this.DrawCircleAbs(null, shadowBrush, offset, circularSectorsCount, false);
                    else
                        this.FillRectangle(shadowBrush, offset);
                }
			}
			else
			{
 
				RectangleF absolute;
				RectangleF offset = RectangleF.Empty;
 
				absolute = Round( rect );
				
 
				// Shadow Position
				offset.X = absolute.X + shadowOffset - 1;
				offset.Y = absolute.Y + shadowOffset - 1;
				offset.Width = absolute.Width + 2;
				offset.Height = absolute.Height + 2;
				
				// Calculate rounded rect radius
				float	radius = shadowOffset * 0.7f;
				radius = (float)Math.Max(radius, 2f);
				radius = (float)Math.Min(radius, offset.Width/4f);
				radius = (float)Math.Min(radius, offset.Height/4f);
				radius = (float)Math.Ceiling(radius);
				if(circular)
				{
					radius = offset.Width/2f;
				}
 
				// Create rounded rectangle path
				GraphicsPath path = new GraphicsPath();
				if(circular && offset.Width != offset.Height)
				{
					float	radiusX = offset.Width/2f;
					float	radiusY = offset.Height/2f;
					path.AddLine(offset.X+radiusX, offset.Y, offset.Right-radiusX, offset.Y);
					path.AddArc(offset.Right-2f*radiusX, offset.Y, 2f*radiusX, 2f*radiusY, 270, 90);
					path.AddLine(offset.Right, offset.Y + radiusY, offset.Right, offset.Bottom - radiusY);
					path.AddArc(offset.Right-2f*radiusX, offset.Bottom-2f*radiusY, 2f*radiusX, 2f*radiusY, 0, 90);
					path.AddLine(offset.Right-radiusX, offset.Bottom, offset.X + radiusX, offset.Bottom);
					path.AddArc(offset.X, offset.Bottom-2f*radiusY, 2f*radiusX, 2f*radiusY, 90, 90);
					path.AddLine(offset.X, offset.Bottom-radiusY, offset.X, offset.Y+radiusY);
					path.AddArc(offset.X, offset.Y, 2f*radiusX, 2f*radiusY, 180, 90);
				}
				else
				{
					path.AddLine(offset.X+radius, offset.Y, offset.Right-radius, offset.Y);
					path.AddArc(offset.Right-2f*radius, offset.Y, 2f*radius, 2f*radius, 270, 90);
					path.AddLine(offset.Right, offset.Y + radius, offset.Right, offset.Bottom - radius);
					path.AddArc(offset.Right-2f*radius, offset.Bottom-2f*radius, 2f*radius, 2f*radius, 0, 90);
					path.AddLine(offset.Right-radius, offset.Bottom, offset.X + radius, offset.Bottom);
					path.AddArc(offset.X, offset.Bottom-2f*radius, 2f*radius, 2f*radius, 90, 90);
					path.AddLine(offset.X, offset.Bottom-radius, offset.X, offset.Y+radius);
					path.AddArc(offset.X, offset.Y, 2f*radius, 2f*radius, 180, 90);
				}
 
				PathGradientBrush shadowBrush = new PathGradientBrush(path);
				shadowBrush.CenterColor = shadowColor;
 
				// Set the color along the entire boundary of the path
				Color[] colors = {Color.Transparent};
				shadowBrush.SurroundColors = colors;
				shadowBrush.CenterPoint = new PointF(offset.X + offset.Width/2f, offset.Y + offset.Height/2f);
 
				// Define brush focus scale
				PointF focusScale = new PointF(1-2f*shadowOffset/offset.Width, 1-2f*shadowOffset/offset.Height);
				if(focusScale.X < 0)
					focusScale.X = 0;
				if(focusScale.Y < 0)
					focusScale.Y = 0;
				shadowBrush.FocusScales = focusScale;
 
                // Draw rectangle
				this.FillPath(shadowBrush, path);
			}
 
            // Reset clip region
            if (clippingUsed)
            {
                Region region = this.Clip;
                this.Clip = oldClipRegion;
                region.Dispose();
            }
		}
 
		/// <summary>
		/// Gets the path of the polygon which represent the circular area.
		/// </summary>
		/// <param name="position">Circle position.</param>
		/// <param name="polygonSectorsNumber">Number of sectors for the polygon.</param>
		/// <returns>Graphics path of the polygon circle.</returns>
		internal GraphicsPath GetPolygonCirclePath(RectangleF position, int polygonSectorsNumber)
		{
			PointF			firstPoint = new PointF(position.X + position.Width/2f, position.Y);
			PointF			centerPoint = new PointF(position.X + position.Width/2f, position.Y + position.Height/2f);
			float			sectorSize = 0f;
			GraphicsPath	path = new GraphicsPath();
			PointF			prevPoint = PointF.Empty;
			float			curentSector = 0f;
 
			// Get sector size
			if(polygonSectorsNumber <= 2)
			{
				// Circle sector size
				sectorSize = 1f;
			}
			else
			{
				// Polygon sector size
				sectorSize = 360f / ((float)polygonSectorsNumber);
			}
 
			// Loop throug all sectors
			for(curentSector = 0f; curentSector < 360f; curentSector += sectorSize)
			{
				// Create matrix
				Matrix matrix = new Matrix();
				matrix.RotateAt(curentSector, centerPoint);
 
				// Get point and rotate it
				PointF[]	points = new PointF[] { firstPoint };
				matrix.TransformPoints(points);
 
				// Add point into the path
				if(!prevPoint.IsEmpty)
				{
					path.AddLine(prevPoint, points[0]);
				}
 
				// Remember last point
				prevPoint = points[0];
			}
 
			path.CloseAllFigures();
 
			return path;
		}
 
		/// <summary>
		/// Fills and/or draws border as circle or polygon.
		/// </summary>
		/// <param name="pen">Border pen.</param>
		/// <param name="brush">Border brush.</param>
		/// <param name="position">Circle position.</param>
		/// <param name="polygonSectorsNumber">Number of sectors for the polygon.</param>
		/// <param name="circle3D">Indicates that circle should be 3D..</param>
		internal void DrawCircleAbs(Pen pen, Brush brush, RectangleF position, int polygonSectorsNumber, bool circle3D)
		{
			bool	fill3DCircle = (circle3D && brush != null);
 
			// Draw 2D circle
			if(polygonSectorsNumber <= 2 && !fill3DCircle)
			{
				if(brush != null)
				{
					this.FillEllipse(brush, position);
				}
				if(pen != null)
				{
					this.DrawEllipse(pen, position);
				}
			}
 
				// Draw circle as polygon with specified number of sectors
			else
			{
				PointF			firstPoint = new PointF(position.X + position.Width/2f, position.Y);
				PointF			centerPoint = new PointF(position.X + position.Width/2f, position.Y + position.Height/2f);
				float			sectorSize = 0f;
				PointF			prevPoint = PointF.Empty;
				float			curentSector = 0f;
 
                using (GraphicsPath path = new GraphicsPath())
                {
                    // Remember current smoothing mode
                    SmoothingMode oldMode = this.SmoothingMode;
                    if (fill3DCircle)
                    {
                        this.SmoothingMode = SmoothingMode.None;
                    }
 
                    // Get sector size
                    if (polygonSectorsNumber <= 2)
                    {
                        // Circle sector size
                        sectorSize = 1f;
                    }
                    else
                    {
                        // Polygon sector size
                        sectorSize = 360f / ((float)polygonSectorsNumber);
                    }
 
                    // Loop throug all sectors
                    for (curentSector = 0f; curentSector < 360f; curentSector += sectorSize)
                    {
                        // Create matrix
                        Matrix matrix = new Matrix();
                        matrix.RotateAt(curentSector, centerPoint);
 
                        // Get point and rotate it
                        PointF[] points = new PointF[] { firstPoint };
                        matrix.TransformPoints(points);
 
                        // Add point into the path
                        if (!prevPoint.IsEmpty)
                        {
                            path.AddLine(prevPoint, points[0]);
 
                            // Fill each segment separatly for the 3D look
                            if (fill3DCircle)
                            {
                                path.AddLine(points[0], centerPoint);
                                path.AddLine(centerPoint, prevPoint);
                                using (Brush sectorBrush = GetSector3DBrush(brush, curentSector, sectorSize))
                                {
                                    this.FillPath(sectorBrush, path);
                                }
                                path.Reset();
                            }
                        }
 
                        // Remember last point
                        prevPoint = points[0];
                    }
 
                    path.CloseAllFigures();
 
                    // Fill last segment for the 3D look
                    if (!prevPoint.IsEmpty && fill3DCircle)
                    {
                        path.AddLine(prevPoint, firstPoint);
                        path.AddLine(firstPoint, centerPoint);
                        path.AddLine(centerPoint, prevPoint);
                        using (Brush sectorBrush = GetSector3DBrush(brush, curentSector, sectorSize))
                        {
                            this.FillPath(sectorBrush, path);
                        }
                        path.Reset();
                    }
 
                    // Restore old mode
                    if (fill3DCircle)
                    {
                        this.SmoothingMode = oldMode;
                    }
 
                    if (brush != null && !circle3D)
                    {
                        this.FillPath(brush, path);
                    }
                    if (pen != null)
                    {
                        this.DrawPath(pen, path);
                    }
                }				
			}
		}
 
        /// <summary>
        /// Creates 3D sector brush.
        /// </summary>
        /// <param name="brush">Original brush.</param>
        /// <param name="curentSector">Sector position.</param>
        /// <param name="sectorSize">Sector size.</param>
        /// <returns>3D brush.</returns>
        [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
            Justification = "Too large of a code change to justify making this change")]
		internal Brush GetSector3DBrush(Brush brush, float curentSector, float sectorSize)
		{
			// Get color from the brush
			Color	brushColor = Color.Gray;
			if(brush is HatchBrush)
			{
				brushColor = ((HatchBrush)brush).BackgroundColor;
			}
			else if(brush is LinearGradientBrush)
			{
				brushColor = ((LinearGradientBrush)brush).LinearColors[0];
			}
			else if(brush is PathGradientBrush)
			{
				brushColor = ((PathGradientBrush)brush).CenterColor;
			}
			else if(brush is SolidBrush)
			{
				brushColor = ((SolidBrush)brush).Color;
			}
 
			// Adjust sector angle
			curentSector -= sectorSize / 2f;
 
			// Make adjustment for polygon circle with 5 segments
			// to avoid the issue that bottom segment is too dark
			if(sectorSize == 72f && curentSector == 180f)
			{
                curentSector *= 0.8f;
			}
 
			// No angles more than 180 
			if(curentSector > 180)
			{
				curentSector = 360f - curentSector;
			}
			curentSector = curentSector / 180F;
 
			// Get brush
			brushColor = GetBrightGradientColor( brushColor, curentSector);
 
			// Get brush
			return new SolidBrush(brushColor);
		}
 
        /// <summary>
        /// This method creates gradient color with brightness
        /// </summary>
        /// <param name="beginColor">Start color for gradient.</param>
        /// <param name="position">Position used between Start and end color.</param>
        /// <returns>Calculated Gradient color from gradient position</returns>
		internal Color GetBrightGradientColor( Color beginColor, double position )
		{
			double brightness = 0.5;
			if( position < brightness )
			{
				return GetGradientColor( Color.FromArgb(beginColor.A,255,255,255), beginColor, 1 - brightness + position );
			}
			else if( -brightness + position < 1 )
			{
				return GetGradientColor( beginColor, Color.Black, -brightness + position);
			}
			else
			{
				return Color.FromArgb( beginColor.A, 0, 0, 0 );
			}
		}
 
		/// <summary>
		/// Draw Rectangle using absolute coordinates.
		/// </summary>
		/// <param name="rect">Size of rectangle</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch Style</param>
		/// <param name="backImage">Image URL</param>
		/// <param name="backImageWrapMode">Image Mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment.</param>
		/// <param name="backGradientStyle">Gradient AxisName</param>
		/// <param name="backSecondaryColor">End Gradient color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="penAlignment">Border is outside or inside rectangle</param>
		internal void FillRectangleAbs( RectangleF rect, 
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			ChartImageAlignmentStyle backImageAlign,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle, 
			PenAlignment penAlignment )
		{
			Brush brush = null;
			Brush backBrush = null;
 
			// Turn off Antialias
			SmoothingMode oldMode = this.SmoothingMode;
			this.SmoothingMode = SmoothingMode.None;
 
			// Color is empty
			if( backColor.IsEmpty ) 
				backColor = Color.White;
 
			if( backSecondaryColor.IsEmpty ) 
				backSecondaryColor = Color.White;
 
			if( borderColor.IsEmpty ) 
			{
				borderColor = Color.White;
				borderWidth = 0;
			}
		
			// Set a border line color
			_pen.Color = borderColor;
 
			// Set a border line width
			_pen.Width = borderWidth;
 
			// Set pen alignment
			_pen.Alignment = penAlignment;
 
			// Set a border line style
			_pen.DashStyle = GetPenStyle( borderDashStyle );
 
			if( backGradientStyle == GradientStyle.None )
			{
				// Set a bar color.
				_solidBrush.Color = backColor;
				brush = _solidBrush;
			}
			else
			{
				// If a gradient type  is set create a brush with gradient
				brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
			}
 
			if( backHatchStyle != ChartHatchStyle.None )
			{
				brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
			}
 
			if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
			{
				backBrush = brush;
				brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
			}
 
			// For inset alignment resize fill rectangle
			RectangleF fillRect;
			
			// The fill rectangle is same
			fillRect = new RectangleF( rect.X + borderWidth, rect.Y + borderWidth, rect.Width - borderWidth * 2, rect.Height - borderWidth * 2 );
 
			// FillRectangle and DrawRectangle works differently with RectangleF.
			fillRect.Width += 1;
			fillRect.Height += 1;
 
			// Draw rectangle image
			if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
			{
				// Load image
                System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
                                
 
				// Prepare image properties (transparent color)
				ImageAttributes attrib = new ImageAttributes();
				if(backImageTransparentColor != Color.Empty)
				{
					attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
				}
 
				// Draw scaled image
				RectangleF imageRect = new RectangleF();
				imageRect.X = fillRect.X;
				imageRect.Y = fillRect.Y;
				imageRect.Width = fillRect.Width;
				imageRect.Height = fillRect.Height;
 
				// Draw unscaled image using align property
				if(backImageWrapMode == ChartImageWrapMode.Unscaled)
				{
                    SizeF imageAbsSize = new SizeF();
 
                    ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageAbsSize);
 
					// Calculate image position
                    imageRect.Width = imageAbsSize.Width;
                    imageRect.Height = imageAbsSize.Height;
 
					// Adjust position with alignment property
					if(imageRect.Width < fillRect.Width)
					{
						if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
							backImageAlign == ChartImageAlignmentStyle.Right ||
							backImageAlign == ChartImageAlignmentStyle.TopRight)
						{
							imageRect.X = fillRect.Right - imageRect.Width;
						}
						else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
							backImageAlign == ChartImageAlignmentStyle.Center ||
							backImageAlign == ChartImageAlignmentStyle.Top)
						{
							imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
						}
					}
					if(imageRect.Height < fillRect.Height)
					{
						if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
							backImageAlign == ChartImageAlignmentStyle.Bottom ||
							backImageAlign == ChartImageAlignmentStyle.BottomLeft)
						{
							imageRect.Y = fillRect.Bottom - imageRect.Height;
						}
						else if(backImageAlign == ChartImageAlignmentStyle.Left ||
							backImageAlign == ChartImageAlignmentStyle.Center ||
							backImageAlign == ChartImageAlignmentStyle.Right)
						{
							imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
						}
					}
 
				}
 
				// Fill background with brush
				this.FillRectangle( brush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1);
 
				// Draw image
				this.DrawImage(image, 
					new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
					0, 0, image.Width, image.Height,
					GraphicsUnit.Pixel, 
					attrib);
			}
				// Draw rectangle
			else
			{
				if(backBrush != null && backImageTransparentColor != Color.Empty)
				{
					// Fill background with brush
					this.FillRectangle( backBrush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
				}
				this.FillRectangle( brush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
			}
 
			// Set pen alignment
			if(borderDashStyle != ChartDashStyle.NotSet)
			{
				if( borderWidth > 1 )
					this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
				else if( borderWidth == 1 )
					this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width, rect.Height );
			}
 
			// Dispose Image and Gradient
			if( backGradientStyle != GradientStyle.None )
			{
				brush.Dispose();
			}
			if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
			{
				brush.Dispose();
			}
			if( backHatchStyle != ChartHatchStyle.None )
			{
				brush.Dispose();
			}
 
			// Set Old Smoothing Mode
			this.SmoothingMode = oldMode;
		}
 
		/// <summary>
		/// Fills graphics path with shadow using absolute coordinates.
		/// </summary>
		/// <param name="path">Graphics path to fill.</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch Style</param>
		/// <param name="backImage">Image URL</param>
		/// <param name="backImageWrapMode">Image Mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment.</param>
		/// <param name="backGradientStyle">Gradient AxisName</param>
		/// <param name="backSecondaryColor">End Gradient color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="penAlignment">Border is outside or inside rectangle</param>
		/// <param name="shadowOffset">Shadow offset.</param>
		/// <param name="shadowColor">Shadow color.</param>
		internal void DrawPathAbs( 
			GraphicsPath path, 
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			ChartImageAlignmentStyle backImageAlign,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle, 
			PenAlignment penAlignment,
			int shadowOffset,
			Color shadowColor)
		{
			// Draw patj shadow
			if(shadowOffset != 0 && shadowColor != Color.Transparent)
			{
				// Save graphics state and apply translate transformation
				GraphicsState graphicsState = this.Save();
				this.TranslateTransform(shadowOffset, shadowOffset);
 
				if(backColor == Color.Transparent &&
					backSecondaryColor.IsEmpty )
				{
					this.DrawPathAbs(
						path,
						Color.Transparent,
						ChartHatchStyle.None,
						String.Empty,
						ChartImageWrapMode.Scaled,
						Color.Empty,
						ChartImageAlignmentStyle.Center,
						GradientStyle.None,
						Color.Empty,
						shadowColor,
						borderWidth,
						borderDashStyle,
						PenAlignment.Center);
				}
				else
				{
					this.DrawPathAbs(
						path,
						shadowColor,
						ChartHatchStyle.None,
						String.Empty,
						ChartImageWrapMode.Scaled,
						Color.Empty,
						ChartImageAlignmentStyle.Center,
						GradientStyle.None,
						Color.Empty,
						Color.Transparent,
						0,
						ChartDashStyle.NotSet,
						PenAlignment.Center);
				}
 
				// Restore graphics state
				this.Restore(graphicsState);
			}
 
			// Draw path
			this.DrawPathAbs(
				path,
				backColor, 
				backHatchStyle, 
				backImage, 
				backImageWrapMode, 
				backImageTransparentColor,
				backImageAlign,
				backGradientStyle, 
				backSecondaryColor, 
				borderColor, 
				borderWidth, 
				borderDashStyle, 
				penAlignment);
		}
 
		/// <summary>
		/// Fills graphics path using absolute coordinates.
		/// </summary>
		/// <param name="path">Graphics path to fill.</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch Style</param>
		/// <param name="backImage">Image URL</param>
		/// <param name="backImageWrapMode">Image Mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment.</param>
		/// <param name="backGradientStyle">Gradient AxisName</param>
		/// <param name="backSecondaryColor">End Gradient color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="penAlignment">Border is outside or inside rectangle</param>
		internal void DrawPathAbs( GraphicsPath path, 
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			ChartImageAlignmentStyle backImageAlign,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle, 
			PenAlignment penAlignment )
		{
			Brush brush = null;
			Brush backBrush = null;
 
			// Color is empty
			if( backColor.IsEmpty ) 
				backColor = Color.White;
 
			if( backSecondaryColor.IsEmpty ) 
				backSecondaryColor = Color.White;
 
			if( borderColor.IsEmpty ) 
			{
				borderColor = Color.White;
				borderWidth = 0;
			}
		
			// Set pen properties
			_pen.Color = borderColor;
			_pen.Width = borderWidth;
			_pen.Alignment = penAlignment;
			_pen.DashStyle = GetPenStyle( borderDashStyle );
 
			if( backGradientStyle == GradientStyle.None )
			{
				// Set solid brush color.
				_solidBrush.Color = backColor;
				brush = _solidBrush;
			}
			else
			{
				// If a gradient type  is set create a brush with gradient
				RectangleF pathRect = path.GetBounds();
				pathRect.Inflate(new SizeF(2,2));
				brush = GetGradientBrush( 
					pathRect, 
					backColor, 
					backSecondaryColor, 
					backGradientStyle );
			}
 
			if( backHatchStyle != ChartHatchStyle.None )
			{
				brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
			}
 
			if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
			{
				backBrush = brush;
				brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
			}
 
			// For inset alignment resize fill rectangle
			RectangleF fillRect = path.GetBounds();
			
			// Draw rectangle image
			if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
			{
				// Load image
System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
 
				// Prepare image properties (transparent color)
				ImageAttributes attrib = new ImageAttributes();
				if(backImageTransparentColor != Color.Empty)
				{
					attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
				}
 
				// Draw scaled image
				RectangleF imageRect = new RectangleF();
				imageRect.X = fillRect.X;
				imageRect.Y = fillRect.Y;
				imageRect.Width = fillRect.Width;
				imageRect.Height = fillRect.Height;
 
				// Draw unscaled image using align property
				if(backImageWrapMode == ChartImageWrapMode.Unscaled)
				{
                    SizeF imageSize = new SizeF();
 
                    ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageSize);
 
					// Calculate image position
                    imageRect.Width = imageSize.Width;
                    imageRect.Height = imageSize.Height;
 
					// Adjust position with alignment property
					if(imageRect.Width < fillRect.Width)
					{
						if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
							backImageAlign == ChartImageAlignmentStyle.Right ||
							backImageAlign == ChartImageAlignmentStyle.TopRight)
						{
							imageRect.X = fillRect.Right - imageRect.Width;
						}
						else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
							backImageAlign == ChartImageAlignmentStyle.Center ||
							backImageAlign == ChartImageAlignmentStyle.Top)
						{
							imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
						}
					}
					if(imageRect.Height < fillRect.Height)
					{
						if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
							backImageAlign == ChartImageAlignmentStyle.Bottom ||
							backImageAlign == ChartImageAlignmentStyle.BottomLeft)
						{
							imageRect.Y = fillRect.Bottom - imageRect.Height;
						}
						else if(backImageAlign == ChartImageAlignmentStyle.Left ||
							backImageAlign == ChartImageAlignmentStyle.Center ||
							backImageAlign == ChartImageAlignmentStyle.Right)
						{
							imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
						}
					}
 
				}
 
				// Fill background with brush
				this.FillPath( brush, path );
 
				// Draw image
				Region oldClipRegion = this.Clip;
				this.Clip = new Region(path);
				this.DrawImage(image, 
					new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
					0, 0, image.Width, image.Height,
					GraphicsUnit.Pixel, 
					attrib);
				this.Clip = oldClipRegion;
			}
			
				// Draw rectangle
			else
			{
				if(backBrush != null && backImageTransparentColor != Color.Empty)
				{
					// Fill background with brush
					this.FillPath( backBrush, path);
				}
				this.FillPath( brush, path);
			}
 
			// Draw border
			if(borderColor != Color.Empty && borderWidth > 0 && borderDashStyle != ChartDashStyle.NotSet)
			{
				this.DrawPath( _pen, path );
			}
		}
 
		/// <summary>
		/// Creates brush with specified properties.
		/// </summary>
		/// <param name="rect">Gradient rectangle</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch style</param>
		/// <param name="backImage">Back Image</param>
		/// <param name="backImageWrapMode">Image mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
		/// <param name="backGradientStyle">Gradient type </param>
		/// <param name="backSecondaryColor">Gradient End Color</param>
		/// <returns>New brush object.</returns>
		internal Brush CreateBrush( 
			RectangleF rect,
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor
			)
		{
			Brush brush = new SolidBrush(backColor);
 
			if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
			{
				brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
			}
			else if( backHatchStyle != ChartHatchStyle.None )
			{
				brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
			}
			else if( backGradientStyle != GradientStyle.None )
			{
				// If a gradient type  is set create a brush with gradient
				brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
			}
 
			return brush;
		}
 
		#endregion
 
		#region Coordinates converter
 
		/// <summary>
        /// This method takes a RectangleF structure that is using absolute coordinates 
        /// and returns a RectangleF object that uses relative coordinates.
		/// </summary>
        /// <param name="rectangle">RectangleF structure in absolute coordinates.</param>
        /// <returns>RectangleF structure in relative coordinates.</returns>
		public RectangleF GetRelativeRectangle( RectangleF rectangle )
		{
            // Check arguments
            if (rectangle == null)
                throw new ArgumentNullException("rectangle");
            
            RectangleF relative = RectangleF.Empty;
 
			// Convert absolute coordinates to relative coordinates
			relative.X = rectangle.X * 100F / ((float)(_width - 1)); 
			relative.Y = rectangle.Y * 100F / ((float)(_height - 1)); 
			relative.Width = rectangle.Width * 100F / ((float)(_width - 1)); 
			relative.Height = rectangle.Height * 100F / ((float)(_height - 1)); 
 
			// Return Relative coordinates
			return relative;
		}
 
		/// <summary>
        /// This method takes a PointF object that is using absolute coordinates 
        /// and returns a PointF object that uses relative coordinates.
		/// </summary>
		/// <param name="point">PointF object in absolute coordinates.</param>
		/// <returns>PointF object in relative coordinates.</returns>
		public PointF GetRelativePoint( PointF point )
		{
            // Check arguments
            if (point == null)
                throw new ArgumentNullException("point");
            
            PointF relative = PointF.Empty;
 
			// Convert absolute coordinates to relative coordinates
			relative.X = point.X * 100F / ((float)(_width - 1)); 
			relative.Y = point.Y * 100F / ((float)(_height - 1)); 
			
			// Return Relative coordinates
			return relative;
		}
 
 
		/// <summary>
        /// This method takes a SizeF object that uses absolute coordinates 
        /// and returns a SizeF object that uses relative coordinates.
		/// </summary>
		/// <param name="size">SizeF object in absolute coordinates.</param>
        /// <returns>SizeF object in relative coordinates.</returns>
		public SizeF GetRelativeSize( SizeF size )
		{
            // Check arguments
            if (size == null)
                throw new ArgumentNullException("size"); 
            
            SizeF relative = SizeF.Empty;
 
			// Convert absolute coordinates to relative coordinates
			relative.Width = size.Width * 100F / ((float)(_width - 1)); 
			relative.Height = size.Height * 100F / ((float)(_height - 1)); 
			
			// Return relative coordinates
			return relative;
		}
 
		/// <summary>
        /// This method takes a PointF object and converts its relative coordinates 
        /// to absolute coordinates.
		/// </summary>
        /// <param name="point">PointF object in relative coordinates.</param>
        /// <returns>PointF object in absolute coordinates.</returns>
		public PointF GetAbsolutePoint( PointF point )
		{
            // Check arguments
            if (point == null)
                throw new ArgumentNullException("point");
 
			PointF absolute = PointF.Empty;
 
			// Convert relative coordinates to absolute coordinates
			absolute.X = point.X * (_width - 1) / 100F; 
			absolute.Y = point.Y * (_height - 1) / 100F; 
 
			// Return Absolute coordinates
			return absolute;
		}
 
		/// <summary>
        /// This method takes a RectangleF structure and converts its relative coordinates 
        /// to absolute coordinates.
		/// </summary>
        /// <param name="rectangle">RectangleF object in relative coordinates.</param>
        /// <returns>RectangleF object in absolute coordinates.</returns>
		public RectangleF GetAbsoluteRectangle( RectangleF rectangle )
		{
            // Check arguments
            if (rectangle == null)
                throw new ArgumentNullException("rectangle");
 
			RectangleF absolute = RectangleF.Empty;
 
			// Convert relative coordinates to absolute coordinates
			absolute.X = rectangle.X * (_width - 1) / 100F; 
			absolute.Y = rectangle.Y * (_height - 1) / 100F; 
			absolute.Width = rectangle.Width * (_width - 1) / 100F; 
			absolute.Height = rectangle.Height * (_height - 1) / 100F; 
 
			// Return Absolute coordinates
			return absolute;
		}
 
		/// <summary>
        /// This method takes a SizeF object that uses relative coordinates
        /// and returns a SizeF object that uses absolute coordinates.
		/// </summary>
        /// <param name="size">SizeF object in relative coordinates.</param>
        /// <returns>SizeF object in absolute coordinates.</returns>
		public SizeF GetAbsoluteSize( SizeF size )
		{
            // Check arguments
            if (size == null)
                throw new ArgumentNullException("size"); 
            
            SizeF absolute = SizeF.Empty;
 
			// Convert relative coordinates to absolute coordinates
			absolute.Width = size.Width * (_width - 1) / 100F; 
			absolute.Height = size.Height * (_height - 1) / 100F; 
			
			// Return Absolute coordinates
			return absolute;
		}
 
	
		#endregion
 
		#region Border drawing helper methods
 
		/// <summary>
		/// Helper function which creates a rounded rectangle path.
		/// </summary>
		/// <param name="rect">Rectangle coordinates.</param>
		/// <param name="cornerRadius">Array of 4 corners radius.</param>
		/// <returns>Graphics path object.</returns>
		internal GraphicsPath CreateRoundedRectPath(RectangleF rect, float[] cornerRadius)
		{
			// Create rounded rectangle path
			GraphicsPath path = new GraphicsPath();
			path.AddLine(rect.X+cornerRadius[0], rect.Y, rect.Right-cornerRadius[1], rect.Y);
			path.AddArc(rect.Right-2f*cornerRadius[1], rect.Y, 2f*cornerRadius[1], 2f*cornerRadius[2], 270, 90);
			path.AddLine(rect.Right, rect.Y + cornerRadius[2], rect.Right, rect.Bottom - cornerRadius[3]);
			path.AddArc(rect.Right-2f*cornerRadius[4], rect.Bottom-2f*cornerRadius[3], 2f*cornerRadius[4], 2f*cornerRadius[3], 0, 90);
			path.AddLine(rect.Right-cornerRadius[4], rect.Bottom, rect.X + cornerRadius[5], rect.Bottom);
			path.AddArc(rect.X, rect.Bottom-2f*cornerRadius[6], 2f*cornerRadius[5], 2f*cornerRadius[6], 90, 90);
			path.AddLine(rect.X, rect.Bottom-cornerRadius[6], rect.X, rect.Y+cornerRadius[7]);
			path.AddArc(rect.X, rect.Y, 2f*cornerRadius[0], 2f*cornerRadius[7], 180, 90);
 
			return path;
		}
 
		/// <summary>
		/// Helper function which draws a shadow of the rounded rect.
		/// </summary>
		/// <param name="rect">Rectangle coordinates.</param>
		/// <param name="cornerRadius">Array of 4 corners radius.</param>
		/// <param name="radius">Rounding radius.</param>
		/// <param name="centerColor">Center color.</param>
		/// <param name="surroundColor">Surrounding color.</param>
		/// <param name="shadowScale">Shadow scale value.</param>
		internal void DrawRoundedRectShadowAbs(RectangleF rect, float[] cornerRadius, float radius, Color centerColor, Color surroundColor, float shadowScale)
		{
			// Create rounded rectangle path
			GraphicsPath path = CreateRoundedRectPath(rect, cornerRadius);
 
			// Create gradient brush
			PathGradientBrush shadowBrush = new PathGradientBrush(path);
			shadowBrush.CenterColor = centerColor;
 
			// Set the color along the entire boundary of the path
			Color[] colors = {surroundColor};
			shadowBrush.SurroundColors = colors;
			shadowBrush.CenterPoint = new PointF(rect.X + rect.Width/2f, rect.Y + rect.Height/2f);
 
			// Define brush focus scale
			PointF focusScale = new PointF(1-shadowScale*radius/rect.Width, 1-shadowScale*radius/rect.Height);
			shadowBrush.FocusScales = focusScale;
 
			// Draw rounded rectangle
			this.FillPath(shadowBrush, path);
 
			if( path != null )
			{
				path.Dispose();
			}
		}
 
		/// <summary>
		/// Draws 3D border in absolute coordinates.
		/// </summary>
		/// <param name="borderSkin">Border skin object.</param>
		/// <param name="rect">Rectangle of the border (pixel coordinates).</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch style</param>
		/// <param name="backImage">Back Image</param>
		/// <param name="backImageWrapMode">Image mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment</param>
		/// <param name="backGradientStyle">Gradient type </param>
		/// <param name="backSecondaryColor">Gradient End Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		internal void Draw3DBorderRel(
			BorderSkin borderSkin, 
			RectangleF rect, 
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			ChartImageAlignmentStyle backImageAlign,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle)
		{
			Draw3DBorderAbs(borderSkin, GetAbsoluteRectangle(rect), backColor, backHatchStyle, 
				backImage, backImageWrapMode, backImageTransparentColor, backImageAlign, backGradientStyle, 
				backSecondaryColor, borderColor, borderWidth, borderDashStyle);
		}
 
 
		/// <summary>
		/// Draws 3D border in absolute coordinates.
		/// </summary>
		/// <param name="borderSkin">Border skin object.</param>
		/// <param name="absRect">Rectangle of the border (pixel coordinates).</param>
		/// <param name="backColor">Color of rectangle</param>
		/// <param name="backHatchStyle">Hatch style</param>
		/// <param name="backImage">Back Image</param>
		/// <param name="backImageWrapMode">Image mode</param>
		/// <param name="backImageTransparentColor">Image transparent color.</param>
        /// <param name="backImageAlign">Image alignment</param>
		/// <param name="backGradientStyle">Gradient type </param>
		/// <param name="backSecondaryColor">Gradient End Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		internal void Draw3DBorderAbs(
			BorderSkin borderSkin, 
			RectangleF absRect, 
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			ChartImageAlignmentStyle backImageAlign,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle)
		{
			// Check input parameters
			if(_common == null || borderSkin.SkinStyle == BorderSkinStyle.None || absRect.Width == 0 || absRect.Height == 0)
			{
				return;
			}
 
			// Find required border interface
			IBorderType	borderTypeInterface = _common.BorderTypeRegistry.GetBorderType(borderSkin.SkinStyle.ToString());
			if(borderTypeInterface != null)
			{
                borderTypeInterface.Resolution = this.Graphics.DpiX;
				// Draw border
				borderTypeInterface.DrawBorder(this, borderSkin, absRect, backColor, backHatchStyle, backImage, backImageWrapMode, 
					backImageTransparentColor, backImageAlign, backGradientStyle, backSecondaryColor, 
					borderColor, borderWidth, borderDashStyle);
			}
		}
 
		#endregion
 
		#region Pie Method
 
		/// <summary>
		/// Helper function that retrieves pie drawing style.
		/// </summary>
		/// <param name="point">Data point to get the drawing style for.</param>
		/// <returns>pie drawing style.</returns>
		internal static PieDrawingStyle GetPieDrawingStyle(DataPoint point)
		{
			// Get column drawing style
			PieDrawingStyle pieDrawingStyle = PieDrawingStyle.Default;
			string styleName = point[CustomPropertyName.PieDrawingStyle];
			if(styleName != null)
			{
				if(String.Compare(styleName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
				{
					pieDrawingStyle = PieDrawingStyle.Default;
				}
                else if (String.Compare(styleName, "SoftEdge", StringComparison.OrdinalIgnoreCase) == 0)
				{
					pieDrawingStyle = PieDrawingStyle.SoftEdge;
				}
                else if (String.Compare(styleName, "Concave", StringComparison.OrdinalIgnoreCase) == 0)
				{
					pieDrawingStyle = PieDrawingStyle.Concave;
				}					
				else
				{
					throw( new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid( styleName, "PieDrawingStyle")));
				}
			}
			return pieDrawingStyle;
		}
 
		/// <summary>
		/// Draws a pie defined by an ellipse specified by a Rectangle structure and two radial lines.
		/// </summary>
		/// <param name="rect">Rectangle structure that represents the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
		/// <param name="startAngle">Angle measured in degrees clockwise from the x-axis to the first side of the pie shape.</param>
		/// <param name="sweepAngle">Angle measured in degrees clockwise from the startAngle parameter to the second side of the pie shape.</param>
		/// <param name="backColor">Fill color</param>
		/// <param name="backHatchStyle">Fill Hatch Style</param>
		/// <param name="backImage">Fill texture</param>
		/// <param name="backImageWrapMode">Texture image mode</param>
		/// <param name="backImageTransparentColor">Texture transparent color</param>
		/// <param name="backGradientStyle">Fill Gradient type </param>
		/// <param name="backSecondaryColor">Fill Gradient Second Color</param>
		/// <param name="borderColor">Border Color</param>
		/// <param name="borderWidth">Border Width</param>
		/// <param name="borderDashStyle">Border Style</param>
		/// <param name="shadow">True if shadow is active</param>
		/// <param name="doughnut">True if Doughnut is drawn instead of pie</param>
		/// <param name="doughnutRadius">Internal radius of the doughnut</param>
		/// <param name="pieDrawingStyle">Pie drawing style.</param>
		internal void DrawPieRel( 
			RectangleF rect, 
			float startAngle,
			float sweepAngle,
			Color backColor, 
			ChartHatchStyle backHatchStyle, 
			string backImage, 
			ChartImageWrapMode backImageWrapMode, 
			Color backImageTransparentColor,
			GradientStyle backGradientStyle, 
			Color backSecondaryColor, 
			Color borderColor, 
			int borderWidth, 
			ChartDashStyle borderDashStyle, 
			bool shadow,
			bool doughnut,
			float doughnutRadius,
			PieDrawingStyle pieDrawingStyle
			)
		{
			Pen borderPen = null;	// Pen
			Brush fillBrush;		// Brush
 
			// Get absolute rectangle
			RectangleF absRect = GetAbsoluteRectangle( rect );
 
			if( doughnutRadius == 100.0 )
			{
				doughnut = false;
			}
 
			if( doughnutRadius == 0.0 )
			{
				return;
			}
 
			// Create Brush
			if( backHatchStyle != ChartHatchStyle.None )
			{
				// Create Hatch Brush
				fillBrush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
			}
			else if( backGradientStyle != GradientStyle.None ) 
			{ 
				// Create gradient brush
				if( backGradientStyle == GradientStyle.Center )
				{
					fillBrush = GetPieGradientBrush( absRect, backColor, backSecondaryColor );
				}
				else
				{
                    using (GraphicsPath path = new GraphicsPath())
                    {
                        path.AddPie(absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle);
                        fillBrush = GetGradientBrush(path.GetBounds(), backColor, backSecondaryColor, backGradientStyle);
                    }
				}
			}
			else if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled )
			{ 
				// Create textured brush
				fillBrush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
			}
			else
			{
				// Create solid brush
				fillBrush = new SolidBrush( backColor );
			}
 
			// Create border Pen
			borderPen = new Pen( borderColor, borderWidth );
			
			// Set a border line style
			borderPen.DashStyle = GetPenStyle( borderDashStyle );
 
			// Use rounded line joins
			borderPen.LineJoin = LineJoin.Round;
 
			// Draw Doughnut
			if( doughnut )
			{
                using (GraphicsPath path = new GraphicsPath())
                {
 
                    path.AddArc(absRect.X + absRect.Width * doughnutRadius / 200 - 1, absRect.Y + absRect.Height * doughnutRadius / 200 - 1, absRect.Width - absRect.Width * doughnutRadius / 100 + 2, absRect.Height - absRect.Height * doughnutRadius / 100 + 2, startAngle, sweepAngle);
                    path.AddArc(absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle + sweepAngle, -sweepAngle);
 
                    path.CloseFigure();
 
                    this.FillPath(fillBrush, path);
 
 
                    // Draw Pie gradien effects
                    this.DrawPieGradientEffects(pieDrawingStyle, absRect, startAngle, sweepAngle, doughnutRadius);
 
                    // Draw Doughnut Border
                    if (!shadow &&
                        borderWidth > 0 &&
                        borderDashStyle != ChartDashStyle.NotSet)
                    {
                        this.DrawPath(borderPen, path);
                    }
                }
			}
			else // Draw Pie
			{
 
				// Draw Soft shadow for pie slice
				if( shadow && softShadows )
				{
					DrawPieSoftShadow( startAngle, sweepAngle, absRect, backColor );
				}
				else 
				{
					// Fill Pie for normal shadow or colored pie slice
					this.FillPie( fillBrush, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
 
					// Draw Pie gradien effects
					this.DrawPieGradientEffects( pieDrawingStyle, absRect, startAngle, sweepAngle, -1f);
				}
 
				
				// Draw Pie Border
				if( !shadow  &&
					borderWidth > 0 &&
					borderDashStyle != ChartDashStyle.NotSet)
				{
					this.DrawPie( borderPen, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
				}
			}
 
			// Dispose graphics objects
			if( borderPen != null )
			{
				borderPen.Dispose();
			}
 
			if( fillBrush != null )
			{
				fillBrush.Dispose();
			}
		}
 
		private void DrawPieGradientEffects( 
			PieDrawingStyle pieDrawingStyle, 
			RectangleF position, 
			float startAngle, 
			float sweepAngle,
			float doughnutRadius)
		{
			if(pieDrawingStyle == PieDrawingStyle.Concave)
			{
				// Calculate the size of the shadow. Note: For Doughnut chart shadow is drawn 
				// twice on the outside and inside radius.
				float minSize = (float)Math.Min(position.Width, position.Height);
				float shadowSize = minSize * 0.05f;
			
				// Create brush path
				RectangleF gradientPath = position;
				gradientPath.Inflate(-shadowSize, -shadowSize);
				using(GraphicsPath brushPath = new GraphicsPath())
				{
					brushPath.AddEllipse(gradientPath);
 
					// Create shadow path
					using(GraphicsPath path = new GraphicsPath())
					{
						if(doughnutRadius < 0f)
						{
							path.AddPie(Rectangle.Round(gradientPath), startAngle, sweepAngle);
						}
						else
						{
							path.AddArc( 
								gradientPath.X + position.Width * doughnutRadius /200 - 1 - shadowSize, 
								gradientPath.Y + position.Height * doughnutRadius /200 - 1 - shadowSize, 
								gradientPath.Width - position.Width * doughnutRadius / 100 + 2 + 2f * shadowSize, 
								gradientPath.Height - position.Height * doughnutRadius / 100 + 2 + 2f * shadowSize, 
								startAngle, 
								sweepAngle );
							path.AddArc( gradientPath.X, gradientPath.Y, gradientPath.Width, gradientPath.Height, startAngle + sweepAngle, -sweepAngle );
						}
 
						// Create linear gradient brush
						gradientPath.Inflate(1f, 1f);
						using(LinearGradientBrush brush = new LinearGradientBrush(
								  gradientPath, 
								  Color.Red,
								  Color.Green, 
								  LinearGradientMode.Vertical) )
						{
							ColorBlend colorBlend = new ColorBlend(3);
							colorBlend.Colors[0] = Color.FromArgb(100, Color.Black);
							colorBlend.Colors[1] = Color.Transparent;
							colorBlend.Colors[2] = Color.FromArgb(140, Color.White);
							colorBlend.Positions[0] = 0f;
							colorBlend.Positions[1] = 0.5f;
							colorBlend.Positions[2] = 1f;
							brush.InterpolationColors = colorBlend;
 
							// Fill shadow
							this.FillPath( brush, path );
 
						}
					}
				}			
			}
			else if(pieDrawingStyle == PieDrawingStyle.SoftEdge)
			{
				// Calculate the size of the shadow. Note: For Doughnut chart shadow is drawn 
				// twice on the outside and inside radius.
				float minSize = (float)Math.Min(position.Width, position.Height);
				float shadowSize = minSize/10f;
				if(doughnutRadius > 0f)
				{
					shadowSize = (minSize * doughnutRadius / 100f) / 8f;
				}
 
				// Create brush path
				using(GraphicsPath brushPath = new GraphicsPath())
				{
					brushPath.AddEllipse(position);
 
					// Create shadow path
					using(GraphicsPath path = new GraphicsPath())
					{
						path.AddArc( position.X + shadowSize, position.Y + shadowSize, position.Width - shadowSize * 2f, position.Height - shadowSize * 2f, startAngle, sweepAngle );
						path.AddArc( position.X, position.Y, position.Width, position.Height, startAngle + sweepAngle, -sweepAngle );
						path.CloseFigure();
 
						// Create shadow brush
						using( PathGradientBrush brush = new PathGradientBrush(brushPath) )
						{
							brush.CenterColor = Color.Transparent;
							brush.SurroundColors = new Color[] { Color.FromArgb(100, Color.Black) };
 
							Blend blend = new Blend(3);
							blend.Positions[0] = 0f;
							blend.Factors[0] = 0f;
							blend.Positions[1] = shadowSize / (minSize / 2f);
							blend.Factors[1] = 1f;
							blend.Positions[2] = 1f;
							blend.Factors[2] = 1f;
							brush.Blend = blend;
 
							// Fill shadow
							this.FillPath( brush, path );
						}
					}
 
					// Draw inner shadow for the doughnut chart
					if(doughnutRadius > 0f)
					{
						// Create brush path
						using(GraphicsPath brushInsidePath = new GraphicsPath())
						{
							RectangleF innerPosition = position;
							innerPosition.Inflate(- position.Width * doughnutRadius / 200f + shadowSize, -position.Height * doughnutRadius / 200f + shadowSize);
							brushInsidePath.AddEllipse(innerPosition);
 
							// Create shadow path
							using(GraphicsPath path = new GraphicsPath())
							{
								path.AddArc( innerPosition.X + shadowSize, innerPosition.Y + shadowSize, innerPosition.Width - 2f * shadowSize, innerPosition.Height - 2f * shadowSize, startAngle, sweepAngle );
								path.AddArc( innerPosition.X, innerPosition.Y, innerPosition.Width, innerPosition.Height, startAngle + sweepAngle, -sweepAngle );
								path.CloseFigure();
 
								// Create shadow brush
								using( PathGradientBrush brushInner = new PathGradientBrush(brushInsidePath) )
								{
									brushInner.CenterColor = Color.FromArgb(100, Color.Black);
									brushInner.SurroundColors = new Color[] { Color.Transparent };
 
									Blend blend = new Blend(3);
									blend.Positions[0] = 0f;
									blend.Factors[0] = 0f;
									blend.Positions[1] = shadowSize / (innerPosition.Width / 2f);
									blend.Factors[1] = 1f;
									blend.Positions[2] = 1f;
									blend.Factors[2] = 1f;
									brushInner.Blend = blend;
 
									// Fill shadow
									this.FillPath( brushInner, path );
								}
							}
						}
					}
				}
			}
		}
 
		/// <summary>
		/// The soft shadow of the pie 
		/// </summary>
		/// <param name="startAngle">Angle measured in degrees clockwise from the x-axis to the first side of the pie shape.</param>
		/// <param name="sweepAngle">Angle measured in degrees clockwise from the startAngle parameter to the second side of the pie shape.</param>
		/// <param name="absRect">Rectangle of the pie in absolute coordinates</param>
		/// <param name="backColor">Fill color</param>
		private void DrawPieSoftShadow( float startAngle, float sweepAngle, RectangleF absRect, Color backColor )
		{
			GraphicsPath path = new GraphicsPath();
			
			path.AddEllipse( absRect.X, absRect.Y, absRect.Width, absRect.Height );
 
			PathGradientBrush brush = new PathGradientBrush( path );
		
			Color[] colors = {
								Color.FromArgb( 0, backColor ),
								Color.FromArgb( backColor.A, backColor ),   
								Color.FromArgb( backColor.A, backColor )}; 
 
			float[] relativePositions = {
											0f,       
											0.05f,     
											1.0f};    // at the center point.
 
			ColorBlend colorBlend = new ColorBlend();
			colorBlend.Colors = colors;
			colorBlend.Positions = relativePositions;
			brush.InterpolationColors = colorBlend;
 
			this.FillPie( brush, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
		}
 
		#endregion
 
		#region Arrow Methods
 
		/// <summary>
		/// Draw Arrow.
		/// </summary>
		/// <param name="position">Position of the arrow</param>
		/// <param name="orientation">Orientation of the arrow - left, right, top, bottom </param>
        /// <param name="type">Arrow style: Triangle, Sharp Triangle, Lines</param>
		/// <param name="color">Color of the arrow</param>
		/// <param name="lineWidth">Line width</param>
		/// <param name="lineDashStyle">Line Dash style</param>
		/// <param name="shift">Distance from the chart area</param>
		/// <param name="size">Arrow size</param>
		internal void DrawArrowRel( PointF position, ArrowOrientation orientation, AxisArrowStyle type, Color color, int lineWidth, ChartDashStyle lineDashStyle, double shift, double size )
		{
			// Check if arrow should be drawn
			if(type == AxisArrowStyle.None)
			{
				return;
			}
 
			// Set a color
            using (SolidBrush brush = new SolidBrush(color))
            {
                PointF endPoint = PointF.Empty; // End point of axis line
                PointF[] points; // arrow points
                PointF absolutePosition; // Absolute position of axis
 
                absolutePosition = GetAbsolutePoint(position);
 
                // Arrow type is triangle
                if (type == AxisArrowStyle.Triangle)
                {
                    points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
 
                    endPoint = GetRelativePoint(endPoint);
 
                    // Draw center line
                    DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
 
                    // Draw arrow
                    this.FillPolygon(brush, points);
 
                }
                // Arrow type is sharp triangle
                else if (type == AxisArrowStyle.SharpTriangle)
                {
                    points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
 
                    endPoint = GetRelativePoint(endPoint);
 
                    // Draw center line
                    DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
 
                    // Draw arrow
                    this.FillPolygon(brush, points);
 
                }
                // Arrow type is 'Lines'
                else if (type == AxisArrowStyle.Lines)
                {
                    points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
 
                    points[0] = GetRelativePoint(points[0]);
                    points[1] = GetRelativePoint(points[1]);
                    points[2] = GetRelativePoint(points[2]);
 
                    endPoint = GetRelativePoint(endPoint);
 
                    // Draw arrow
                    DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
                    DrawLineRel(color, lineWidth, lineDashStyle, points[0], points[2]);
                    DrawLineRel(color, lineWidth, lineDashStyle, points[1], points[2]);
 
                }
            }
		}
 
		/// <summary>
		/// This function calculates points for polygon, which represents 
		/// shape of an arrow. There are four different orientations 
		/// of arrow and three arrow types.
		/// </summary>
		/// <param name="position">Arrow position</param>
		/// <param name="orientation">Arrow orientation ( Left, Right, Top, Bottom )</param>
		/// <param name="shift">Distance from chart area to the arrow</param>
		/// <param name="size">Arrow size</param>
        /// <param name="type">Arrow style.</param>
		/// <param name="endPoint">End point of the axis and the beginning of arrow</param>
		/// <returns>Polygon points</returns>
		private PointF[] GetArrowShape( PointF position, ArrowOrientation orientation, double shift, double size, AxisArrowStyle type, ref PointF endPoint )
		{
			PointF[] points = new PointF[3]; // Polygon points
			double sharp; // Size for sharp triangle
 
			// Four different orientations for AxisArrowStyle
			switch( orientation )
			{
					// Top orientation
				case ArrowOrientation.Top:
					// Get absolute size for arrow
					// Arrow size has to have the same shape when width and height 
					// are changed. When the picture is resized, width of the chart 
					// picture is used only for arrow size.
					size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
					shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Height;
 
					// Size for sharp and regular triangle
					if( type == AxisArrowStyle.SharpTriangle )
						sharp = size * 4;
					else
						sharp = size * 2;
 
					points[0].X = position.X - (float)size;
					points[0].Y = position.Y - (float)shift;
					points[1].X = position.X + (float)size;
					points[1].Y = position.Y - (float)shift;
					points[2].X = position.X;
					points[2].Y = position.Y - (float)shift - (float)sharp;
					// End of the axis line
					endPoint.X = position.X;
					if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
						endPoint.Y = points[1].Y;
					else
						endPoint.Y = points[2].Y;
					
					break;
					// Bottom orientation
				case ArrowOrientation.Bottom:
					// Get absolute size for arrow
					// Arrow size has to have the same shape when width and height 
					// are changed. When the picture is resized, width of the chart 
					// picture is used only for arrow size.
					size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
					shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Height;
 
					// Size for sharp and regular triangle
					if( type == AxisArrowStyle.SharpTriangle )
						sharp = size * 4;
					else
						sharp = size * 2;
 
					points[0].X = position.X - (float)size;
					points[0].Y = position.Y + (float)shift;
					points[1].X = position.X + (float)size;
					points[1].Y = position.Y + (float)shift;
					points[2].X = position.X;
					points[2].Y = position.Y + (float)shift + (float)sharp;
					// End of the axis line
					endPoint.X = position.X;
					if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
						endPoint.Y = points[1].Y;
					else
						endPoint.Y = points[2].Y;
					break;
					// Left orientation
				case ArrowOrientation.Left:
					// Get absolute size for arrow
					size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
					shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Width;
 
					// Size for sharp and regular triangle
					if( type == AxisArrowStyle.SharpTriangle )
						sharp = size * 4;
					else
						sharp = size * 2;
 
					points[0].Y = position.Y - (float)size;
					points[0].X = position.X - (float)shift;
					points[1].Y = position.Y + (float)size;
					points[1].X = position.X - (float)shift;
					points[2].Y = position.Y;
					points[2].X = position.X - (float)shift - (float)sharp;
					// End of the axis line
					endPoint.Y = position.Y;
					if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
						endPoint.X = points[1].X;
					else
						endPoint.X = points[2].X;
					break;
					// Right orientation
				case ArrowOrientation.Right:
					// Get absolute size for arrow
					size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
					shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Width;
 
					// Size for sharp and regular triangle
					if( type == AxisArrowStyle.SharpTriangle )
						sharp = size * 4;
					else
						sharp = size * 2;
 
					points[0].Y = position.Y - (float)size;
					points[0].X = position.X + (float)shift;
					points[1].Y = position.Y + (float)size;
					points[1].X = position.X + (float)shift;
					points[2].Y = position.Y;
					points[2].X = position.X + (float)shift + (float)sharp;
					// End of the axis line
					endPoint.Y = position.Y;
					if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
						endPoint.X = points[1].X;
					else
						endPoint.X = points[2].X;
					break;
			}
 
			return points;
		}
 
		#endregion
		
		#region Other methods and properties
 
		/// <summary>
		/// Helper function that retrieves bar drawing style.
		/// </summary>
		/// <param name="point">Data point to get the drawing style for.</param>
		/// <returns>Bar drawing style.</returns>
		internal static BarDrawingStyle GetBarDrawingStyle(DataPoint point)
		{
			// Get column drawing style
			BarDrawingStyle barDrawingStyle = BarDrawingStyle.Default;
			string styleName = point[CustomPropertyName.DrawingStyle];
			if(styleName != null)
			{
				if(String.Compare(styleName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
				{
					barDrawingStyle = BarDrawingStyle.Default;
				}
                else if (String.Compare(styleName, "Cylinder", StringComparison.OrdinalIgnoreCase) == 0)
				{
					barDrawingStyle = BarDrawingStyle.Cylinder;
				}
                else if (String.Compare(styleName, "Emboss", StringComparison.OrdinalIgnoreCase) == 0)
				{
					barDrawingStyle = BarDrawingStyle.Emboss;
				}
                else if (String.Compare(styleName, "LightToDark", StringComparison.OrdinalIgnoreCase) == 0)
				{
					barDrawingStyle = BarDrawingStyle.LightToDark;
				}
                else if (String.Compare(styleName, "Wedge", StringComparison.OrdinalIgnoreCase) == 0)
				{
					barDrawingStyle = BarDrawingStyle.Wedge;
				}
				else
				{
                    throw (new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid(styleName, "DrawingStyle")));
				}
			}
			return barDrawingStyle;
		}
 
 
		/// <summary>
		/// Find rounding coordinates for a rectangle
		/// </summary>
		/// <param name="rect">Rectangle which has to be rounded</param>
		/// <returns>Rounded rectangle</returns>
		internal RectangleF Round(RectangleF rect)
		{
			float	left = (float)Math.Round( (double)rect.Left );
			float	right = (float)Math.Round( (double)rect.Right );
			float	top = (float)Math.Round( (double)rect.Top );
			float	bottom = (float)Math.Round( (double)rect.Bottom );
 
			return new RectangleF( left, top, right - left, bottom - top ); 
		}
		
		/// <summary>
        /// This method takes a given axis value for a specified axis and returns the relative pixel value.
		/// </summary>
		/// <param name="chartAreaName">Chart area name.</param>
        /// <param name="axis">An AxisName enum value that identifies the relevant axis.</param>
        /// <param name="axisValue">The axis value that needs to be converted to a relative pixel value.</param>
		/// <returns>The converted axis value, in relative pixel coordinates.</returns>
		public double GetPositionFromAxis( string chartAreaName, AxisName axis, double axisValue )
		{
			if( axis == AxisName.X )
				return _common.ChartPicture.ChartAreas[chartAreaName].AxisX.GetLinearPosition( axisValue );
 
			if( axis == AxisName.X2 )
				return _common.ChartPicture.ChartAreas[chartAreaName].AxisX2.GetLinearPosition( axisValue );
 
			if( axis == AxisName.Y )
				return _common.ChartPicture.ChartAreas[chartAreaName].AxisY.GetLinearPosition( axisValue );
 
			if( axis == AxisName.Y2 )
				return _common.ChartPicture.ChartAreas[chartAreaName].AxisY2.GetLinearPosition( axisValue );
 
			return 0;
		}
 
		/// <summary>
		/// Set picture size
		/// </summary>
		/// <param name="width">Width</param>
		/// <param name="height">Height</param>
		internal void SetPictureSize( int width, int height )
		{
			this._width = width;
			this._height = height;
		}
 
		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="common">Common elements class</param>
		internal ChartGraphics(CommonElements common)
		{
			// Set Common elements
			this._common = common;
            base.Common = common;
			// Create a pen object
			_pen = new Pen(Color.Black);
 
			// Create a brush object
			_solidBrush = new SolidBrush(Color.Black);
		}
 
		/// <summary>
		/// Chart Graphics Anti alias mode
		/// </summary>
		internal AntiAliasingStyles AntiAliasing
		{
			get
			{
				return _antiAliasing;
			}
			set
			{
				_antiAliasing = value;
 
				// Graphics mode not set
				if( Graphics == null )
					return;
 
				// Convert Chart's anti alias enumeration to GDI+ SmoothingMode
				if( (_antiAliasing & AntiAliasingStyles.Graphics) == AntiAliasingStyles.Graphics )
				{
					this.SmoothingMode = SmoothingMode.AntiAlias;
				}
				else
				{
					this.SmoothingMode = SmoothingMode.None;
				}
			}
		}
 
        /// <summary>
        /// Gets reusable pen.
        /// </summary>
        internal Pen Pen
        {
            get { return _pen; }
        }
 
		/// <summary>
		/// Sets the clipping region of this Graphics object 
		/// to the rectangle specified by a RectangleF structure.
		/// </summary>
		/// <param name="region">Region rectangle</param>
		internal void SetClip( RectangleF region )
		{
			this.SetClipAbs( GetAbsoluteRectangle( region ) );
		}
	
		#endregion
 
		#region Color manipulation methods
 
        /// <summary>
        /// Returns the gradient color from a gradient position.
        /// </summary>
        /// <param name="beginColor">The color from the gradient beginning</param>
        /// <param name="endColor">The color from the gradient end.</param>
        /// <param name="relativePosition">The relative position.</param>
        /// <returns>Result color.</returns>
        static internal Color GetGradientColor(Color beginColor, Color endColor, double relativePosition)
		{
			// Check if position is valid
			if(relativePosition < 0 || relativePosition > 1 || double.IsNaN(relativePosition))
			{
				return beginColor;
			}
			
			// Extracts Begin color
			int nBRed = beginColor.R;
			int nBGreen = beginColor.G;
			int nBBlue = beginColor.B;
 
			// Extracts End color
			int nERed = endColor.R;
			int nEGreen = endColor.G;
			int nEBlue = endColor.B;
 
			// Gradient positions for Red, Green and Blue colors
			double dRRed = nBRed + (nERed - nBRed) * relativePosition;
			double dRGreen = nBGreen + (nEGreen - nBGreen) * relativePosition;
			double dRBlue = nBBlue + (nEBlue - nBBlue) * relativePosition;
 
			// Make sure colors are in range from 0 to 255
			if(dRRed > 255.0)
				dRRed = 255.0;
			if(dRRed < 0.0)
				dRRed = 0.0;
			if(dRGreen > 255.0)
				dRGreen = 255.0;
			if(dRGreen < 0.0)
				dRGreen = 0.0;
			if(dRBlue > 255.0)
				dRBlue = 255.0;
			if(dRBlue < 0.0)
				dRBlue = 0.0;
 
			// Return a gradient color position
			return Color.FromArgb(beginColor.A, (int)dRRed, (int)dRGreen, (int)dRBlue);
		}
 
		#endregion
 
        #region RightToLeft
        /// <summary>
        /// Returns chart right to left flag 
        /// </summary>
        internal bool IsRightToLeft
        {
            get
            {
                if (Common == null)
                {
                    return false;
                }
                return Common.ChartPicture.RightToLeft == RightToLeft.Yes;
            }
        }
        
        #endregion //RightToLeft
 
        #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)
            {   
                // Free up managed resources
                if (_pen != null)
                {
                    _pen.Dispose();
                    _pen = null;
                }
                if (_solidBrush != null)
                {
                    _solidBrush.Dispose();
                    _solidBrush = null;
                }
                if (_myMatrix != null)
                {
                    _myMatrix.Dispose();
                    _myMatrix = null;
                }
            }
            base.Dispose(disposing);
        }
 
        #endregion
    }
}