Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web.DataVisualization / Common / General / ChartGraphics.cs
1 //-------------------------------------------------------------
2 // <copyright company=\92Microsoft Corporation\92>
3 //   Copyright © Microsoft Corporation. All Rights Reserved.
4 // </copyright>
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
8 //  File:               ChartGraphics.cs
9 //
10 //  Namespace:  System.Web.UI.WebControls[Windows.Forms].Charting
11 //
12 //      Classes:        ChartGraphics
13 //
14 //  Purpose:    Chart graphic class is used for drawing Chart 
15 //                              elements as Rectangles, Pie slices, lines, areas 
16 //                              etc. This class is used in all classes where 
17 //                              drawing is necessary. The GDI+ graphic class is 
18 //                              used throw this class. Encapsulates a GDI+ chart 
19 //                              drawing functionality
20 //
21 //      Reviewed:       GS - Jul 31, 2002
22 //                              AG - August 7, 2002
23 //              AG - Microsoft 16, 2007
24 //
25 //===================================================================
26
27 #region Used namespaces
28
29 using System;
30 using System.Drawing;
31 using System.Drawing.Drawing2D;
32 using System.Drawing.Text;
33 using System.Drawing.Imaging;
34 using System.Diagnostics.CodeAnalysis;
35
36 #if Microsoft_CONTROL
37     using System.Windows.Forms.DataVisualization.Charting.Utilities;
38     using System.Windows.Forms.DataVisualization.Charting.Borders3D;
39 #else
40         using System.Web.UI.DataVisualization.Charting.Utilities;
41         using System.Web.UI.DataVisualization.Charting.Borders3D;
42 #endif
43
44 #endregion
45
46 #if Microsoft_CONTROL
47         namespace System.Windows.Forms.DataVisualization.Charting
48 #else
49 namespace System.Web.UI.DataVisualization.Charting
50
51 #endif
52 {
53         #region Enumerations
54
55         /// <summary>
56         /// Defines the style how the bars/columns are drawn.
57         /// </summary>
58     internal enum BarDrawingStyle
59         {
60                 /// <summary>
61                 /// Default bar/column style.
62                 /// </summary>
63                 Default,
64
65                 /// <summary>
66                 /// Cylinder bar/column style.
67                 /// </summary>
68                 Cylinder,
69
70                 /// <summary>
71                 /// Emboss bar/column style.
72                 /// </summary>
73                 Emboss,
74
75                 /// <summary>
76                 /// LightToDark bar/column style.
77                 /// </summary>
78                 LightToDark,
79                 
80                 /// <summary>
81                 /// Wedge bar/column style.
82                 /// </summary>
83                 Wedge,
84         }
85
86         /// <summary>
87         /// Defines the style how the pie and doughnut charts are drawn.
88         /// </summary>
89     internal enum PieDrawingStyle
90         {
91                 /// <summary>
92                 /// Default pie/doughnut drawing style.
93                 /// </summary>
94                 Default,
95
96         /// <summary>
97         /// Soft edge shadow is drawn on the edges of the pie/doughnut slices.
98         /// </summary>
99                 SoftEdge,
100
101                 /// <summary>
102                 /// A shadow is drawn from the top to the bottom of the pie/doughnut chart.
103                 /// </summary>
104                 Concave,
105         }
106
107         /// <summary>
108         /// An enumeration of line styles.
109         /// </summary>
110         public enum ChartDashStyle
111         {
112                 /// <summary>
113                 /// Line style not set
114                 /// </summary>
115                 NotSet,
116                 /// <summary>
117                 /// Specifies a line consisting of dashes. 
118                 /// </summary>
119                 Dash,
120                 /// <summary>
121                 /// Specifies a line consisting of a repeating pattern of dash-dot. 
122                 /// </summary>
123                 DashDot,
124                 /// <summary>
125                 /// Specifies a line consisting of a repeating pattern of dash-dot-dot. 
126                 /// </summary>
127                 DashDotDot,
128                 /// <summary>
129                 /// Specifies a line consisting of dots. 
130                 /// </summary>
131                 Dot,
132                 /// <summary>
133                 /// Specifies a solid line. 
134                 /// </summary>
135                 Solid,
136         }
137
138         #endregion
139
140         /// <summary>
141     /// The ChartGraphics class provides all chart drawing capabilities. 
142     /// It contains methods for drawing 2D primitives and also exposes 
143     /// all ChartGraphics3D class methods for 3D shapes. Only this 
144     /// class should be used for any drawing in the chart.
145         /// </summary>
146 #if ASPPERM_35
147         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
148     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
149 #endif
150     public partial class ChartGraphics : ChartElement
151         {
152                 #region Fields
153
154                 // Common Elements
155                 private CommonElements          _common;
156
157                 // Reusable objects
158                 private Pen                 _pen;
159                 private SolidBrush                      _solidBrush;
160                 private Matrix                          _myMatrix;
161         
162                 // Private fields which represents picture size
163                 private int                                     _width;
164                 private int                                     _height;
165                 
166                 // Indicates that smoothing is applied while drawing shadows
167                 internal bool                           softShadows = true;
168
169                 // Anti aliasing flags
170                 private AntiAliasingStyles              _antiAliasing = AntiAliasingStyles.All;
171
172                 // True if rendering into the metafile
173                 internal bool                           IsMetafile = false;
174
175                 #endregion
176
177                 #region Lines Methods
178
179                 /// <summary>
180                 /// Draws a line connecting the two specified points.
181                 /// </summary>
182                 /// <param name="color">Line color.</param>
183                 /// <param name="width">Line width.</param>
184                 /// <param name="style">Line style.</param>
185                 /// <param name="firstPointF">A Point that represents the first point to connect.</param>
186                 /// <param name="secondPointF">A Point that represents the second point to connect.</param>
187                 internal void DrawLineRel( 
188                         Color color, 
189                         int width, 
190                         ChartDashStyle style, 
191                         PointF firstPointF, 
192                         PointF secondPointF 
193                         )
194                 {
195                         DrawLineAbs(
196                                 color, 
197                                 width, 
198                                 style, 
199                                 GetAbsolutePoint(firstPointF), 
200                                 GetAbsolutePoint(secondPointF) );
201                 }
202
203                 /// <summary>
204                 /// Draws a line connecting the two specified points using absolute coordinates.
205                 /// </summary>
206                 /// <param name="color">Line color.</param>
207                 /// <param name="width">Line width.</param>
208                 /// <param name="style">Line style.</param>
209                 /// <param name="firstPoint">A Point that represents the first point to connect.</param>
210                 /// <param name="secondPoint">A Point that represents the second point to connect.</param>
211                 internal void DrawLineAbs( 
212                         Color color, 
213                         int width, 
214                         ChartDashStyle style, 
215                         PointF firstPoint, 
216                         PointF secondPoint 
217                         )
218                 {
219                         // Do not draw line if width is 0 or style not set
220                         if( width == 0 || style == ChartDashStyle.NotSet )
221                         {
222                                 return;
223                         }
224
225                         // Set a line color
226                         if(_pen.Color != color)
227                         {
228                                 _pen.Color = color;
229                         }
230
231                         // Set a line width
232                         if(_pen.Width != width)
233                         {
234                                 _pen.Width = width;
235                         }
236
237                         // Set a line style
238                         if(_pen.DashStyle != GetPenStyle( style ))
239                         {
240                                 _pen.DashStyle = GetPenStyle( style );
241                         }
242
243                         // Remember SmoothingMode and turn off anti aliasing for 
244                         // vertical or horizontal lines usinig 1 pixel dashed pen.
245                         // This prevents anialiasing from completly smoothing the 
246                         // dashed line.
247                         SmoothingMode oldSmoothingMode = this.SmoothingMode;
248                         if(width <= 1 && style != ChartDashStyle.Solid)
249                         {
250                                 if(firstPoint.X == secondPoint.X ||
251                                         firstPoint.Y == secondPoint.Y)
252                                 {
253                     this.SmoothingMode = SmoothingMode.Default;
254                                 }
255                         }
256
257                         // Draw a line
258             this.DrawLine(_pen, 
259                                 (float)Math.Round(firstPoint.X), 
260                                 (float)Math.Round(firstPoint.Y), 
261                                 (float)Math.Round(secondPoint.X), 
262                                 (float)Math.Round(secondPoint.Y) );
263
264                         // Return old smoothing mode
265             this.SmoothingMode = oldSmoothingMode;
266                 }
267
268                 /// <summary>
269                 /// Draws a line with shadow connecting the two specified points.
270                 /// </summary>
271                 /// <param name="color">Line color.</param>
272                 /// <param name="width">Line width.</param>
273                 /// <param name="style">Line style.</param>
274                 /// <param name="firstPoint">A Point that represents the first point to connect.</param>
275                 /// <param name="secondPoint">A Point that represents the second point to connect.</param>              
276                 /// <param name="shadowColor">Shadow Color.</param>
277                 /// <param name="shadowOffset">Shadow Offset.</param>
278                 internal void DrawLineRel(      
279                         Color color, 
280                         int width, 
281                         ChartDashStyle style, 
282                         PointF firstPoint, 
283                         PointF secondPoint, 
284                         Color shadowColor, 
285                         int shadowOffset  
286                         )
287                 {
288                         DrawLineAbs(    
289                                 color, 
290                                 width, 
291                                 style, 
292                                 GetAbsolutePoint(firstPoint), 
293                                 GetAbsolutePoint(secondPoint), 
294                                 shadowColor, 
295                                 shadowOffset );
296                 }
297
298                 /// <summary>
299                 /// Draws a line with shadow connecting the two specified points.
300                 /// </summary>
301                 /// <param name="color">Line color.</param>
302                 /// <param name="width">Line width.</param>
303                 /// <param name="style">Line style.</param>
304                 /// <param name="firstPoint">A Point that represents the first point to connect.</param>
305                 /// <param name="secondPoint">A Point that represents the second point to connect.</param>              
306                 /// <param name="shadowColor">Shadow Color.</param>
307                 /// <param name="shadowOffset">Shadow Offset.</param>
308                 internal void DrawLineAbs(      
309                         Color color, 
310                         int width, 
311                         ChartDashStyle style, 
312                         PointF firstPoint, 
313                         PointF secondPoint, 
314                         Color shadowColor, 
315                         int shadowOffset  
316                         )
317                 {
318                         if(shadowOffset != 0)
319                         {
320                                 // Shadow color
321                                 Color shColor;
322
323                                 // Make shadow semi transparent 
324                                 // if alpha value not used
325                                 if( shadowColor.A != 255 )
326                                         shColor = shadowColor;
327                                 else
328                                         shColor = Color.FromArgb(color.A/2, shadowColor);
329
330                                 // Set shadow line position
331                                 PointF firstShadow = new PointF( firstPoint.X + shadowOffset, firstPoint.Y + shadowOffset);
332                                 PointF secondShadow = new PointF( secondPoint.X + shadowOffset, secondPoint.Y + shadowOffset );
333
334                                 // Draw Shadow of Line
335                                 DrawLineAbs( shColor, width, style, firstShadow, secondShadow );
336                         }
337
338                         // Draw Line
339                         DrawLineAbs( color, width, style, firstPoint, secondPoint );
340                 }
341
342                 #endregion
343
344                 #region Pen and Brush Methods
345
346                 /// <summary>
347                 /// Creates a Hatch Brush.
348                 /// </summary>
349                 /// <param name="hatchStyle">Chart Hatch style.</param>
350                 /// <param name="backColor">Back Color.</param>
351                 /// <param name="foreColor">Fore Color.</param>
352                 /// <returns>Brush</returns>
353         internal Brush GetHatchBrush( 
354                         ChartHatchStyle hatchStyle, 
355                         Color backColor, 
356                         Color foreColor 
357                         )
358                 {
359                         // Convert Chart Hatch Style enum 
360                         // to Hatch Style enum.
361                         HatchStyle hatch;
362                         hatch = (HatchStyle)Enum.Parse(typeof(HatchStyle),hatchStyle.ToString());
363                         
364                         // Create Hatch Brush
365                         return new HatchBrush( hatch, foreColor, backColor );
366                 }
367
368                 /// <summary>
369                 /// Creates a textured brush.
370                 /// </summary>
371                 /// <param name="name">Image file name or URL.</param>
372                 /// <param name="backImageTransparentColor">Image transparent color.</param>
373                 /// <param name="mode">Wrap mode.</param>
374                 /// <param name="backColor">Image background color.</param>
375                 /// <returns>Textured brush.</returns>
376                 internal Brush GetTextureBrush(
377                         string name, 
378                         Color backImageTransparentColor, 
379                         ChartImageWrapMode mode,
380                         Color backColor
381                         )
382                 {
383                         // Load a image
384            System.Drawing.Image image = _common.ImageLoader.LoadImage( name );
385
386                         // Create a brush
387                         ImageAttributes attrib = new ImageAttributes();
388                         attrib.SetWrapMode((mode == ChartImageWrapMode.Unscaled) ? WrapMode.Clamp : ((WrapMode)mode));
389                         if(backImageTransparentColor != Color.Empty)
390                         {
391                                 attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
392                         }
393
394                         // If image is a metafile background must be filled first
395                         // Solves issue that background is not cleared correctly
396                         if(backImageTransparentColor == Color.Empty &&
397                                 image is Metafile &&
398                                 backColor != Color.Transparent)
399                         {
400                                 TextureBrush backFilledBrush = null;
401                                 Bitmap bitmap = new Bitmap(image.Width, image.Height);
402                                 using(Graphics graphics = Graphics.FromImage(bitmap))
403                                 {
404                                         using(SolidBrush backBrush = new SolidBrush(backColor))
405                                         {
406                                                 graphics.FillRectangle(backBrush, 0, 0, image.Width, image.Height);
407                                                 graphics.DrawImageUnscaled(image, 0, 0);
408                                                 backFilledBrush= new TextureBrush( bitmap, new RectangleF(0,0,image.Width,image.Height), attrib); 
409                                         }
410                                 }
411
412                                 return backFilledBrush;
413                         }
414                        
415             
416             TextureBrush textureBrush;
417
418             if (ImageLoader.DoDpisMatch(image, this.Graphics))
419                 textureBrush = new TextureBrush(image, new RectangleF(0, 0, image.Width, image.Height), attrib);
420             else  // if the image dpi does not match the graphics dpi we have to scale the image    
421             {
422                 Image scaledImage = ImageLoader.GetScaledImage(image, this.Graphics);
423                 textureBrush = new TextureBrush(scaledImage, new RectangleF(0, 0, scaledImage.Width, scaledImage.Height), attrib);
424                 scaledImage.Dispose();
425             }
426             
427             return textureBrush;
428
429                 }
430                 
431                 /// <summary>
432                 /// This method creates a gradient brush.
433                 /// </summary>
434                 /// <param name="rectangle">A rectangle which has to be filled with a gradient color.</param>
435                 /// <param name="firstColor">First color.</param>
436                 /// <param name="secondColor">Second color.</param>
437                 /// <param name="type ">Gradient type .</param>
438                 /// <returns>Gradient Brush</returns>
439         internal Brush GetGradientBrush( 
440                         RectangleF rectangle, 
441                         Color firstColor, 
442                         Color secondColor, 
443                         GradientStyle type
444                         )
445                 {
446                         // Increse the brush rectangle by 1 pixel to ensure the fit
447                         rectangle.Inflate(1f, 1f);
448
449                         Brush gradientBrush = null;
450                         float angle = 0;
451
452                         // Function which create gradient brush fires exception if 
453                         // rectangle size is zero.
454                         if( rectangle.Height == 0 || rectangle.Width == 0 )
455                         {
456                                 gradientBrush = new SolidBrush( Color.Black );
457                                 return gradientBrush;
458                         }
459
460                         // *******************************************
461                         // Linear Gradient
462                         // *******************************************
463                         // Check linear type .
464                         if( type == GradientStyle.LeftRight || type == GradientStyle.VerticalCenter )
465                         {
466                                 angle = 0;
467                         }
468                         else if( type == GradientStyle.TopBottom || type == GradientStyle.HorizontalCenter )
469                         {
470                                 angle = 90;
471                         }
472                         else if(  type == GradientStyle.DiagonalLeft )
473                         {
474                                 angle = (float)(Math.Atan(rectangle.Width / rectangle.Height)* 180 / Math.PI); 
475                         }
476                         else if(  type == GradientStyle.DiagonalRight )
477                         {
478                                 angle = (float)(180 - Math.Atan(rectangle.Width / rectangle.Height)* 180 / Math.PI); 
479                         }
480                         
481                         // Create a linear gradient brush
482                         if( type == GradientStyle.TopBottom || type == GradientStyle.LeftRight 
483                                 || type == GradientStyle.DiagonalLeft || type == GradientStyle.DiagonalRight
484                                 || type == GradientStyle.HorizontalCenter || type == GradientStyle.VerticalCenter )
485                         {
486                                 RectangleF tempRect = new RectangleF(rectangle.X,rectangle.Y,rectangle.Width,rectangle.Height);
487                                 // For Horizontal and vertical center gradient types
488                                 if( type == GradientStyle.HorizontalCenter )
489                                 {
490                                         // Resize and wrap gradient
491                                         tempRect.Height = tempRect.Height / 2F;
492                     LinearGradientBrush linearGradientBrush = new LinearGradientBrush(tempRect, firstColor, secondColor, angle);
493                     gradientBrush = linearGradientBrush;
494                                         linearGradientBrush.WrapMode = WrapMode.TileFlipX;
495                                 }
496                                 else if( type == GradientStyle.VerticalCenter )
497                                 {
498                                         // Resize and wrap gradient
499                                         tempRect.Width = tempRect.Width / 2F;
500                     LinearGradientBrush linearGradientBrush = new LinearGradientBrush(tempRect, firstColor, secondColor, angle);
501                     gradientBrush = linearGradientBrush;
502                     linearGradientBrush.WrapMode = WrapMode.TileFlipX;
503                                 }
504                                 else
505                                 {
506                                         gradientBrush = new LinearGradientBrush( rectangle, firstColor, secondColor, angle );
507                                 }
508                                 return gradientBrush;
509                         }
510
511                         // *******************************************
512                         // Gradient is not linear : From Center.
513                         // *******************************************
514                         
515                         // Create a path
516                         GraphicsPath path = new GraphicsPath();
517
518                         // Add a rectangle to the path
519                         path.AddRectangle( rectangle );
520
521                         // Create a gradient brush
522             PathGradientBrush pathGradientBrush = new PathGradientBrush(path);
523             gradientBrush = pathGradientBrush;
524
525                         // Set the center color
526             pathGradientBrush.CenterColor = firstColor;
527
528                         // Set the Surround color
529                         Color[] colors = {secondColor};
530             pathGradientBrush.SurroundColors = colors;
531                         
532                         if( path != null )
533                         {
534                                 path.Dispose();
535                         }
536
537                         return gradientBrush;
538                 }
539
540                 /// <summary>
541                 /// This method creates a gradient brush for pie. This gradient is one 
542                 /// of the types used only with pie and doughnut.
543                 /// </summary>
544                 /// <param name="rectangle">A rectangle which has to be filled with a gradient color</param>
545                 /// <param name="firstColor">First color</param>
546                 /// <param name="secondColor">Second color</param>
547                 /// <returns>Gradient Brush</returns>
548                 internal Brush GetPieGradientBrush( 
549                         RectangleF rectangle, 
550                         Color firstColor, 
551                         Color secondColor 
552                         )
553                 {
554                         // Create a path that consists of a single ellipse.
555                         GraphicsPath path = new GraphicsPath();
556                         path.AddEllipse( rectangle );
557
558                         // Use the path to construct a brush.
559                         PathGradientBrush gradientBrush = new PathGradientBrush(path);
560
561                         // Set the color at the center of the path.
562                         gradientBrush.CenterColor = firstColor;
563
564                         // Set the color along the entire boundary 
565                         // of the path to aqua.
566                         Color[] colors = {secondColor};
567
568                         gradientBrush.SurroundColors = colors;
569
570                         if( path != null )
571                         {
572                                 path.Dispose();
573                         }
574
575                         return gradientBrush;
576
577                 }
578
579                 /// <summary>
580                 /// Converts GDI+ line style to Chart Graph line style.
581                 /// </summary>
582                 /// <param name="style">Chart Line style.</param>
583                 /// <returns>GDI+ line style.</returns>
584                 internal DashStyle GetPenStyle( ChartDashStyle style )
585                 {
586                         // Convert to chart line styles. The custom style doesn\92t exist.
587                         switch( style )
588                         {
589                                 case ChartDashStyle.Dash:
590                                         return DashStyle.Dash;
591                                 case ChartDashStyle.DashDot:
592                                         return DashStyle.DashDot;
593                                 case ChartDashStyle.DashDotDot:
594                                         return DashStyle.DashDotDot;
595                                 case ChartDashStyle.Dot:
596                                         return DashStyle.Dot;
597                         }
598
599                         return DashStyle.Solid;
600                 }
601
602                 #endregion
603
604                 #region Markers
605
606                 /// <summary>
607                 /// Creates polygon for multi-corner star marker.
608                 /// </summary>
609                 /// <param name="rect">Marker rectangle.</param>
610                 /// <param name="numberOfCorners">Number of corners (4 and up).</param>
611                 /// <returns>Array of points.</returns>
612                 internal PointF[] CreateStarPolygon(RectangleF rect, int numberOfCorners)
613                 {
614             int numberOfCornersX2;
615             checked
616             {
617                 numberOfCornersX2 = numberOfCorners * 2;
618             }
619
620             bool outside = true;
621             PointF[] points = new PointF[numberOfCornersX2];
622             PointF[] tempPoints = new PointF[1];
623             // overflow check
624             for (int pointIndex = 0; pointIndex < numberOfCornersX2; pointIndex++)
625                         {
626                                 tempPoints[0] = new PointF(rect.X + rect.Width/2f, (outside == true) ? rect.Y : rect.Y + rect.Height/4f);
627                                 Matrix  matrix = new Matrix();
628                                 matrix.RotateAt(pointIndex*(360f/(numberOfCorners*2f)), new PointF(rect.X + rect.Width/2f, rect.Y + rect.Height/2f));
629                                 matrix.TransformPoints(tempPoints);
630                                 points[pointIndex] = tempPoints[0];
631                                 outside = !outside;
632                         }
633
634                         return points;
635                 }
636
637                 /// <summary>
638                 /// Draw marker using relative coordinates of the center.
639                 /// </summary>
640                 /// <param name="point">Coordinates of the center.</param>
641                 /// <param name="markerStyle">Marker style.</param>
642                 /// <param name="markerSize">Marker size.</param>
643                 /// <param name="markerColor">Marker color.</param>
644                 /// <param name="markerBorderColor">Marker border color.</param>
645                 /// <param name="markerBorderSize">Marker border size.</param>
646                 /// <param name="markerImage">Marker image name.</param>
647                 /// <param name="markerImageTransparentColor">Marker image transparent color.</param>
648                 /// <param name="shadowSize">Marker shadow size.</param>
649                 /// <param name="shadowColor">Marker shadow color.</param>
650                 /// <param name="imageScaleRect">Rectangle to which marker image should be scaled.</param>
651                 internal void DrawMarkerRel(
652                         PointF point, 
653                         MarkerStyle markerStyle, 
654                         int markerSize, 
655                         Color markerColor, 
656                         Color markerBorderColor, 
657                         int markerBorderSize, 
658                         string markerImage, 
659                         Color markerImageTransparentColor, 
660                         int shadowSize, 
661                         Color shadowColor, 
662                         RectangleF imageScaleRect
663                         )
664                 {
665                         DrawMarkerAbs(this.GetAbsolutePoint(point), markerStyle, markerSize, markerColor, markerBorderColor, markerBorderSize, markerImage, markerImageTransparentColor, shadowSize, shadowColor, imageScaleRect, false);
666                 }
667
668                 /// <summary>
669                 /// Draw marker using absolute coordinates of the center.
670                 /// </summary>
671                 /// <param name="point">Coordinates of the center.</param>
672                 /// <param name="markerStyle">Marker style.</param>
673                 /// <param name="markerSize">Marker size.</param>
674                 /// <param name="markerColor">Marker color.</param>
675                 /// <param name="markerBorderColor">Marker border color.</param>
676                 /// <param name="markerBorderSize">Marker border size.</param>
677                 /// <param name="markerImage">Marker image name.</param>
678                 /// <param name="markerImageTransparentColor">Marker image transparent color.</param>
679                 /// <param name="shadowSize">Marker shadow size.</param>
680                 /// <param name="shadowColor">Marker shadow color.</param>
681                 /// <param name="imageScaleRect">Rectangle to which marker image should be scaled.</param>
682                 /// <param name="forceAntiAlias">Always use anti aliasing when drawing the marker.</param>
683                 internal void DrawMarkerAbs(
684                         PointF point, 
685                         MarkerStyle markerStyle, 
686                         int markerSize, 
687                         Color markerColor, 
688                         Color markerBorderColor, 
689                         int markerBorderSize, 
690                         string markerImage, 
691                         Color markerImageTransparentColor, 
692                         int shadowSize, 
693                         Color shadowColor, 
694                         RectangleF imageScaleRect, 
695                         bool forceAntiAlias
696                         )
697                 {
698                         // Hide border when zero width specified
699                         if(markerBorderSize <= 0)
700                         {
701                                 markerBorderColor = Color.Transparent;
702                         }
703
704                         // Draw image instead of standart markers
705                         if(markerImage.Length > 0)
706                         {
707                                 // Get image
708                 System.Drawing.Image image = _common.ImageLoader.LoadImage( markerImage );
709
710                 if (image != null)
711                 {
712                     // Calculate image rectangle
713                     RectangleF rect = RectangleF.Empty;
714                     if (imageScaleRect == RectangleF.Empty)
715                     {
716                         SizeF size = new SizeF();
717                         ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref size);
718                         imageScaleRect.Width = size.Width;
719                         imageScaleRect.Height = size.Height;
720                     }
721
722                     rect.X = point.X - imageScaleRect.Width / 2F;
723                     rect.Y = point.Y - imageScaleRect.Height / 2F;
724                     rect.Width = imageScaleRect.Width;
725                     rect.Height = imageScaleRect.Height;
726
727                     // Prepare image properties (transparent color)
728                     ImageAttributes attrib = new ImageAttributes();
729                     if (markerImageTransparentColor != Color.Empty)
730                     {
731                         attrib.SetColorKey(markerImageTransparentColor, markerImageTransparentColor, ColorAdjustType.Default);
732                     }
733
734                     // Draw image shadow
735                     if (shadowSize != 0 && shadowColor != Color.Empty)
736                     {
737                         ImageAttributes attribShadow = new ImageAttributes();
738                         attribShadow.SetColorKey(markerImageTransparentColor, markerImageTransparentColor, ColorAdjustType.Default);
739                         ColorMatrix colorMatrix = new ColorMatrix();
740                         colorMatrix.Matrix00 = 0.25f; // Red
741                         colorMatrix.Matrix11 = 0.25f; // Green
742                         colorMatrix.Matrix22 = 0.25f; // Blue
743                         colorMatrix.Matrix33 = 0.5f; // alpha
744                         colorMatrix.Matrix44 = 1.0f; // w
745                         attribShadow.SetColorMatrix(colorMatrix);
746
747                         this.DrawImage(image,
748                             new Rectangle((int)rect.X + shadowSize, (int)rect.Y + shadowSize, (int)rect.Width, (int)rect.Height),
749                             0, 0, image.Width, image.Height,
750                             GraphicsUnit.Pixel,
751                             attribShadow);
752                     }
753
754                     // Draw image
755                     this.DrawImage(image,
756                         new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height),
757                         0, 0, image.Width, image.Height,
758                         GraphicsUnit.Pixel,
759                         attrib);
760                 }
761                         }
762
763                         // Draw standart marker using style, size and color
764                         else if(markerStyle != MarkerStyle.None && markerSize > 0 && markerColor != Color.Empty)
765                         {
766                                 // Enable antialising
767                 SmoothingMode oldSmoothingMode = this.SmoothingMode;
768                                 if(forceAntiAlias)
769                                 {
770                     this.SmoothingMode = SmoothingMode.AntiAlias;
771                                 }
772                                 
773                                 // Create solid color brush
774                 using (SolidBrush brush = new SolidBrush(markerColor))
775                 {
776                     // Calculate marker rectangle
777                     RectangleF rect = RectangleF.Empty;
778                     rect.X = point.X - ((float)markerSize) / 2F;
779                     rect.Y = point.Y - ((float)markerSize) / 2F;
780                     rect.Width = markerSize;
781                     rect.Height = markerSize;
782
783                     // Draw marker depending on style
784                     switch (markerStyle)
785                     {
786                         case (MarkerStyle.Star4):
787                         case (MarkerStyle.Star5):
788                         case (MarkerStyle.Star6):
789                         case (MarkerStyle.Star10):
790                             {
791                                 // Set number of corners
792                                 int cornerNumber = 4;
793                                 if (markerStyle == MarkerStyle.Star5)
794                                 {
795                                     cornerNumber = 5;
796                                 }
797                                 else if (markerStyle == MarkerStyle.Star6)
798                                 {
799                                     cornerNumber = 6;
800                                 }
801                                 else if (markerStyle == MarkerStyle.Star10)
802                                 {
803                                     cornerNumber = 10;
804                                 }
805
806                                 // Get star polygon
807                                 PointF[] points = CreateStarPolygon(rect, cornerNumber);
808
809                                 // Draw shadow
810                                 if (shadowSize != 0 && shadowColor != Color.Empty)
811                                 {
812                                     Matrix translateMatrix = this.Transform.Clone();
813                                     translateMatrix.Translate(shadowSize, shadowSize);
814                                     Matrix oldMatrix = this.Transform;
815                                     this.Transform = translateMatrix;
816
817                                     this.FillPolygon(new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)), points);
818
819                                     this.Transform = oldMatrix;
820                                 }
821
822                                 // Draw star
823                                 this.FillPolygon(brush, points);
824                                 this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
825                                 break;
826                             }
827                         case (MarkerStyle.Circle):
828                             {
829                                 // Draw marker shadow
830                                 if (shadowSize != 0 && shadowColor != Color.Empty)
831                                 {
832                                     if (!softShadows)
833                                     {
834                                         using (SolidBrush shadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
835                                         {
836                                             RectangleF shadowRect = rect;
837                                             shadowRect.X += shadowSize;
838                                             shadowRect.Y += shadowSize;
839                                             this.FillEllipse(shadowBrush, shadowRect);
840                                         }
841                                     }
842                                     else
843                                     {
844                                         // Add circle to the graphics path
845                                         using (GraphicsPath path = new GraphicsPath())
846                                         {
847                                             path.AddEllipse(rect.X + shadowSize - 1, rect.Y + shadowSize - 1, rect.Width + 2, rect.Height + 2);
848
849                                             // Create path brush
850                                             using (PathGradientBrush shadowBrush = new PathGradientBrush(path))
851                                             {
852                                                 shadowBrush.CenterColor = shadowColor;
853
854                                                 // Set the color along the entire boundary of the path
855                                                 Color[] colors = { Color.Transparent };
856                                                 shadowBrush.SurroundColors = colors;
857                                                 shadowBrush.CenterPoint = new PointF(point.X, point.Y);
858
859                                                 // Define brush focus scale
860                                                 PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
861                                                 if (focusScale.X < 0)
862                                                 {
863                                                     focusScale.X = 0;
864                                                 }
865                                                 if (focusScale.Y < 0)
866                                                 {
867                                                     focusScale.Y = 0;
868                                                 }
869                                                 shadowBrush.FocusScales = focusScale;
870
871                                                 // Draw shadow
872                                                 this.FillPath(shadowBrush, path);
873                                             }
874                                         }
875                                     }
876                                 }
877
878                                 this.FillEllipse(brush, rect);
879                                 this.DrawEllipse(new Pen(markerBorderColor, markerBorderSize), rect);
880                                 break;
881                             }
882                         case (MarkerStyle.Square):
883                             {
884                                 // Draw marker shadow
885                                 if (shadowSize != 0 && shadowColor != Color.Empty)
886                                 {
887                                     FillRectangleShadowAbs(rect, shadowColor, shadowSize, shadowColor);
888                                 }
889
890                                 this.FillRectangle(brush, rect);
891                                 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));
892                                 break;
893                             }
894                         case (MarkerStyle.Cross):
895                             {
896                                 // Calculate cross line width and size
897                                 float crossLineWidth = (float)Math.Ceiling(markerSize / 4F);
898                                 float crossSize = markerSize;// * (float)Math.Sin(45f/180f*Math.PI);
899
900                                 // Calculate cross coordinates
901                                 PointF[] points = new PointF[12];
902                                 points[0].X = point.X - crossSize / 2F;
903                                 points[0].Y = point.Y + crossLineWidth / 2F;
904                                 points[1].X = point.X - crossSize / 2F;
905                                 points[1].Y = point.Y - crossLineWidth / 2F;
906
907                                 points[2].X = point.X - crossLineWidth / 2F;
908                                 points[2].Y = point.Y - crossLineWidth / 2F;
909                                 points[3].X = point.X - crossLineWidth / 2F;
910                                 points[3].Y = point.Y - crossSize / 2F;
911                                 points[4].X = point.X + crossLineWidth / 2F;
912                                 points[4].Y = point.Y - crossSize / 2F;
913
914                                 points[5].X = point.X + crossLineWidth / 2F;
915                                 points[5].Y = point.Y - crossLineWidth / 2F;
916                                 points[6].X = point.X + crossSize / 2F;
917                                 points[6].Y = point.Y - crossLineWidth / 2F;
918                                 points[7].X = point.X + crossSize / 2F;
919                                 points[7].Y = point.Y + crossLineWidth / 2F;
920
921                                 points[8].X = point.X + crossLineWidth / 2F;
922                                 points[8].Y = point.Y + crossLineWidth / 2F;
923                                 points[9].X = point.X + crossLineWidth / 2F;
924                                 points[9].Y = point.Y + crossSize / 2F;
925                                 points[10].X = point.X - crossLineWidth / 2F;
926                                 points[10].Y = point.Y + crossSize / 2F;
927                                 points[11].X = point.X - crossLineWidth / 2F;
928                                 points[11].Y = point.Y + crossLineWidth / 2F;
929
930                                 // Rotate cross coordinates 45 degrees
931                                 Matrix rotationMatrix = new Matrix();
932                                 rotationMatrix.RotateAt(45, point);
933                                 rotationMatrix.TransformPoints(points);
934
935                                 // Draw shadow
936                                 if (shadowSize != 0 && shadowColor != Color.Empty)
937                                 {
938                                     // Create translation matrix
939                                     Matrix translateMatrix = this.Transform.Clone();
940                                     translateMatrix.Translate(
941                                         (softShadows) ? shadowSize + 1 : shadowSize,
942                                         (softShadows) ? shadowSize + 1 : shadowSize);
943                                     Matrix oldMatrix = this.Transform;
944                                     this.Transform = translateMatrix;
945
946                                     if (!softShadows)
947                                     {
948                                         using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
949                                         {
950                                             this.FillPolygon(softShadowBrush, points);
951                                         }
952                                     }
953                                     else
954                                     {
955                                         // Add polygon to the graphics path
956                                         using (GraphicsPath path = new GraphicsPath())
957                                         {
958                                             path.AddPolygon(points);
959
960                                             // Create path brush
961                                             using (PathGradientBrush shadowBrush = new PathGradientBrush(path))
962                                             {
963                                                 shadowBrush.CenterColor = shadowColor;
964
965                                                 // Set the color along the entire boundary of the path
966                                                 Color[] colors = { Color.Transparent };
967                                                 shadowBrush.SurroundColors = colors;
968                                                 shadowBrush.CenterPoint = new PointF(point.X, point.Y);
969
970                                                 // Define brush focus scale
971                                                 PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
972                                                 if (focusScale.X < 0)
973                                                 {
974                                                     focusScale.X = 0;
975                                                 }
976                                                 if (focusScale.Y < 0)
977                                                 {
978                                                     focusScale.Y = 0;
979                                                 }
980                                                 shadowBrush.FocusScales = focusScale;
981
982                                                 // Draw shadow
983                                                 this.FillPath(shadowBrush, path);
984                                             }
985                                         }
986                                     }
987
988                                     this.Transform = oldMatrix;
989                                 }
990
991                                 // Create translation matrix
992                                 Matrix translateMatrixShape = this.Transform.Clone();
993                                 Matrix oldMatrixShape = this.Transform;
994                                 this.Transform = translateMatrixShape;
995
996                                 this.FillPolygon(brush, points);
997                                 this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
998
999                                 this.Transform = oldMatrixShape;
1000
1001                                 break;
1002                             }
1003                         case (MarkerStyle.Diamond):
1004                             {
1005                                 PointF[] points = new PointF[4];
1006                                 points[0].X = rect.X;
1007                                 points[0].Y = rect.Y + rect.Height / 2F;
1008                                 points[1].X = rect.X + rect.Width / 2F;
1009                                 points[1].Y = rect.Top;
1010                                 points[2].X = rect.Right;
1011                                 points[2].Y = rect.Y + rect.Height / 2F;
1012                                 points[3].X = rect.X + rect.Width / 2F;
1013                                 points[3].Y = rect.Bottom;
1014
1015                                 // Draw shadow
1016                                 if (shadowSize != 0 && shadowColor != Color.Empty)
1017                                 {
1018                                     Matrix translateMatrix = this.Transform.Clone();
1019                                     translateMatrix.Translate((softShadows) ? 0 : shadowSize,
1020                                         (softShadows) ? 0 : shadowSize);
1021                                     Matrix oldMatrix = this.Transform;
1022                                     this.Transform = translateMatrix;
1023
1024                                     if (!softShadows)
1025                                     {
1026                                         using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
1027                                         {
1028                                             this.FillPolygon(softShadowBrush, points);
1029                                         }
1030                                     }
1031                                     else
1032                                     {
1033                                         // Calculate diamond size
1034                                         float diamondSize = markerSize * (float)Math.Sin(45f / 180f * Math.PI);
1035
1036                                         // Calculate diamond rectangle position
1037                                         RectangleF diamondRect = RectangleF.Empty;
1038                                         diamondRect.X = point.X - ((float)diamondSize) / 2F;
1039                                         diamondRect.Y = point.Y - ((float)diamondSize) / 2F - shadowSize;
1040                                         diamondRect.Width = diamondSize;
1041                                         diamondRect.Height = diamondSize;
1042
1043                                         // Set rotation matrix to 45 
1044                                         translateMatrix.RotateAt(45, point);
1045                                         this.Transform = translateMatrix;
1046
1047                                         FillRectangleShadowAbs(diamondRect, shadowColor, shadowSize, shadowColor);
1048                                     }
1049
1050
1051                                     this.Transform = oldMatrix;
1052                                 }
1053
1054                                 this.FillPolygon(brush, points);
1055                                 this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
1056                                 break;
1057                             }
1058                         case (MarkerStyle.Triangle):
1059                             {
1060                                 PointF[] points = new PointF[3];
1061                                 points[0].X = rect.X;
1062                                 points[0].Y = rect.Bottom;
1063                                 points[1].X = rect.X + rect.Width / 2F;
1064                                 points[1].Y = rect.Top;
1065                                 points[2].X = rect.Right;
1066                                 points[2].Y = rect.Bottom;
1067
1068                                 // Draw image shadow
1069                                 if (shadowSize != 0 && shadowColor != Color.Empty)
1070                                 {
1071                                     Matrix translateMatrix = this.Transform.Clone();
1072                                     translateMatrix.Translate((softShadows) ? shadowSize - 1 : shadowSize,
1073                                         (softShadows) ? shadowSize + 1 : shadowSize);
1074                                     Matrix oldMatrix = this.Transform;
1075                                     this.Transform = translateMatrix;
1076
1077                                     if (!softShadows)
1078                                     {
1079                                         using (Brush softShadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(markerColor.A / 2, shadowColor)))
1080                                         {
1081                                             this.FillPolygon(softShadowBrush, points);
1082                                         }
1083                                     }
1084                                     else
1085                                     {
1086                                         // Add polygon to the graphics path
1087                                         GraphicsPath path = new GraphicsPath();
1088                                         path.AddPolygon(points);
1089
1090                                         // Create path brush
1091                                         PathGradientBrush shadowBrush = new PathGradientBrush(path);
1092                                         shadowBrush.CenterColor = shadowColor;
1093
1094                                         // Set the color along the entire boundary of the path
1095                                         Color[] colors = { Color.Transparent };
1096                                         shadowBrush.SurroundColors = colors;
1097                                         shadowBrush.CenterPoint = new PointF(point.X, point.Y);
1098
1099                                         // Define brush focus scale
1100                                         PointF focusScale = new PointF(1 - 2f * shadowSize / rect.Width, 1 - 2f * shadowSize / rect.Height);
1101                                         if (focusScale.X < 0)
1102                                         {
1103                                             focusScale.X = 0;
1104                                         }
1105                                         if (focusScale.Y < 0)
1106                                         {
1107                                             focusScale.Y = 0;
1108                                         }
1109                                         shadowBrush.FocusScales = focusScale;
1110
1111                                         // Draw shadow
1112                                         this.FillPath(shadowBrush, path);
1113                                     }
1114
1115                                     this.Transform = oldMatrix;
1116                                 }
1117
1118                                 this.FillPolygon(brush, points);
1119                                 this.DrawPolygon(new Pen(markerBorderColor, markerBorderSize), points);
1120                                 break;
1121                             }
1122                         default:
1123                             {
1124                                 throw (new InvalidOperationException(SR.ExceptionGraphicsMarkerStyleUnknown));
1125                             }
1126                     }
1127                 }
1128
1129                                 // Restore SmoothingMode
1130                                 if(forceAntiAlias)
1131                                 {
1132                                         this.SmoothingMode = oldSmoothingMode;
1133                                 }
1134                         }
1135                 }
1136
1137                 #endregion
1138         
1139                 #region String Methods
1140
1141         /// <summary>
1142         /// Measures the specified string when drawn with the specified 
1143         /// Font object and formatted with the specified StringFormat object.
1144         /// </summary>
1145         /// <param name="text">String to measure.</param>
1146         /// <param name="font">Font object defines the text format of the string.</param>
1147         /// <param name="layoutArea">SizeF structure that specifies the maximum layout area for the text.</param>
1148         /// <param name="stringFormat">StringFormat object that represents formatting information, such as line spacing, for the string.</param>
1149         /// <param name="textOrientation">Text orientation.</param>
1150         /// <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>
1151         internal SizeF MeasureString(
1152             string text,
1153             Font font,
1154             SizeF layoutArea,
1155             StringFormat stringFormat,
1156             TextOrientation textOrientation
1157             )
1158         {
1159             // Current implementation of the stacked text will simply insert a new
1160             // line character between all characters in the original string. This
1161             // apporach will not allow to show multiple lines of stacked text or 
1162             // correctly handle text wrapping. 
1163             if (textOrientation == TextOrientation.Stacked)
1164             {
1165                 text = GetStackedText(text);
1166             }
1167             return this.MeasureString(text, font, layoutArea, stringFormat);
1168         }
1169
1170         /// <summary>
1171         /// Measures the specified text string when drawn with 
1172         /// the specified Font object and formatted with the 
1173         /// specified StringFormat object.
1174         /// </summary>
1175         /// <param name="text">The string to measure</param>
1176         /// <param name="font">The Font object used to determine the size of the text string. </param>
1177         /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
1178         /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
1179         /// <param name="textOrientation">Text orientation.</param>
1180         /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
1181         internal SizeF MeasureStringRel(
1182             string text, 
1183             Font font, 
1184             SizeF layoutArea, 
1185             StringFormat stringFormat,
1186             TextOrientation textOrientation)
1187         {
1188             // Current implementation of the stacked text will simply insert a new
1189             // line character between all characters in the original string. This
1190             // apporach will not allow to show multiple lines of stacked text or 
1191             // correctly handle text wrapping. 
1192             if (textOrientation == TextOrientation.Stacked)
1193             {
1194                 text = GetStackedText(text);
1195             }
1196             return this.MeasureStringRel(text, font, layoutArea, stringFormat);
1197         }
1198
1199                 /// <summary>
1200                 /// 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.
1201                 /// </summary>
1202                 /// <param name="text">String to draw.</param>
1203                 /// <param name="font">Font object that defines the text format of the string.</param>
1204                 /// <param name="brush">Brush object that determines the color and texture of the drawn text.</param>
1205         /// <param name="rect">Position of the drawn text in pixels.</param>
1206                 /// <param name="format">StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
1207         /// <param name="textOrientation">Text orientation.</param>
1208         internal void DrawString(
1209             string text,
1210             Font font,
1211             Brush brush,
1212             RectangleF rect,
1213             StringFormat format,
1214             TextOrientation textOrientation
1215             )
1216         {
1217             // Current implementation of the stacked text will simply insert a new
1218             // line character between all characters in the original string. This
1219             // apporach will not allow to show multiple lines of stacked text or 
1220             // correctly handle text wrapping. 
1221             if (textOrientation == TextOrientation.Stacked)
1222             {
1223                 text = GetStackedText(text);
1224             }
1225             this.DrawString(text, font, brush, rect, format);
1226         }
1227
1228         /// <summary>
1229         /// Draw a string.
1230         /// </summary>
1231         /// <param name="text">Text.</param>
1232         /// <param name="font">Text Font.</param>
1233         /// <param name="brush">Text Brush.</param>
1234         /// <param name="position">Text Position.</param>
1235         /// <param name="format">Format and text alignment.</param>
1236         /// <param name="angle">Text angle.</param>
1237         /// <param name="textOrientation">Text orientation.</param>
1238         internal void DrawStringRel(
1239             string text,
1240             System.Drawing.Font font,
1241             System.Drawing.Brush brush,
1242             PointF position,
1243             System.Drawing.StringFormat format,
1244             int angle,
1245             TextOrientation textOrientation
1246             )
1247         {
1248             // Current implementation of the stacked text will simply insert a new
1249             // line character between all characters in the original string. This
1250             // apporach will not allow to show multiple lines of stacked text or 
1251             // correctly handle text wrapping. 
1252             if (textOrientation == TextOrientation.Stacked)
1253             {
1254                 text = GetStackedText(text);
1255             }
1256
1257             this.DrawStringRel(text, font, brush, position, format, angle);
1258         }
1259
1260         /// <summary>
1261         /// Draw a string.
1262         /// </summary>
1263         /// <param name="text">Text.</param>
1264         /// <param name="font">Text Font.</param>
1265         /// <param name="brush">Text Brush.</param>
1266         /// <param name="position">Text Position.</param>
1267         /// <param name="format">Format and text alignment.</param>
1268         /// <param name="textOrientation">Text orientation.</param>
1269         internal void DrawStringRel(
1270             string text,
1271             System.Drawing.Font font,
1272             System.Drawing.Brush brush,
1273             RectangleF position,
1274             System.Drawing.StringFormat format,
1275             TextOrientation textOrientation
1276             )
1277         {
1278             // Current implementation of the stacked text will simply insert a new
1279             // line character between all characters in the original string. This
1280             // apporach will not allow to show multiple lines of stacked text or 
1281             // correctly handle text wrapping. 
1282             if (textOrientation == TextOrientation.Stacked)
1283             {
1284                 text = GetStackedText(text);
1285             }
1286
1287             this.DrawStringRel(text, font, brush, position, format);
1288         }
1289
1290         /// <summary>
1291         /// Function returned stacked text by inserting new line characters between
1292         /// all characters in the original string.
1293         /// </summary>
1294         /// <param name="text">Original text.</param>
1295         /// <returns>Stacked text.</returns>
1296         internal static string GetStackedText(string text)
1297         {
1298             string result = string.Empty;
1299             foreach (char ch in text)
1300             {
1301                 result += ch;
1302                 if (ch != '\n')
1303                 {
1304                     result += '\n';
1305                 }
1306             }
1307             return result;
1308         }
1309
1310                 /// <summary>
1311                 /// Draw a string and fills it's background
1312                 /// </summary>
1313                 /// <param name="common">The Common elements object.</param>
1314                 /// <param name="text">Text.</param>
1315                 /// <param name="font">Text Font.</param>
1316                 /// <param name="brush">Text Brush.</param>
1317                 /// <param name="position">Text Position.</param>
1318                 /// <param name="format">Format and text alignment.</param>
1319                 /// <param name="angle">Text angle.</param>
1320                 /// <param name="backPosition">Text background position.</param>
1321                 /// <param name="backColor">Back Color</param>
1322                 /// <param name="borderColor">Border Color</param>
1323                 /// <param name="borderWidth">Border Width</param>
1324                 /// <param name="borderDashStyle">Border Style</param>
1325                 /// <param name="series">Series</param>
1326                 /// <param name="point">Point</param>
1327                 /// <param name="pointIndex">Point index in series</param>
1328                 internal void DrawPointLabelStringRel( 
1329                         CommonElements common,
1330                         string text, 
1331                         System.Drawing.Font font, 
1332                         System.Drawing.Brush brush, 
1333                         RectangleF position, 
1334                         System.Drawing.StringFormat format, 
1335                         int angle,
1336                         RectangleF backPosition,
1337                         Color backColor, 
1338                         Color borderColor, 
1339                         int borderWidth, 
1340                         ChartDashStyle borderDashStyle,
1341                         Series series,
1342                         DataPoint point,
1343                         int pointIndex)
1344                 {
1345                         // Start Svg/Flash Selection mode
1346                         this.StartHotRegion( point, true );
1347
1348                         // Draw background
1349                         DrawPointLabelBackground( 
1350                                 common,
1351                                 angle,
1352                                 PointF.Empty,
1353                                 backPosition,
1354                                 backColor, 
1355                                 borderColor, 
1356                                 borderWidth, 
1357                                 borderDashStyle,
1358                                 series,
1359                                 point,
1360                                 pointIndex);
1361
1362                         // End Svg/Flash Selection mode
1363                         this.EndHotRegion( );
1364             
1365             point._lastLabelText = text;
1366             // Draw text
1367             if (IsRightToLeft)
1368             {
1369                 // datapoint label alignments should appear as not RTL.
1370                 using (StringFormat fmt = (StringFormat)format.Clone())
1371                 {
1372                     if (fmt.Alignment == StringAlignment.Far)
1373                     {
1374                         fmt.Alignment = StringAlignment.Near;
1375                     }
1376                     else if (fmt.Alignment == StringAlignment.Near)
1377                     {
1378                         fmt.Alignment = StringAlignment.Far;
1379                     }
1380                     DrawStringRel(text,font,brush,position,fmt,angle);
1381                 }
1382             }
1383             else
1384                 DrawStringRel(text, font, brush, position, format, angle);
1385                 }
1386
1387                 /// <summary>
1388                 /// Draw a string and fills it's background
1389                 /// </summary>
1390                 /// <param name="common">The Common elements object.</param>
1391                 /// <param name="text">Text.</param>
1392                 /// <param name="font">Text Font.</param>
1393                 /// <param name="brush">Text Brush.</param>
1394                 /// <param name="position">Text Position.</param>
1395                 /// <param name="format">Format and text alignment.</param>
1396                 /// <param name="angle">Text angle.</param>
1397                 /// <param name="backPosition">Text background position.</param>
1398                 /// <param name="backColor">Back Color</param>
1399                 /// <param name="borderColor">Border Color</param>
1400                 /// <param name="borderWidth">Border Width</param>
1401                 /// <param name="borderDashStyle">Border Style</param>
1402                 /// <param name="series">Series</param>
1403                 /// <param name="point">Point</param>
1404                 /// <param name="pointIndex">Point index in series</param>
1405                 internal void DrawPointLabelStringRel( 
1406                         CommonElements common,
1407                         string text, 
1408                         System.Drawing.Font font, 
1409                         System.Drawing.Brush brush, 
1410                         PointF position, 
1411                         System.Drawing.StringFormat format, 
1412                         int angle,
1413                         RectangleF backPosition,
1414                         Color backColor, 
1415                         Color borderColor, 
1416                         int borderWidth, 
1417                         ChartDashStyle borderDashStyle,
1418                         Series series,
1419                         DataPoint point,
1420                         int pointIndex)
1421                 {
1422                         // Start Svg/Flash Selection mode
1423                         this.StartHotRegion( point, true );
1424
1425                         // Draw background
1426                         DrawPointLabelBackground( 
1427                                 common,
1428                                 angle,
1429                                 position, 
1430                                 backPosition,
1431                                 backColor, 
1432                                 borderColor, 
1433                                 borderWidth, 
1434                                 borderDashStyle,
1435                                 series,
1436                                 point,
1437                                 pointIndex);
1438
1439                         // End Svg/Flash Selection mode
1440                         this.EndHotRegion( );
1441
1442             point._lastLabelText = text;
1443             // Draw text
1444             if (IsRightToLeft)
1445             {
1446                 // datapoint label alignments should appear as not RTL
1447                 using (StringFormat fmt = (StringFormat)format.Clone())
1448                 {
1449                     if (fmt.Alignment == StringAlignment.Far)
1450                     {
1451                         fmt.Alignment = StringAlignment.Near;
1452                     }
1453                     else if (fmt.Alignment == StringAlignment.Near)
1454                     {
1455                         fmt.Alignment = StringAlignment.Far;
1456                     }
1457                     DrawStringRel(text,font,brush,position,fmt,angle);
1458                 }
1459             }
1460             else
1461                 DrawStringRel(text,font,brush,position,format,angle);
1462                 }
1463
1464                 /// <summary>
1465                 /// Draw a string and fills it's background
1466                 /// </summary>
1467                 /// <param name="common">The Common elements object.</param>
1468                 /// <param name="angle">Text angle.</param>
1469                 /// <param name="textPosition">Text position.</param>
1470                 /// <param name="backPosition">Text background position.</param>
1471                 /// <param name="backColor">Back Color</param>
1472                 /// <param name="borderColor">Border Color</param>
1473                 /// <param name="borderWidth">Border Width</param>
1474                 /// <param name="borderDashStyle">Border Style</param>
1475                 /// <param name="series">Series</param>
1476                 /// <param name="point">Point</param>
1477                 /// <param name="pointIndex">Point index in series</param>
1478                 private void DrawPointLabelBackground( 
1479                         CommonElements common,
1480                         int angle,
1481                         PointF textPosition,
1482                         RectangleF backPosition,
1483                         Color backColor, 
1484                         Color borderColor, 
1485                         int borderWidth, 
1486                         ChartDashStyle borderDashStyle,
1487                         Series series,
1488                         DataPoint point,
1489                         int pointIndex)
1490                 {
1491                         // Draw background
1492                         if(!backPosition.IsEmpty)
1493                         {
1494                                 RectangleF backPositionAbs = this.Round(this.GetAbsoluteRectangle(backPosition));
1495
1496                                 // Get rotation point
1497                                 PointF rotationPoint = PointF.Empty;
1498                                 if(textPosition.IsEmpty)
1499                                 {
1500                                         rotationPoint = new PointF(backPositionAbs.X + backPositionAbs.Width/2f, backPositionAbs.Y + backPositionAbs.Height/2f);
1501                                 }
1502                                 else
1503                                 {
1504                                         rotationPoint = this.GetAbsolutePoint(textPosition);
1505                                 }
1506
1507                                 // Create a matrix and rotate it.
1508                                 _myMatrix = this.Transform.Clone();
1509                                 _myMatrix.RotateAt( angle, rotationPoint );
1510
1511                                 // Save old state
1512                                 GraphicsState graphicsState = this.Save();
1513
1514                                 // Set transformatino
1515                                 this.Transform = _myMatrix;
1516
1517                 // Check for empty colors
1518                                 if( !backColor.IsEmpty ||
1519                                         !borderColor.IsEmpty)
1520                                 {
1521                                         // Fill box around the label
1522                                         using(Brush     brush = new SolidBrush(backColor))
1523                                         {
1524                                                 this.FillRectangle(brush, backPositionAbs);
1525                                         }
1526
1527                     // deliant: Fix VSTS #156433        (2)     Data Label Border in core always shows when the style is set to NotSet  
1528                     // Draw box border
1529                                         if(  borderWidth > 0 &&
1530                         !borderColor.IsEmpty && borderDashStyle != ChartDashStyle.NotSet)
1531                                         {
1532                         AntiAliasingStyles saveAntiAliasing = this.AntiAliasing;
1533                         try
1534                         {
1535                             this.AntiAliasing = AntiAliasingStyles.None;                                                
1536                             using(Pen pen = new Pen(borderColor, borderWidth))
1537                                                     {
1538                                                             pen.DashStyle = GetPenStyle( borderDashStyle );
1539                                                             this.DrawRectangle(
1540                                                                     pen, 
1541                                                                     backPositionAbs.X, 
1542                                                                     backPositionAbs.Y, 
1543                                                                     backPositionAbs.Width, 
1544                                                                     backPositionAbs.Height);
1545                                                     }
1546                         }
1547                         finally
1548                         {
1549                             this.AntiAliasing = saveAntiAliasing;
1550                         }
1551                                         }
1552                                 }
1553                                 else
1554                                 {
1555                                         // Draw invisible rectangle to handle tooltips
1556                                         using(Brush     brush = new SolidBrush(Color.Transparent))
1557                                         {
1558                                                 this.FillRectangle(brush, backPositionAbs);
1559                                         }
1560                                 }
1561                         
1562
1563                                 // Restore old state
1564                                 this.Restore(graphicsState);
1565
1566                                 // Add point label hot region
1567                                 if( common != null &&
1568                                         common.ProcessModeRegions)
1569                                 {
1570 #if !Microsoft_CONTROL
1571                                         // Remember all point attributes
1572                     string oldToolTip = point.IsCustomPropertySet( CommonCustomProperties.ToolTip) ?  point.ToolTip : null;
1573                                         string oldUrl = point.IsCustomPropertySet( CommonCustomProperties.Url) ?  point.Url : null;
1574                                         string oldMapAreaAttributes = point.IsCustomPropertySet( CommonCustomProperties.MapAreaAttributes) ?  point.MapAreaAttributes : null;
1575                     string oldPostback = point.IsCustomPropertySet( CommonCustomProperties.PostBackValue) ?  point.PostBackValue : null;
1576                     object oldTag = point.Tag;
1577                     // Set label attributes into the point attribute.
1578                                         // Workaround for the AddHotRegion method limitation.
1579                                         point.ToolTip = point.LabelToolTip;
1580                                         point.Url = point.LabelUrl;
1581                                         point.MapAreaAttributes = point.LabelMapAreaAttributes;
1582                     point.PostBackValue = point.PostBackValue;
1583 #endif // !Microsoft_CONTROL
1584
1585                     // Insert area
1586                                         if(angle == 0)
1587                                         {
1588                                                 common.HotRegionsList.AddHotRegion( 
1589                                                         backPosition,
1590                                                         point,
1591                                                         series.Name,
1592                                                         pointIndex );
1593                                         }
1594                                         else
1595                                         {
1596                                                 // Convert rectangle to the graphics path and apply rotation transformation
1597                         using (GraphicsPath path = new GraphicsPath())
1598                         {
1599                             path.AddRectangle(backPositionAbs);
1600                             path.Transform(_myMatrix);
1601
1602                             // Add hot region
1603                             common.HotRegionsList.AddHotRegion(
1604                                 path,
1605                                 false,
1606                                 this,
1607                                 point,
1608                                 series.Name,
1609                                 pointIndex);
1610                         }
1611                                         }
1612
1613 #if !Microsoft_CONTROL
1614                                         // Restore all point attributes
1615                     if (oldToolTip != null) point.ToolTip = oldToolTip; else point.ResetToolTip();
1616                     if (oldUrl != null) point.Url = oldUrl; else point.ResetUrl();
1617                     if (oldMapAreaAttributes != null) point.MapAreaAttributes = oldMapAreaAttributes; else point.ResetMapAreaAttributes();
1618                     if (oldPostback != null) point.PostBackValue = oldPostback; else point.ResetPostBackValue();
1619                     point.Tag = oldTag;
1620 #endif // !Microsoft_CONTROL
1621
1622                                         // Set new hot region element type 
1623                     if (common.HotRegionsList.List != null && common.HotRegionsList.List.Count > 0)
1624                                         {
1625                                                 ((HotRegion)common.HotRegionsList.List[common.HotRegionsList.List.Count - 1]).Type = 
1626                                                         ChartElementType.DataPointLabel;
1627                                         }
1628                                 }
1629                         }
1630                 }
1631
1632                 /// <summary>
1633                 /// Draw a string.
1634                 /// </summary>
1635                 /// <param name="text">Text.</param>
1636                 /// <param name="font">Text Font.</param>
1637                 /// <param name="brush">Text Brush.</param>
1638                 /// <param name="position">Text Position.</param>
1639                 /// <param name="format">Format and text alignment.</param>
1640                 /// <param name="angle">Text angle.</param>
1641                 internal void DrawStringRel( 
1642                         string text, 
1643                         System.Drawing.Font font, 
1644                         System.Drawing.Brush brush, 
1645                         PointF position, 
1646                         System.Drawing.StringFormat format, 
1647                         int angle 
1648                         )
1649                 {
1650                         DrawStringAbs( 
1651                                 text, 
1652                                 font, 
1653                                 brush, 
1654                                 GetAbsolutePoint(position), 
1655                                 format, 
1656                                 angle);
1657                 }
1658
1659                 /// <summary>
1660                 /// Draw a string.
1661                 /// </summary>
1662                 /// <param name="text">Text.</param>
1663                 /// <param name="font">Text Font.</param>
1664                 /// <param name="brush">Text Brush.</param>
1665                 /// <param name="absPosition">Text Position.</param>
1666                 /// <param name="format">Format and text alignment.</param>
1667                 /// <param name="angle">Text angle.</param>
1668                 internal void DrawStringAbs( 
1669                         string text, 
1670                         System.Drawing.Font font, 
1671                         System.Drawing.Brush brush, 
1672                         PointF absPosition, 
1673                         System.Drawing.StringFormat format, 
1674                         int angle 
1675                         )
1676                 {
1677                         // Create a matrix and rotate it.
1678                         _myMatrix = this.Transform.Clone();
1679                         _myMatrix.RotateAt(angle, absPosition);
1680     
1681                         // Save aold state
1682                         GraphicsState graphicsState = this.Save();
1683
1684                         // Set Angle
1685                         this.Transform = _myMatrix;
1686
1687                         // Draw text with anti-aliasing
1688                         /*
1689                         if( (AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
1690                                 this.TextRenderingHint = TextRenderingHint.AntiAlias;
1691                         else
1692                                 this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
1693                         */
1694
1695                         // Draw a string
1696                         this.DrawString( text, font, brush, absPosition , format );
1697
1698                         // Restore old state
1699                         this.Restore(graphicsState);
1700                 }
1701
1702         /// <summary>
1703         /// This method is used by the axis title hot region generation code. 
1704         /// It transforms the centered rectangle the same way as the Axis title text.
1705         /// </summary>
1706         /// <param name="center">Title center</param>
1707         /// <param name="size">Title text size</param>
1708         /// <param name="angle">Title rotation angle</param>
1709         /// <returns></returns>
1710         internal GraphicsPath GetTranformedTextRectPath(PointF center, SizeF size, int angle)
1711         {
1712             // Text hot area is 10px greater than the size of text
1713             size.Width += 10; 
1714             size.Height += 10;
1715             
1716             // Get the absolute center and create the centered rectangle points
1717             PointF absCenter = GetAbsolutePoint(center);            
1718             PointF[] points = new PointF[] {
1719                 new PointF(absCenter.X - size.Width / 2f, absCenter.Y - size.Height / 2f), 
1720                 new PointF(absCenter.X + size.Width / 2f, absCenter.Y - size.Height / 2f), 
1721                 new PointF(absCenter.X + size.Width / 2f, absCenter.Y + size.Height / 2f), 
1722                 new PointF(absCenter.X - size.Width / 2f, absCenter.Y + size.Height / 2f)};
1723
1724             //Prepare the same tranformation matrix as used for the axis title
1725             Matrix matrix = this.Transform.Clone();
1726             matrix.RotateAt(angle, absCenter);
1727             //Tranform the rectangle points
1728             matrix.TransformPoints(points);
1729
1730             //Return the path consisting of the rect points
1731             GraphicsPath path = new GraphicsPath();
1732             path.AddLines(points);
1733             path.CloseAllFigures();
1734             return path;
1735         }
1736
1737
1738
1739
1740                 /// <summary>
1741                 /// Draw label string.
1742                 /// </summary>
1743                 /// <param name="axis">Label axis.</param>
1744                 /// <param name="labelRowIndex">Label text row index (0-10).</param>
1745                 /// <param name="labelMark">Second row labels mark style.</param>
1746                 /// <param name="markColor">Label mark line color.</param>
1747                 /// <param name="text">Label text.</param>
1748                 /// <param name="image">Label image name.</param>
1749                 /// <param name="imageTransparentColor">Label image transparent color.</param>
1750                 /// <param name="font">Text bont.</param>
1751                 /// <param name="brush">Text brush.</param>
1752                 /// <param name="position">Text position rectangle.</param>
1753                 /// <param name="format">Label text format.</param>
1754                 /// <param name="angle">Label text angle.</param>
1755                 /// <param name="boundaryRect">Specifies the rectangle where the label text MUST be fitted.</param>
1756                 /// <param name="label">Custom Label Item</param>
1757                 /// <param name="truncatedLeft">Label is truncated on the left.</param>
1758                 /// <param name="truncatedRight">Label is truncated on the right.</param>
1759                 internal void DrawLabelStringRel( 
1760                         Axis axis, 
1761                         int labelRowIndex, 
1762                         LabelMarkStyle labelMark, 
1763                         Color markColor,
1764                         string text, 
1765                         string image,
1766                         Color imageTransparentColor,
1767                         System.Drawing.Font font, 
1768                         System.Drawing.Brush brush, 
1769                         RectangleF position, 
1770                         System.Drawing.StringFormat format, 
1771                         int angle, 
1772                         RectangleF boundaryRect,
1773                         CustomLabel label,
1774                         bool truncatedLeft,
1775                         bool truncatedRight)
1776                 {
1777                         Matrix oldTransform;
1778             using (StringFormat drawingFormat = (StringFormat)format.Clone())
1779             {
1780                 SizeF labelSize = SizeF.Empty;
1781
1782                 // Check that rectangle is not empty
1783                 if (position.Width == 0 || position.Height == 0)
1784                 {
1785                     return;
1786                 }
1787
1788                 // Find absolute position
1789                 RectangleF absPosition = this.GetAbsoluteRectangle(position);
1790
1791                 // Make sure the rectangle is not empty
1792                 if (absPosition.Width < 1f)
1793                 {
1794                     absPosition.Width = 1f;
1795                 }
1796                 if (absPosition.Height < 1f)
1797                 {
1798                     absPosition.Height = 1f;
1799                 }
1800
1801 #if DEBUG
1802                 // TESTING CODE: Shows labels rectangle position.
1803                 //                      Rectangle rr = Rectangle.Round(absPosition);
1804                 //                      rr.Width = (int)Math.Round(absPosition.Right) - rr.X;
1805                 //                      rr.Height = (int)Math.Round(absPosition.Bottom) - rr.Y;
1806                 //                      this.DrawRectangle(Pens.Red,rr.X, rr.Y, rr.Width, rr.Height);
1807 #endif // DEBUG
1808
1809                 CommonElements common = axis.Common;
1810                 if (common.ProcessModeRegions)
1811                 {
1812                     common.HotRegionsList.AddHotRegion(Rectangle.Round(absPosition), label, ChartElementType.AxisLabels, false, true);
1813                 }
1814
1815                 //********************************************************************
1816                 //** Draw labels in the second row
1817                 //********************************************************************
1818                 if (labelRowIndex > 0)
1819                 {
1820                     drawingFormat.LineAlignment = StringAlignment.Center;
1821                     drawingFormat.Alignment = StringAlignment.Center;
1822                     angle = 0;
1823
1824                     if (axis.AxisPosition == AxisPosition.Left)
1825                     {
1826                         angle = -90;
1827                     }
1828                     else if (axis.AxisPosition == AxisPosition.Right)
1829                     {
1830                         angle = 90;
1831                     }
1832                     else if (axis.AxisPosition == AxisPosition.Top)
1833                     {
1834                     }
1835                     else if (axis.AxisPosition == AxisPosition.Bottom)
1836                     {
1837                     }
1838                 }
1839
1840                 //********************************************************************
1841                 //** Calculate rotation point
1842                 //********************************************************************
1843                 PointF rotationPoint = PointF.Empty;
1844                 if (axis.AxisPosition == AxisPosition.Left)
1845                 {
1846                     rotationPoint.X = absPosition.Right;
1847                     rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
1848                 }
1849                 else if (axis.AxisPosition == AxisPosition.Right)
1850                 {
1851                     rotationPoint.X = absPosition.Left;
1852                     rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
1853                 }
1854                 else if (axis.AxisPosition == AxisPosition.Top)
1855                 {
1856                     rotationPoint.X = absPosition.X + absPosition.Width / 2F;
1857                     rotationPoint.Y = absPosition.Bottom;
1858                 }
1859                 else if (axis.AxisPosition == AxisPosition.Bottom)
1860                 {
1861                     rotationPoint.X = absPosition.X + absPosition.Width / 2F;
1862                     rotationPoint.Y = absPosition.Top;
1863                 }
1864
1865                 //********************************************************************
1866                 //** Adjust rectangle for horisontal axis
1867                 //********************************************************************
1868                 if ((axis.AxisPosition == AxisPosition.Top || axis.AxisPosition == AxisPosition.Bottom) &&
1869                     angle != 0)
1870                 {
1871                     // Get rectangle center
1872                     rotationPoint.X = absPosition.X + absPosition.Width / 2F;
1873                     rotationPoint.Y = (axis.AxisPosition == AxisPosition.Top) ? absPosition.Bottom : absPosition.Y;
1874
1875                     // Rotate rectangle 90 degrees
1876                     RectangleF newRect = RectangleF.Empty;
1877                     newRect.X = absPosition.X + absPosition.Width / 2F;
1878                     newRect.Y = absPosition.Y - absPosition.Width / 2F;
1879                     newRect.Height = absPosition.Width;
1880                     newRect.Width = absPosition.Height;
1881
1882                     // Adjust values for bottom axis
1883                     if (axis.AxisPosition == AxisPosition.Bottom)
1884                     {
1885                         if (angle < 0)
1886                         {
1887                             newRect.X -= newRect.Width;
1888                         }
1889
1890                         // Replace string alignment
1891                         drawingFormat.Alignment = StringAlignment.Near;
1892                         if (angle < 0)
1893                         {
1894                             drawingFormat.Alignment = StringAlignment.Far;
1895                         }
1896                         drawingFormat.LineAlignment = StringAlignment.Center;
1897                     }
1898
1899                     // Adjust values for bottom axis
1900                     if (axis.AxisPosition == AxisPosition.Top)
1901                     {
1902                         newRect.Y += absPosition.Height;
1903                         if (angle > 0)
1904                         {
1905                             newRect.X -= newRect.Width;
1906                         }
1907
1908                         // Replace string alignment
1909                         drawingFormat.Alignment = StringAlignment.Far;
1910                         if (angle < 0)
1911                         {
1912                             drawingFormat.Alignment = StringAlignment.Near;
1913                         }
1914                         drawingFormat.LineAlignment = StringAlignment.Center;
1915                     }
1916
1917                     // Set new label rect
1918                     absPosition = newRect;
1919                 }
1920
1921                 //********************************************************************
1922                 //** 90 degrees is a special case for vertical axes
1923                 //********************************************************************
1924                 if ((axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right) &&
1925                     (angle == 90 || angle == -90))
1926                 {
1927                     // Get rectangle center
1928                     rotationPoint.X = absPosition.X + absPosition.Width / 2F;
1929                     rotationPoint.Y = absPosition.Y + absPosition.Height / 2F;
1930
1931                     // Rotate rectangle 90 degrees
1932                     RectangleF newRect = RectangleF.Empty;
1933                     newRect.X = rotationPoint.X - absPosition.Height / 2F;
1934                     newRect.Y = rotationPoint.Y - absPosition.Width / 2F;
1935                     newRect.Height = absPosition.Width;
1936                     newRect.Width = absPosition.Height;
1937                     absPosition = newRect;
1938
1939                     // Replace string alignment
1940                     StringAlignment align = drawingFormat.Alignment;
1941                     drawingFormat.Alignment = drawingFormat.LineAlignment;
1942                     drawingFormat.LineAlignment = align;
1943                     if (angle == 90)
1944                     {
1945                         if (drawingFormat.LineAlignment == StringAlignment.Far)
1946                             drawingFormat.LineAlignment = StringAlignment.Near;
1947                         else if (drawingFormat.LineAlignment == StringAlignment.Near)
1948                             drawingFormat.LineAlignment = StringAlignment.Far;
1949                     }
1950                     if (angle == -90)
1951                     {
1952                         if (drawingFormat.Alignment == StringAlignment.Far)
1953                             drawingFormat.Alignment = StringAlignment.Near;
1954                         else if (drawingFormat.Alignment == StringAlignment.Near)
1955                             drawingFormat.Alignment = StringAlignment.Far;
1956                     }
1957                 }
1958
1959                 //********************************************************************
1960                 //** Create a matrix and rotate it.
1961                 //********************************************************************
1962                 oldTransform = null;
1963                 if (angle != 0)
1964                 {
1965                     _myMatrix = this.Transform.Clone();
1966                     _myMatrix.RotateAt(angle, rotationPoint);
1967
1968                     // Old angle
1969                     oldTransform = this.Transform;
1970
1971                     // Set Angle
1972                     this.Transform = _myMatrix;
1973                 }
1974
1975                 //********************************************************************
1976                 //** Measure string exact rectangle and adjust label bounding rectangle
1977                 //********************************************************************
1978                 RectangleF labelRect = Rectangle.Empty;
1979                 float offsetY = 0f;
1980                 float offsetX = 0f;
1981                 
1982                 // Measure text size
1983                 labelSize = this.MeasureString(text.Replace("\\n", "\n"), font, absPosition.Size, drawingFormat);
1984
1985                 // Calculate text rectangle
1986                 labelRect.Width = labelSize.Width;
1987                 labelRect.Height = labelSize.Height;
1988                 if (drawingFormat.Alignment == StringAlignment.Far)
1989                 {
1990                     labelRect.X = absPosition.Right - labelSize.Width;
1991                 }
1992                 else if (drawingFormat.Alignment == StringAlignment.Near)
1993                 {
1994                     labelRect.X = absPosition.X;
1995                 }
1996                 else if (drawingFormat.Alignment == StringAlignment.Center)
1997                 {
1998                     labelRect.X = absPosition.X + absPosition.Width / 2F - labelSize.Width / 2F;
1999                 }
2000
2001                 if (drawingFormat.LineAlignment == StringAlignment.Far)
2002                 {
2003                     labelRect.Y = absPosition.Bottom - labelSize.Height;
2004                 }
2005                 else if (drawingFormat.LineAlignment == StringAlignment.Near)
2006                 {
2007                     labelRect.Y = absPosition.Y;
2008                 }
2009                 else if (drawingFormat.LineAlignment == StringAlignment.Center)
2010                 {
2011                     labelRect.Y = absPosition.Y + absPosition.Height / 2F - labelSize.Height / 2F;
2012                 }
2013
2014                 //If the angle is not vertical or horizontal
2015                 if (angle != 0 && angle != 90 && angle != -90)
2016                 {
2017                     // Adjust label rectangle so it will not overlap the plotting area
2018                     offsetY = (float)Math.Sin((90 - angle) / 180F * Math.PI) * labelRect.Height / 2F;
2019                     offsetX = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * labelRect.Height / 2F;
2020
2021                     if (axis.AxisPosition == AxisPosition.Left)
2022                     {
2023                         _myMatrix.Translate(-offsetX, 0);
2024                     }
2025                     else if (axis.AxisPosition == AxisPosition.Right)
2026                     {
2027                         _myMatrix.Translate(offsetX, 0);
2028                     }
2029                     else if (axis.AxisPosition == AxisPosition.Top)
2030                     {
2031                         _myMatrix.Translate(0, -offsetY);
2032                     }
2033                     else if (axis.AxisPosition == AxisPosition.Bottom)
2034                     {
2035                         _myMatrix.Translate(0, offsetY);
2036                     }
2037
2038                     // Adjust label rectangle so it will be inside boundary
2039                     if (boundaryRect != RectangleF.Empty)
2040                     {
2041                         Region region = new Region(labelRect);
2042                         region.Transform(_myMatrix);
2043
2044                         // Extend boundary rectangle to the chart picture border
2045                         if (axis.AxisPosition == AxisPosition.Left)
2046                         {
2047                             boundaryRect.Width += boundaryRect.X;
2048                             boundaryRect.X = 0;
2049                         }
2050                         else if (axis.AxisPosition == AxisPosition.Right)
2051                         {
2052                             boundaryRect.Width = this._common.Width - boundaryRect.X;
2053                         }
2054                         else if (axis.AxisPosition == AxisPosition.Top)
2055                         {
2056                             boundaryRect.Height += boundaryRect.Y;
2057                             boundaryRect.Y = 0;
2058                         }
2059                         else if (axis.AxisPosition == AxisPosition.Bottom)
2060                         {
2061                             boundaryRect.Height = this._common.Height - boundaryRect.Y;
2062                         }
2063
2064                         // Exclude boundary rectangle from the label rectangle
2065                         region.Exclude(this.GetAbsoluteRectangle(boundaryRect));
2066
2067                         // If any part of the label was outside bounding rectangle
2068                         if (!region.IsEmpty(Graphics))
2069                         {
2070                             this.Transform = oldTransform;
2071                             RectangleF truncateRect = region.GetBounds(Graphics);
2072
2073                             float sizeChange = truncateRect.Width / (float)Math.Cos(Math.Abs(angle) / 180F * Math.PI);
2074                             if (axis.AxisPosition == AxisPosition.Left)
2075                             {
2076                                 sizeChange -= labelRect.Height * (float)Math.Tan(Math.Abs(angle) / 180F * Math.PI);
2077                                 absPosition.Y = labelRect.Y;
2078                                 absPosition.X = labelRect.X + sizeChange;
2079                                 absPosition.Width = labelRect.Width - sizeChange;
2080                                 absPosition.Height = labelRect.Height;
2081                             }
2082                             else if (axis.AxisPosition == AxisPosition.Right)
2083                             {
2084                                 sizeChange -= labelRect.Height * (float)Math.Tan(Math.Abs(angle) / 180F * Math.PI);
2085                                 absPosition.Y = labelRect.Y;
2086                                 absPosition.X = labelRect.X;
2087                                 absPosition.Width = labelRect.Width - sizeChange;
2088                                 absPosition.Height = labelRect.Height;
2089                             }
2090                             else if (axis.AxisPosition == AxisPosition.Top)
2091                             {
2092                                 absPosition.Y = labelRect.Y;
2093                                 absPosition.X = labelRect.X;
2094                                 absPosition.Width = labelRect.Width - sizeChange;
2095                                 absPosition.Height = labelRect.Height;
2096                                 if (angle > 0)
2097                                 {
2098                                     absPosition.X += sizeChange;
2099                                 }
2100                             }
2101                             else if (axis.AxisPosition == AxisPosition.Bottom)
2102                             {
2103                                 absPosition.Y = labelRect.Y;
2104                                 absPosition.X = labelRect.X;
2105                                 absPosition.Width = labelRect.Width - sizeChange;
2106                                 absPosition.Height = labelRect.Height;
2107                                 if (angle < 0)
2108                                 {
2109                                     absPosition.X += sizeChange;
2110                                 }
2111                             }
2112                         }
2113                     }
2114
2115                     // Update transformation matrix
2116                     this.Transform = _myMatrix;
2117                 }
2118
2119                 //********************************************************************
2120                 //** Reserve space on the left for the label iamge
2121                 //********************************************************************
2122                 RectangleF absPositionWithoutImage = new RectangleF(absPosition.Location, absPosition.Size);
2123                 
2124                 System.Drawing.Image labelImage = null;
2125                 SizeF imageAbsSize = new SizeF();
2126
2127                 if (image.Length > 0)
2128                 {
2129                     labelImage = axis.Common.ImageLoader.LoadImage(label.Image);
2130
2131                     if (labelImage != null)
2132                     {
2133                         ImageLoader.GetAdjustedImageSize(labelImage, this.Graphics, ref imageAbsSize);
2134
2135                         // Adjust label position using image size
2136                         absPositionWithoutImage.Width -= imageAbsSize.Width;
2137                         absPositionWithoutImage.X += imageAbsSize.Width;
2138                     }
2139
2140                     if (absPositionWithoutImage.Width < 1f)
2141                     {
2142                         absPositionWithoutImage.Width = 1f;
2143                     }
2144
2145                 }
2146
2147                 //********************************************************************
2148                 //** Draw tick marks for labels in second row
2149                 //********************************************************************
2150                 if (labelRowIndex > 0 && labelMark != LabelMarkStyle.None)
2151                 {
2152                     // Make sure that me know the exact size of the text
2153                     labelSize = this.MeasureString(
2154                         text.Replace("\\n", "\n"),
2155                         font,
2156                         absPositionWithoutImage.Size,
2157                         drawingFormat);
2158
2159                     // Adjust for label image
2160                     SizeF labelSizeWithImage = new SizeF(labelSize.Width, labelSize.Height);
2161                     if (labelImage != null)
2162                     {
2163                         labelSizeWithImage.Width += imageAbsSize.Width;
2164                     }
2165
2166                     // Draw mark
2167                     DrawSecondRowLabelMark(
2168                         axis,
2169                         markColor,
2170                         absPosition,
2171                         labelSizeWithImage,
2172                         labelMark,
2173                         truncatedLeft,
2174                         truncatedRight,
2175                         oldTransform);
2176                 }
2177
2178                 //********************************************************************
2179                 //** Make sure that one line label will not disapear with LineLimit
2180                 //** flag on.
2181                 //********************************************************************
2182                 if ((drawingFormat.FormatFlags & StringFormatFlags.LineLimit) != 0)
2183                 {
2184                     // Measure string height out of one character
2185                     drawingFormat.FormatFlags ^= StringFormatFlags.LineLimit;
2186                     SizeF size = this.MeasureString("I", font, absPosition.Size, drawingFormat);
2187
2188                     // If height of one characte is more than rectangle heigjt - remove LineLimit flag
2189                     if (size.Height < absPosition.Height)
2190                     {
2191                         drawingFormat.FormatFlags |= StringFormatFlags.LineLimit;
2192                     }
2193                 }
2194                 else
2195                 {
2196                     // Set NoClip flag
2197                     if ((drawingFormat.FormatFlags & StringFormatFlags.NoClip) != 0)
2198                     {
2199                         drawingFormat.FormatFlags ^= StringFormatFlags.NoClip;
2200                     }
2201
2202                     // Measure string height out of one character without clipping
2203                     SizeF size = this.MeasureString("I", font, absPosition.Size, drawingFormat);
2204
2205                     // Clear NoClip flag
2206                     drawingFormat.FormatFlags ^= StringFormatFlags.NoClip;
2207
2208                     // If height of one characte is more than rectangle heigt - set NoClip flag
2209                     if (size.Height > absPosition.Height)
2210                     {
2211                         float delta = size.Height - absPosition.Height;
2212                         absPosition.Y -= delta / 2f;
2213                         absPosition.Height += delta;
2214                     }
2215                 }
2216
2217                 //********************************************************************
2218                 //** Draw a string
2219                 //********************************************************************
2220                 if (IsRightToLeft)
2221                 {
2222                     // label alignment on the axis should appear as not RTL. 
2223                     using (StringFormat fmt = (StringFormat)drawingFormat.Clone())
2224                     {
2225
2226                         if (fmt.Alignment == StringAlignment.Far)
2227                         {
2228                             fmt.Alignment = StringAlignment.Near;
2229                         }
2230                         else if (fmt.Alignment == StringAlignment.Near)
2231                         {
2232                             fmt.Alignment = StringAlignment.Far;
2233                         }
2234                         this.DrawString(text.Replace("\\n", "\n"), font, brush,
2235                         absPositionWithoutImage,
2236                         fmt);
2237
2238                     }
2239                 }
2240                 else
2241                     this.DrawString(text.Replace("\\n", "\n"), font, brush,
2242                     absPositionWithoutImage,
2243                     drawingFormat);
2244
2245                 // Add separate hot region for the label
2246                 if (common.ProcessModeRegions)
2247                 {
2248                     using (GraphicsPath path = new GraphicsPath())
2249                     {
2250                         path.AddRectangle(labelRect);
2251                         path.Transform(this.Transform);
2252                         string url = string.Empty;
2253                         string mapAreaAttributes = string.Empty;
2254                         string postbackValue = string.Empty;
2255 #if !Microsoft_CONTROL
2256                         url = label.Url;
2257                         mapAreaAttributes = label.MapAreaAttributes;
2258                         postbackValue = label.PostBackValue;
2259 #endif // !Microsoft_CONTROL
2260                         common.HotRegionsList.AddHotRegion(
2261                             this,
2262                             path,
2263                             false,
2264                             label.ToolTip,
2265                             url,
2266                             mapAreaAttributes,
2267                             postbackValue,
2268                             label,
2269                             ChartElementType.AxisLabels);
2270                     }
2271                 }
2272
2273                 //********************************************************************
2274                 //** Draw an image
2275                 //********************************************************************
2276                 if (labelImage != null)
2277                 {
2278                     // Make sure we no the text size
2279                     if (labelSize.IsEmpty)
2280                     {
2281                         labelSize = this.MeasureString(
2282                             text.Replace("\\n", "\n"),
2283                             font,
2284                             absPositionWithoutImage.Size,
2285                             drawingFormat);
2286                     }
2287
2288                     // Calculate image rectangle
2289                     RectangleF imageRect = new RectangleF(
2290                         absPosition.X + (absPosition.Width - imageAbsSize.Width - labelSize.Width) / 2,
2291                         absPosition.Y + (absPosition.Height - imageAbsSize.Height) / 2,
2292                         imageAbsSize.Width,
2293                         imageAbsSize.Height);
2294
2295                     if (drawingFormat.LineAlignment == StringAlignment.Center)
2296                     {
2297                         imageRect.Y = absPosition.Y + (absPosition.Height - imageAbsSize.Height) / 2;
2298                     }
2299                     else if (drawingFormat.LineAlignment == StringAlignment.Far)
2300                     {
2301                         imageRect.Y = absPosition.Bottom - (labelSize.Height + imageAbsSize.Height) / 2;
2302                     }
2303                     else if (drawingFormat.LineAlignment == StringAlignment.Near)
2304                     {
2305                         imageRect.Y = absPosition.Top + (labelSize.Height - imageAbsSize.Height) / 2;
2306                     }
2307
2308                     if (drawingFormat.Alignment == StringAlignment.Center)
2309                     {
2310                         imageRect.X = absPosition.X + (absPosition.Width - imageAbsSize.Width - labelSize.Width) / 2;
2311                     }
2312                     else if (drawingFormat.Alignment == StringAlignment.Far)
2313                     {
2314                         imageRect.X = absPosition.Right - imageAbsSize.Width - labelSize.Width;
2315                     }
2316                     else if (drawingFormat.Alignment == StringAlignment.Near)
2317                     {
2318                         imageRect.X = absPosition.X;
2319                     }
2320
2321                     // Create image attribute
2322                     ImageAttributes attrib = new ImageAttributes();
2323                     if (imageTransparentColor != Color.Empty)
2324                     {
2325                         attrib.SetColorKey(imageTransparentColor, imageTransparentColor, ColorAdjustType.Default);
2326                     }
2327
2328                     // Draw image
2329                     this.DrawImage(
2330                         labelImage,
2331                         Rectangle.Round(imageRect),
2332                         0, 0, labelImage.Width, labelImage.Height,
2333                         GraphicsUnit.Pixel,
2334                         attrib);
2335
2336                     // Add separate hot region for the label image
2337                     if (common.ProcessModeRegions)
2338                     {
2339                         using (GraphicsPath path = new GraphicsPath())
2340                         {
2341                             path.AddRectangle(imageRect);
2342                             path.Transform(this.Transform);
2343                             string imageUrl = string.Empty;
2344                             string imageMapAreaAttributes = string.Empty;
2345                             string postbackValue = string.Empty;
2346 #if !Microsoft_CONTROL
2347                             imageUrl = label.ImageUrl;
2348                             imageMapAreaAttributes = label.ImageMapAreaAttributes;
2349                             postbackValue = label.PostBackValue;
2350 #endif // !Microsoft_CONTROL
2351                             common.HotRegionsList.AddHotRegion(
2352                                 this,
2353                                 path,
2354                                 false,
2355                                 string.Empty,
2356                                 imageUrl,
2357                                 imageMapAreaAttributes,
2358                                 postbackValue,
2359                                 label,
2360                                 ChartElementType.AxisLabelImage);
2361                         }
2362                     }
2363                 }
2364             }
2365
2366                         // Set Old Angle
2367                         if(oldTransform != null)
2368                         {
2369                                 this.Transform = oldTransform;
2370                         }
2371                 }
2372
2373                 /// <summary>
2374                 /// Draw box marks for the labels in second row
2375                 /// </summary>
2376                 /// <param name="axis">Axis object.</param>
2377                 /// <param name="markColor">Label mark color.</param>
2378                 /// <param name="absPosition">Absolute position of the text.</param>
2379                 /// <param name="truncatedLeft">Label is truncated on the left.</param>
2380                 /// <param name="truncatedRight">Label is truncated on the right.</param>
2381                 /// <param name="originalTransform">Original transformation matrix.</param>
2382                 private void DrawSecondRowLabelBoxMark(
2383                         Axis axis, 
2384                         Color markColor,
2385                         RectangleF absPosition, 
2386                         bool truncatedLeft,
2387                         bool truncatedRight,
2388                         Matrix originalTransform)
2389                 {
2390                         // Remeber current and then reset original matrix
2391                         Matrix curentMatrix = this.Transform;
2392                         if(originalTransform != null)
2393                         {
2394                                 this.Transform = originalTransform;
2395                         }
2396
2397                         // Calculate center of the text rectangle
2398                         PointF  centerNotRound = new PointF(absPosition.X + absPosition.Width/2F, absPosition.Y + absPosition.Height/2F);
2399
2400                         // Rotate rectangle 90 degrees
2401                         if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
2402                         {
2403                                 RectangleF newRect = RectangleF.Empty;
2404                                 newRect.X = centerNotRound.X - absPosition.Height / 2F;
2405                                 newRect.Y = centerNotRound.Y - absPosition.Width / 2F;
2406                                 newRect.Height = absPosition.Width;
2407                                 newRect.Width = absPosition.Height;
2408                                 absPosition = newRect;
2409                         }
2410
2411                         // Get axis position
2412                         float axisPosRelative = (float)axis.GetAxisPosition(true);
2413                         PointF axisPositionAbs = new PointF(axisPosRelative, axisPosRelative);
2414                         axisPositionAbs = this.GetAbsolutePoint(axisPositionAbs);
2415
2416                         // Round position to achieve crisp lines with antialiasing
2417                         Rectangle absPositionRounded = Rectangle.Round(absPosition);
2418
2419                         // Make sure the right and bottom position is not shifted during rounding
2420                         absPositionRounded.Width = (int)Math.Round(absPosition.Right) - absPositionRounded.X;
2421                         absPositionRounded.Height = (int)Math.Round(absPosition.Bottom) - absPositionRounded.Y;
2422
2423                         // Create pen
2424                         Pen     markPen = new Pen(
2425                                 (markColor.IsEmpty) ? axis.MajorTickMark.LineColor : markColor, 
2426                                 axis.MajorTickMark.LineWidth);
2427
2428                         // Set pen style
2429                         markPen.DashStyle = GetPenStyle( axis.MajorTickMark.LineDashStyle );
2430
2431                         // Draw top/bottom lines
2432                         if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
2433                         {
2434                                 this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Top, absPositionRounded.Left, absPositionRounded.Bottom);
2435                                 this.DrawLine(markPen, absPositionRounded.Right, absPositionRounded.Top, absPositionRounded.Right, absPositionRounded.Bottom);
2436                         }
2437                         else
2438                         {
2439                                 this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Top, absPositionRounded.Right, absPositionRounded.Top);
2440                                 this.DrawLine(markPen, absPositionRounded.Left, absPositionRounded.Bottom, absPositionRounded.Right, absPositionRounded.Bottom);
2441                         }
2442
2443                         // Draw left line
2444                         if(!truncatedLeft)
2445                         {
2446                                 if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
2447                                 {
2448                                         this.DrawLine(
2449                                                 markPen, 
2450                                                 (axis.AxisPosition == AxisPosition.Left) ? absPositionRounded.Left : absPositionRounded.Right, 
2451                                                 absPositionRounded.Bottom, 
2452                                                 axisPositionAbs.X, 
2453                                                 absPositionRounded.Bottom);
2454                                 }
2455                                 else
2456                                 {
2457                                         this.DrawLine(
2458                                                 markPen, 
2459                                                 absPositionRounded.Left, 
2460                                                 (axis.AxisPosition == AxisPosition.Top) ? absPositionRounded.Top : absPositionRounded.Bottom, 
2461                                                 absPositionRounded.Left, 
2462                                                 axisPositionAbs.Y);
2463                                 }
2464                         }
2465
2466                         // Draw right line
2467                         if(!truncatedRight)
2468                         {
2469                                 if( axis.AxisPosition == AxisPosition.Left || axis.AxisPosition == AxisPosition.Right)
2470                                 {
2471                                         this.DrawLine(
2472                                                 markPen, 
2473                                                 (axis.AxisPosition == AxisPosition.Left) ? absPositionRounded.Left : absPositionRounded.Right, 
2474                                                 absPositionRounded.Top, 
2475                                                 axisPositionAbs.X, 
2476                                                 absPositionRounded.Top);
2477                                 }
2478                                 else
2479                                 {
2480                                         this.DrawLine(
2481                                                 markPen, 
2482                                                 absPositionRounded.Right, 
2483                                                 (axis.AxisPosition == AxisPosition.Top) ? absPositionRounded.Top : absPositionRounded.Bottom, 
2484                                                 absPositionRounded.Right, 
2485                                                 axisPositionAbs.Y);
2486                                 }
2487                         }
2488
2489                         // Dispose Pen
2490                         if( markPen != null )
2491                         {
2492                                 markPen.Dispose();
2493                         }
2494
2495                         // Restore currentmatrix
2496                         if(originalTransform != null)
2497                         {
2498                                 this.Transform = curentMatrix;
2499                         }
2500                 }
2501
2502
2503                 /// <summary>
2504                 /// Draw marks for the labels in second row
2505                 /// </summary>
2506                 /// <param name="axis">Axis object.</param>
2507                 /// <param name="markColor">Label mark color.</param>
2508                 /// <param name="absPosition">Absolute position of the text.</param>
2509                 /// <param name="labelSize">Exact mesured size of the text.</param>
2510                 /// <param name="labelMark">Label mark style to draw.</param>
2511                 /// <param name="truncatedLeft">Label is truncated on the left.</param>
2512                 /// <param name="truncatedRight">Label is truncated on the right.</param>
2513                 /// <param name="oldTransform">Original transformation matrix.</param>
2514                 private void DrawSecondRowLabelMark(
2515                         Axis axis, 
2516                         Color markColor,
2517                         RectangleF absPosition, 
2518                         SizeF labelSize, 
2519                         LabelMarkStyle labelMark,
2520                         bool truncatedLeft,
2521                         bool truncatedRight,
2522                         Matrix oldTransform)
2523                 {
2524                         // Do not draw marking line if width is 0 and style or color are not set
2525                         if( axis.MajorTickMark.LineWidth == 0 || 
2526                                 axis.MajorTickMark.LineDashStyle == ChartDashStyle.NotSet ||
2527                                 axis.MajorTickMark.LineColor == Color.Empty)
2528                         {
2529                                 return;
2530                         }
2531
2532                         // Remember SmoothingMode and turn off anti aliasing for 
2533                         // vertical or horizontal lines of the label markers.
2534                         SmoothingMode oldSmoothingMode = this.SmoothingMode;
2535                         this.SmoothingMode = SmoothingMode.None;
2536
2537
2538                         // Draw box marker
2539                         if(labelMark == LabelMarkStyle.Box)
2540                         {
2541                                 DrawSecondRowLabelBoxMark(
2542                                         axis, 
2543                                         markColor,
2544                                         absPosition, 
2545                                         truncatedLeft,
2546                                         truncatedRight,
2547                                         oldTransform);
2548                         }
2549                         else
2550
2551                         {
2552                                 // Calculate center of the text rectangle
2553                                 Point   center = Point.Round(new PointF(absPosition.X + absPosition.Width/2F, absPosition.Y + absPosition.Height/2F));
2554
2555                                 // Round position to achieve crisp lines with antialiasing
2556                                 Rectangle absPositionRounded = Rectangle.Round(absPosition);
2557
2558                                 // Make sure the right and bottom position is not shifted during rounding
2559                                 absPositionRounded.Width = (int)Math.Round(absPosition.Right) - absPositionRounded.X;
2560                                 absPositionRounded.Height = (int)Math.Round(absPosition.Bottom) - absPositionRounded.Y;
2561
2562
2563                                 // Arrays of points for the left and right marking lines
2564                                 PointF[]        leftLine = new PointF[3];
2565                                 PointF[]        rightLine = new PointF[3];
2566
2567                                 // Calculate marking lines coordinates
2568                                 leftLine[0].X = absPositionRounded.Left;
2569                                 leftLine[0].Y = absPositionRounded.Bottom;
2570                                 leftLine[1].X = absPositionRounded.Left;
2571                                 leftLine[1].Y = center.Y;
2572                                 leftLine[2].X = (float)Math.Round((double)center.X - labelSize.Width/2F - 1F);
2573                                 leftLine[2].Y = center.Y;
2574
2575                                 rightLine[0].X = absPositionRounded.Right;
2576                                 rightLine[0].Y = absPositionRounded.Bottom;
2577                                 rightLine[1].X = absPositionRounded.Right;
2578                                 rightLine[1].Y = center.Y;
2579                                 rightLine[2].X = (float)Math.Round((double)center.X + labelSize.Width/2F - 1F);
2580                                 rightLine[2].Y = center.Y;
2581
2582                                 if(axis.AxisPosition == AxisPosition.Bottom)
2583                                 {
2584                                         leftLine[0].Y = absPositionRounded.Top;
2585                                         rightLine[0].Y = absPositionRounded.Top;
2586                                 }
2587
2588                                 // Remove third point to draw only side marks
2589                                 if(labelMark == LabelMarkStyle.SideMark)
2590                                 {
2591                                         leftLine[2] = leftLine[1];
2592                                         rightLine[2] = rightLine[1];
2593                                 }
2594
2595                                 if(truncatedLeft)
2596                                 {
2597                                         leftLine[0] = leftLine[1];
2598                                 }
2599                                 if(truncatedRight)
2600                                 {
2601                                         rightLine[0] = rightLine[1];
2602                                 }
2603
2604                                 // Create pen
2605                                 Pen     markPen = new Pen(
2606                                         (markColor.IsEmpty) ? axis.MajorTickMark.LineColor : markColor, 
2607                                         axis.MajorTickMark.LineWidth);
2608
2609                                 // Set pen style
2610                                 markPen.DashStyle = GetPenStyle( axis.MajorTickMark.LineDashStyle );
2611
2612                                 // Draw marking lines
2613                                 this.DrawLines(markPen, leftLine);
2614                                 this.DrawLines(markPen, rightLine);
2615
2616                                 // Dispose Pen
2617                                 if( markPen != null )
2618                                 {
2619                                         markPen.Dispose();
2620                                 }
2621                         }
2622
2623                         // Restore previous SmoothingMode
2624                         this.SmoothingMode = oldSmoothingMode;
2625                 }
2626
2627                 /// <summary>
2628                 /// Measures the specified text string when drawn with 
2629                 /// the specified Font object and formatted with the 
2630                 /// specified StringFormat object.
2631                 /// </summary>
2632                 /// <param name="text">The string to measure</param>
2633                 /// <param name="font">The Font object used to determine the size of the text string. </param>
2634                 /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
2635                 internal SizeF MeasureStringRel( string text, Font font )
2636                 {
2637                         SizeF newSize;
2638
2639                         // Measure string
2640                         newSize = this.MeasureString( text, font );
2641
2642                         // Convert to relative Coordinates
2643                         return GetRelativeSize( newSize );
2644                 }
2645
2646                 /// <summary>
2647                 /// Measures the specified text string when drawn with 
2648                 /// the specified Font object and formatted with the 
2649                 /// specified StringFormat object.
2650                 /// </summary>
2651                 /// <param name="text">The string to measure</param>
2652                 /// <param name="font">The Font object used to determine the size of the text string. </param>
2653                 /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
2654                 /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
2655                 /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
2656                 internal SizeF MeasureStringRel( string text, Font font, SizeF layoutArea, StringFormat stringFormat )
2657                 {
2658                         SizeF size, newSize;
2659
2660                         // Get absolute coordinates
2661                         size = GetAbsoluteSize( layoutArea );
2662
2663                         newSize = this.MeasureString( text, font, size, stringFormat );
2664
2665                         // Convert to relative Coordinates
2666                         return GetRelativeSize( newSize );
2667                 }
2668
2669                 /// <summary>
2670                 /// Measures the specified text string when drawn with 
2671                 /// the specified Font object and formatted with the 
2672                 /// specified StringFormat object.
2673                 /// </summary>
2674                 /// <param name="text">The string to measure</param>
2675                 /// <param name="font">The Font object used to determine the size of the text string. </param>
2676                 /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
2677                 internal Size MeasureStringAbs( string text, Font font )
2678                 {
2679                         // Measure string
2680                         SizeF size = this.MeasureString( text, font );
2681                         return new Size( (int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));
2682                 }
2683
2684                 /// <summary>
2685                 /// Measures the specified text string when drawn with 
2686                 /// the specified Font object and formatted with the 
2687                 /// specified StringFormat object.
2688                 /// </summary>
2689                 /// <param name="text">The string to measure</param>
2690                 /// <param name="font">The Font object used to determine the size of the text string. </param>
2691                 /// <param name="layoutArea">A SizeF structure that specifies the layout rectangle for the text. </param>
2692                 /// <param name="stringFormat">A StringFormat object that represents formatting information, such as line spacing, for the text string. </param>
2693                 /// <returns>A SizeF structure that represents the size of text as drawn with font.</returns>
2694                 internal Size MeasureStringAbs( string text, Font font, SizeF layoutArea, StringFormat stringFormat )
2695                 {
2696                         SizeF size = this.MeasureString( text, font, layoutArea, stringFormat );
2697                         return new Size( (int)Math.Ceiling(size.Width), (int)Math.Ceiling(size.Height));
2698                 }
2699
2700                 /// <summary>
2701                 /// Draws the specified text string at the specified location 
2702                 /// with the specified Brush object and font. The formatting 
2703                 /// properties in the specified StringFormat object are applied 
2704                 /// to the text.
2705                 /// </summary>
2706                 /// <param name="text">A string object that specifies the text to draw.</param>
2707                 /// <param name="font">A Font object that specifies the font face and size with which to draw the text.</param>
2708                 /// <param name="brush">A Brush object that determines the color and/or texture of the drawn text.</param>
2709                 /// <param name="layoutRectangle">A RectangleF structure that specifies the location of the drawn text.</param>
2710                 /// <param name="format">A StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
2711                 internal void DrawStringRel( string text, Font font, Brush brush,       RectangleF layoutRectangle,     StringFormat format     )
2712                 {
2713                         RectangleF rect;
2714
2715                         // Check that rectangle is not empty
2716                         if(layoutRectangle.Width == 0 || layoutRectangle.Height == 0)
2717                         {
2718                                 return;
2719                         }
2720
2721                         // Get absolute coordinates
2722                         rect = GetAbsoluteRectangle( layoutRectangle );
2723
2724                         // Draw text with anti-aliasing
2725                         /*
2726                         if( (this.AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
2727                         {
2728                                 this.TextRenderingHint = TextRenderingHint.AntiAlias;
2729                         }
2730                         else
2731                         {
2732                                 this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
2733                         }
2734                         */
2735
2736                         this.DrawString( text, font, brush, rect, format );
2737                 }
2738
2739                 
2740                 /// <summary>
2741                 /// Draws the specified text string at the specified location 
2742                 /// with the specified angle and with the specified Brush object and font. The 
2743                 /// formatting properties in the specified StringFormat object are applied 
2744                 /// to the text.
2745                 /// </summary>
2746                 /// <param name="text">A string object that specifies the text to draw.</param>
2747                 /// <param name="font">A Font object that specifies the font face and size with which to draw the text.</param>
2748                 /// <param name="brush">A Brush object that determines the color and/or texture of the drawn text.</param>
2749                 /// <param name="layoutRectangle">A RectangleF structure that specifies the location of the drawn text.</param>
2750                 /// <param name="format">A StringFormat object that specifies formatting properties, such as line spacing and alignment, that are applied to the drawn text.</param>
2751                 /// <param name="angle">A angle of the text</param>
2752                 internal void DrawStringRel( 
2753                         string text, 
2754                         Font font, 
2755                         Brush brush,    
2756                         RectangleF layoutRectangle,     
2757                         StringFormat format, 
2758                         int angle       
2759                         )
2760                 {
2761                         RectangleF rect;
2762                         SizeF size;
2763                         Matrix oldTransform;
2764                         PointF rotationCenter = PointF.Empty;
2765
2766                         // Check that rectangle is not empty
2767                         if(layoutRectangle.Width == 0 || layoutRectangle.Height == 0)
2768                         {
2769                                 return;
2770                         }
2771
2772                         // Get absolute coordinates
2773                         rect = GetAbsoluteRectangle( layoutRectangle );
2774
2775                         size = this.MeasureString( text, font, rect.Size, format );
2776
2777
2778                         // Find the center of rotation
2779                         if( format.Alignment == StringAlignment.Near )
2780                         { // Near
2781                                 rotationCenter.X = rect.X + size.Width / 2;
2782                                 rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
2783                         }
2784                         else if( format.Alignment == StringAlignment.Far )
2785                         { // Far
2786                                 rotationCenter.X = rect.Right - size.Width / 2;
2787                                 rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
2788                         }
2789                         else
2790                         { // Center
2791                                 rotationCenter.X = ( rect.Left + rect.Right ) / 2;
2792                                 rotationCenter.Y = ( rect.Bottom + rect.Top ) / 2;
2793                         }
2794                         // Create a matrix and rotate it.
2795                         _myMatrix = this.Transform.Clone();
2796                         _myMatrix.RotateAt( angle, rotationCenter);
2797
2798                         // Old angle
2799                         oldTransform = this.Transform;
2800
2801                         // Set Angle
2802                         this.Transform = _myMatrix;
2803
2804                         // Draw text with anti-aliasing
2805                         /*
2806                         if( (AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
2807                         {
2808                                 this.TextRenderingHint = TextRenderingHint.AntiAlias;
2809                         }
2810                         else
2811                         {
2812                                 this.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
2813                         }
2814                         */
2815
2816                         this.DrawString( text, font, brush, rect, format );
2817
2818                         // Set Old Angle
2819                         this.Transform = oldTransform;
2820                 }
2821
2822                 #endregion
2823
2824                 #region Rectangle Methods
2825
2826                 /// <summary>
2827                 /// Draws different shadows to create bar styles.
2828                 /// </summary>
2829                 /// <param name="barDrawingStyle">Bar drawing style.</param>
2830                 /// <param name="isVertical">True if a vertical bar.</param>
2831                 /// <param name="rect">Rectangle position.</param>
2832                 internal void DrawRectangleBarStyle(BarDrawingStyle barDrawingStyle, bool isVertical, RectangleF rect)
2833                 {
2834                         // Check if non-default bar drawing style is specified
2835                         if(barDrawingStyle != BarDrawingStyle.Default)
2836                         {
2837                                 // Check column/bar size
2838                                 if(rect.Width > 0 && rect.Height > 0)
2839                                 {
2840                                         // Draw gradient(s)
2841                                         if(barDrawingStyle == BarDrawingStyle.Cylinder)
2842                                         {
2843                                                 // Calculate gradient position
2844                                                 RectangleF gradientRect = rect;
2845                                                 if(isVertical)
2846                                                 {
2847                                                         gradientRect.Width *= 0.3f;
2848                                                 }
2849                                                 else
2850                                                 {
2851                                                         gradientRect.Height *= 0.3f;
2852                                                 }
2853                                                 if(gradientRect.Width > 0 && gradientRect.Height > 0)
2854                                                 {
2855                                                         this.FillRectangleAbs( 
2856                                                                 gradientRect, 
2857                                                                 Color.Transparent,
2858                                                                 ChartHatchStyle.None, 
2859                                                                 string.Empty, 
2860                                                                 ChartImageWrapMode.Scaled, 
2861                                                                 Color.Empty,
2862                                                                 ChartImageAlignmentStyle.Center,
2863                                                                 (isVertical) ? GradientStyle.LeftRight : GradientStyle.TopBottom, 
2864                                                                 Color.FromArgb(120, Color.White),
2865                                                                 Color.Empty, 
2866                                                                 0, 
2867                                                                 ChartDashStyle.NotSet, 
2868                                                                 PenAlignment.Inset );
2869
2870                                                 
2871                                                         if(isVertical)
2872                                                         {
2873                                                                 gradientRect.X += gradientRect.Width + 1f;
2874                                                                 gradientRect.Width = rect.Right - gradientRect.X;
2875                                                         }
2876                                                         else
2877                                                         {
2878                                                                 gradientRect.Y += gradientRect.Height + 1f;
2879                                                                 gradientRect.Height = rect.Bottom - gradientRect.Y;
2880                                                         }
2881
2882                                                         this.FillRectangleAbs( 
2883                                                                 gradientRect, 
2884                                                                 Color.FromArgb(120, Color.White),
2885                                                                 ChartHatchStyle.None, 
2886                                                                 string.Empty, 
2887                                                                 ChartImageWrapMode.Scaled, 
2888                                                                 Color.Empty,
2889                                                                 ChartImageAlignmentStyle.Center,
2890                                                                 (isVertical) ? GradientStyle.LeftRight : GradientStyle.TopBottom, 
2891                                                                 Color.FromArgb(150, Color.Black),
2892                                                                 Color.Empty, 
2893                                                                 0, 
2894                                                                 ChartDashStyle.NotSet, 
2895                                                                 PenAlignment.Inset );
2896
2897                                                 }
2898                                         }
2899                                         else if(barDrawingStyle == BarDrawingStyle.Emboss)
2900                                         {
2901                                                 // Calculate width of shadows used to create the effect
2902                                                 float shadowSize = 3f;
2903                                                 if(rect.Width < 6f || rect.Height < 6f)
2904                                                 {
2905                                                         shadowSize = 1f;
2906                                                 }
2907                                                 else if(rect.Width < 15f || rect.Height < 15f)
2908                                                 {
2909                                                         shadowSize = 2f;
2910                                                 }
2911
2912                                                 // Create and draw left/top path
2913                                                 using(GraphicsPath path = new GraphicsPath())
2914                                                 {
2915                                                         // Add shadow polygon to the path
2916                                                         PointF[] points = new PointF[] {
2917                                                                                                                            new PointF(rect.Left, rect.Bottom),
2918                                                                                                                            new PointF(rect.Left, rect.Top),
2919                                                                                                                            new PointF(rect.Right, rect.Top),
2920                                                                                                                            new PointF(rect.Right - shadowSize, rect.Top + shadowSize),
2921                                                                                                                            new PointF(rect.Left + shadowSize, rect.Top + shadowSize),
2922                                                                                                                            new PointF(rect.Left + shadowSize, rect.Bottom - shadowSize) };
2923                                                         path.AddPolygon(points);
2924
2925                                                         // Create brush
2926                                                         using(SolidBrush leftTopBrush = new SolidBrush(Color.FromArgb(100, Color.White)))
2927                                                         {
2928                                                                 // Fill shadow path on the left-bottom side of the bar
2929                                                                 this.FillPath(leftTopBrush, path);
2930                                                         }
2931                                                 }
2932
2933                                                 // Create and draw top/right path
2934                                                 using(GraphicsPath path = new GraphicsPath())
2935                                                 {
2936                                                         // Add shadow polygon to the path
2937                                                         PointF[] points = new PointF[] {
2938                                                                                                                            new PointF(rect.Right, rect.Top),
2939                                                                                                                            new PointF(rect.Right, rect.Bottom),
2940                                                                                                                            new PointF(rect.Left, rect.Bottom),
2941                                                                                                                            new PointF(rect.Left + shadowSize, rect.Bottom - shadowSize),
2942                                                                                                                            new PointF(rect.Right - shadowSize, rect.Bottom - shadowSize),
2943                                                                                                                            new PointF(rect.Right - shadowSize, rect.Top + shadowSize) };
2944                                                         path.AddPolygon(points);
2945
2946                                                         // Create brush
2947                                                         using(SolidBrush bottomRightBrush = new SolidBrush(Color.FromArgb(80, Color.Black)))
2948                                                         {
2949                                                                 // Fill shadow path on the left-bottom side of the bar
2950                                                                 this.FillPath(bottomRightBrush, path);
2951                                                         }
2952                                                 }
2953                                         }
2954                                         else if(barDrawingStyle == BarDrawingStyle.LightToDark)
2955                                         {
2956                                                 // Calculate width of shadows used to create the effect
2957                                                 float shadowSize = 4f;
2958                                                 if(rect.Width < 6f || rect.Height < 6f)
2959                                                 {
2960                                                         shadowSize = 2f;
2961                                                 }
2962                                                 else if(rect.Width < 15f || rect.Height < 15f)
2963                                                 {
2964                                                         shadowSize = 3f;
2965                                                 }
2966
2967                                                 // Calculate gradient position
2968                                                 RectangleF gradientRect = rect;
2969                                                 gradientRect.Inflate(-shadowSize, -shadowSize);
2970                                                 if(isVertical)
2971                                                 {
2972                                                         gradientRect.Height = (float)Math.Floor(gradientRect.Height / 3f);
2973                                                 }
2974                                                 else
2975                                                 {
2976                                                         gradientRect.X = gradientRect.Right - (float)Math.Floor(gradientRect.Width / 3f);
2977                                                         gradientRect.Width = (float)Math.Floor(gradientRect.Width / 3f);
2978                                                 }
2979                                                 if(gradientRect.Width > 0 && gradientRect.Height > 0)
2980                                                 {
2981                                                         this.FillRectangleAbs( 
2982                                                                 gradientRect, 
2983                                                                 (isVertical) ? Color.FromArgb(120, Color.White) : Color.Transparent, 
2984                                                                 ChartHatchStyle.None, 
2985                                                                 string.Empty, 
2986                                                                 ChartImageWrapMode.Scaled, 
2987                                                                 Color.Empty,
2988                                                                 ChartImageAlignmentStyle.Center,
2989                                                                 (isVertical) ? GradientStyle.TopBottom : GradientStyle.LeftRight, 
2990                                                                 (isVertical) ? Color.Transparent : Color.FromArgb(120, Color.White), 
2991                                                                 Color.Empty, 
2992                                                                 0, 
2993                                                                 ChartDashStyle.NotSet, 
2994                                                                 PenAlignment.Inset );
2995
2996                                                         gradientRect = rect;
2997                                                         gradientRect.Inflate(-shadowSize, -shadowSize);
2998                                                         if(isVertical)
2999                                                         {
3000                                                                 gradientRect.Y = gradientRect.Bottom - (float)Math.Floor(gradientRect.Height / 3f);
3001                                                                 gradientRect.Height = (float)Math.Floor(gradientRect.Height / 3f);
3002                                                         }
3003                                                         else
3004                                                         {
3005                                                                 gradientRect.Width = (float)Math.Floor(gradientRect.Width / 3f);
3006                                                         }
3007
3008
3009                                                         this.FillRectangleAbs( 
3010                                                                 gradientRect, 
3011                                                                 (!isVertical) ? Color.FromArgb(80, Color.Black) : Color.Transparent, 
3012                                                                 ChartHatchStyle.None, 
3013                                                                 string.Empty, 
3014                                                                 ChartImageWrapMode.Scaled, 
3015                                                                 Color.Empty,
3016                                                                 ChartImageAlignmentStyle.Center,
3017                                                                 (isVertical) ? GradientStyle.TopBottom : GradientStyle.LeftRight, 
3018                                                                 (!isVertical) ? Color.Transparent : Color.FromArgb(80, Color.Black), 
3019                                                                 Color.Empty, 
3020                                                                 0, 
3021                                                                 ChartDashStyle.NotSet, 
3022                                                                 PenAlignment.Inset );
3023
3024                                                 }
3025                                         }
3026                                         else if(barDrawingStyle == BarDrawingStyle.Wedge)
3027                                         {
3028                                                 // Calculate wedge size to fit the rectangle
3029                                                 float size = (isVertical) ? rect.Width / 2f : rect.Height / 2f;
3030                                                 if(isVertical && 2f * size > rect.Height)
3031                                                 {
3032                                                         size = rect.Height/2f;
3033                                                 }
3034                                                 if(!isVertical && 2f * size > rect.Width)
3035                                                 {
3036                                                         size = rect.Width/2f;
3037                                                 }
3038
3039                                                 // Draw left/bottom shadow
3040                                                 RectangleF gradientRect = rect;
3041                                                 using(GraphicsPath path = new GraphicsPath())
3042                                                 {
3043                                                         if(isVertical)
3044                                                         {
3045                                                                 path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size, gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size);
3046                                                                 path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size, gradientRect.Right, gradientRect.Bottom);
3047                                                                 path.AddLine(gradientRect.Right, gradientRect.Bottom, gradientRect.Right, gradientRect.Y);
3048                                                         }
3049                                                         else
3050                                                         {
3051                                                                 path.AddLine(gradientRect.X + size, gradientRect.Y + gradientRect.Height/2f, gradientRect.Right - size, gradientRect.Y + gradientRect.Height/2f);
3052                                                                 path.AddLine(gradientRect.Right - size, gradientRect.Y + gradientRect.Height/2f, gradientRect.Right, gradientRect.Bottom);
3053                                                                 path.AddLine(gradientRect.Right, gradientRect.Bottom, gradientRect.Left, gradientRect.Bottom);
3054                                                         }
3055                                                         path.CloseAllFigures();
3056
3057                                                         // Create brush and fill path
3058                                                         using(SolidBrush brush = new SolidBrush(Color.FromArgb(90, Color.Black)))
3059                                                         {
3060                                                                 this.FillPath(brush, path);
3061                                                         }
3062                                                 }
3063
3064                                                 // Draw top/right triangle
3065                                                 using(GraphicsPath path = new GraphicsPath())
3066                                                 {
3067                                                         if(isVertical)
3068                                                         {
3069                                                                 path.AddLine(gradientRect.X, gradientRect.Y, gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size);
3070                                                                 path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Y + size, gradientRect.Right, gradientRect.Y);
3071                                                         }
3072                                                         else
3073                                                         {
3074                                                                 path.AddLine(gradientRect.Right, gradientRect.Y, gradientRect.Right - size, gradientRect.Y + gradientRect.Height / 2f);
3075                                                                 path.AddLine(gradientRect.Right - size, gradientRect.Y + gradientRect.Height / 2f, gradientRect.Right, gradientRect.Bottom);
3076                                                         }
3077
3078                                                         // Create brush and fill path
3079                                                         using(SolidBrush brush = new SolidBrush(Color.FromArgb(50, Color.Black)))
3080                                                         {
3081                                                                 // Fill shadow path on the left-bottom side of the bar
3082                                                                 this.FillPath(brush, path);
3083
3084                                                                 // Draw Lines
3085                                                                 using(Pen penDark = new Pen(Color.FromArgb(20, Color.Black), 1))
3086                                                                 {
3087                                                                         this.DrawPath(penDark, path);
3088                                                                         if(isVertical)
3089                                                                         {
3090                                                                                 this.DrawLine(
3091                                                                                         penDark, 
3092                                                                                         rect.X + rect.Width/2f, 
3093                                                                                         rect.Y + size,
3094                                                                                         rect.X + rect.Width/2f, 
3095                                                                                         rect.Bottom - size);
3096                                                                         }
3097                                                                         else
3098                                                                         {
3099                                                                                 this.DrawLine(
3100                                                                                         penDark, 
3101                                                                                         rect.X + size, 
3102                                                                                         rect.Y + rect.Height/2f,
3103                                                                                         rect.X + size, 
3104                                                                                         rect.Bottom - rect.Height/2f);
3105                                                                         }
3106                                                                 }
3107
3108                                                                 // Draw Lines
3109                                                                 using(Pen pen = new Pen(Color.FromArgb(40, Color.White), 1))
3110                                                                 {
3111                                                                         this.DrawPath(pen, path);
3112                                                                         if(isVertical)
3113                                                                         {
3114                                                                                 this.DrawLine(
3115                                                                                         pen, 
3116                                                                                         rect.X + rect.Width/2f, 
3117                                                                                         rect.Y + size,
3118                                                                                         rect.X + rect.Width/2f, 
3119                                                                                         rect.Bottom - size);
3120                                                                         }
3121                                                                         else
3122                                                                         {
3123                                                                                 this.DrawLine(
3124                                                                                         pen, 
3125                                                                                         rect.X + size, 
3126                                                                                         rect.Y + rect.Height/2f,
3127                                                                                         rect.X + size, 
3128                                                                                         rect.Bottom - rect.Height/2f);
3129                                                                         }
3130                                                                 }
3131                                                         }
3132                                                 }
3133
3134                                                 // Draw bottom/left triangle
3135                                                 using(GraphicsPath path = new GraphicsPath())
3136                                                 {
3137                                                         if(isVertical)
3138                                                         {
3139                                                                 path.AddLine(gradientRect.X, gradientRect.Bottom, gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size);
3140                                                                 path.AddLine(gradientRect.X + gradientRect.Width/2f, gradientRect.Bottom - size, gradientRect.Right, gradientRect.Bottom);
3141                                                         }
3142                                                         else
3143                                                         {
3144                                                                 path.AddLine(gradientRect.X, gradientRect.Y, gradientRect.X + size, gradientRect.Y + gradientRect.Height / 2f);
3145                                                                 path.AddLine(gradientRect.X + size, gradientRect.Y + gradientRect.Height / 2f, gradientRect.X, gradientRect.Bottom);
3146                                                         }
3147
3148                                                         // Create brush
3149                                                         using(SolidBrush brush = new SolidBrush(Color.FromArgb(50, Color.Black)))
3150                                                         {
3151                                                                 // Fill shadow path on the left-bottom side of the bar
3152                                                                 this.FillPath(brush, path);
3153
3154                                                                 // Draw edges
3155                                                                 using(Pen penDark = new Pen(Color.FromArgb(20, Color.Black), 1))
3156                                                                 {
3157                                                                         this.DrawPath(penDark, path);
3158                                                                 }
3159                                                                 using(Pen pen = new Pen(Color.FromArgb(40, Color.White), 1))
3160                                                                 {
3161                                                                         this.DrawPath(pen, path);
3162                                                                 }
3163                                                         }
3164                                                 }
3165                                         }
3166                                 }
3167                         }
3168                 }
3169
3170                 /// <summary>
3171                 /// Draw a bar with shadow.
3172                 /// </summary>
3173                 /// <param name="rectF">Size of rectangle</param>
3174                 /// <param name="backColor">Color of rectangle</param>
3175                 /// <param name="backHatchStyle">Hatch style</param>
3176                 /// <param name="backImage">Back Image</param>
3177                 /// <param name="backImageWrapMode">Image mode</param>
3178                 /// <param name="backImageTransparentColor">Image transparent color.</param>
3179         /// <param name="backImageAlign">Image alignment</param>
3180                 /// <param name="backGradientStyle">Gradient type </param>
3181                 /// <param name="backSecondaryColor">Gradient End Color</param>
3182                 /// <param name="borderColor">Border Color</param>
3183                 /// <param name="borderWidth">Border Width</param>
3184                 /// <param name="borderDashStyle">Border Style</param>
3185                 /// <param name="shadowColor">Shadow Color</param>
3186                 /// <param name="shadowOffset">Shadow Offset</param>
3187                 /// <param name="penAlignment">Pen Alignment</param>
3188                 /// <param name="barDrawingStyle">Bar drawing style.</param>
3189                 /// <param name="isVertical">True if a vertical bar.</param>
3190                 internal void FillRectangleRel( RectangleF rectF, 
3191                         Color backColor, 
3192                         ChartHatchStyle backHatchStyle, 
3193                         string backImage, 
3194                         ChartImageWrapMode backImageWrapMode, 
3195                         Color backImageTransparentColor,
3196                         ChartImageAlignmentStyle backImageAlign,
3197                         GradientStyle backGradientStyle, 
3198                         Color backSecondaryColor, 
3199                         Color borderColor, 
3200                         int borderWidth, 
3201                         ChartDashStyle borderDashStyle, 
3202                         Color shadowColor, 
3203                         int shadowOffset,
3204                         PenAlignment penAlignment,
3205                         BarDrawingStyle barDrawingStyle,
3206                         bool isVertical)
3207                 {
3208                         this.FillRectangleRel( 
3209                                 rectF, 
3210                                 backColor, 
3211                                 backHatchStyle, 
3212                                 backImage, 
3213                                 backImageWrapMode, 
3214                                 backImageTransparentColor,
3215                                 backImageAlign,
3216                                 backGradientStyle, 
3217                                 backSecondaryColor, 
3218                                 borderColor, 
3219                                 borderWidth, 
3220                                 borderDashStyle, 
3221                                 shadowColor, 
3222                                 shadowOffset,
3223                                 penAlignment,
3224                                 false,
3225                                 0,
3226                                 false,
3227                                 barDrawingStyle,
3228                                 isVertical);
3229                 }
3230
3231                 /// <summary>
3232                 /// Draw a bar with shadow.
3233                 /// </summary>
3234                 /// <param name="rectF">Size of rectangle</param>
3235                 /// <param name="backColor">Color of rectangle</param>
3236                 /// <param name="backHatchStyle">Hatch style</param>
3237                 /// <param name="backImage">Back Image</param>
3238                 /// <param name="backImageWrapMode">Image mode</param>
3239                 /// <param name="backImageTransparentColor">Image transparent color.</param>
3240         /// <param name="backImageAlign">Image alignment</param>
3241                 /// <param name="backGradientStyle">Gradient type </param>
3242                 /// <param name="backSecondaryColor">Gradient End Color</param>
3243                 /// <param name="borderColor">Border Color</param>
3244                 /// <param name="borderWidth">Border Width</param>
3245                 /// <param name="borderDashStyle">Border Style</param>
3246                 /// <param name="shadowColor">Shadow Color</param>
3247                 /// <param name="shadowOffset">Shadow Offset</param>
3248                 /// <param name="penAlignment">Pen Alignment</param>
3249                 internal void FillRectangleRel( RectangleF rectF, 
3250                         Color backColor, 
3251                         ChartHatchStyle backHatchStyle, 
3252                         string backImage, 
3253                         ChartImageWrapMode backImageWrapMode, 
3254                         Color backImageTransparentColor,
3255                         ChartImageAlignmentStyle backImageAlign,
3256                         GradientStyle backGradientStyle, 
3257                         Color backSecondaryColor, 
3258                         Color borderColor, 
3259                         int borderWidth, 
3260                         ChartDashStyle borderDashStyle, 
3261                         Color shadowColor, 
3262                         int shadowOffset,
3263                         PenAlignment penAlignment )
3264                 {
3265                         this.FillRectangleRel( 
3266                                 rectF, 
3267                                 backColor, 
3268                                 backHatchStyle, 
3269                                 backImage, 
3270                                 backImageWrapMode, 
3271                                 backImageTransparentColor,
3272                                 backImageAlign,
3273                                 backGradientStyle, 
3274                                 backSecondaryColor, 
3275                                 borderColor, 
3276                                 borderWidth, 
3277                                 borderDashStyle, 
3278                                 shadowColor, 
3279                                 shadowOffset,
3280                                 penAlignment,
3281                                 false,
3282                                 0,
3283                                 false,
3284                                 BarDrawingStyle.Default,
3285                                 true);
3286                 }
3287
3288                 /// <summary>
3289                 /// Draws rectangle or circle (inside rectangle) with shadow.
3290                 /// </summary>
3291                 /// <param name="rectF">Size of rectangle</param>
3292                 /// <param name="backColor">Color of rectangle</param>
3293                 /// <param name="backHatchStyle">Hatch style</param>
3294                 /// <param name="backImage">Back Image</param>
3295                 /// <param name="backImageWrapMode">Image mode</param>
3296                 /// <param name="backImageTransparentColor">Image transparent color.</param>
3297         /// <param name="backImageAlign">Image alignment</param>
3298                 /// <param name="backGradientStyle">Gradient type </param>
3299                 /// <param name="backSecondaryColor">Gradient End Color</param>
3300                 /// <param name="borderColor">Border Color</param>
3301                 /// <param name="borderWidth">Border Width</param>
3302                 /// <param name="borderDashStyle">Border Style</param>
3303                 /// <param name="shadowColor">Shadow Color</param>
3304                 /// <param name="shadowOffset">Shadow Offset</param>
3305                 /// <param name="penAlignment">Pen Alignment</param>
3306                 /// <param name="circular">Draw circular shape inside the rectangle.</param>
3307                 /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
3308                 /// <param name="circle3D">3D Circle must be drawn.</param>
3309                 internal void FillRectangleRel( RectangleF rectF, 
3310                         Color backColor, 
3311                         ChartHatchStyle backHatchStyle, 
3312                         string backImage, 
3313                         ChartImageWrapMode backImageWrapMode, 
3314                         Color backImageTransparentColor,
3315                         ChartImageAlignmentStyle backImageAlign,
3316                         GradientStyle backGradientStyle, 
3317                         Color backSecondaryColor, 
3318                         Color borderColor, 
3319                         int borderWidth, 
3320                         ChartDashStyle borderDashStyle, 
3321                         Color shadowColor, 
3322                         int shadowOffset,
3323                         PenAlignment penAlignment,
3324                         bool circular,
3325                         int     circularSectorsCount,
3326                         bool circle3D)
3327                 {
3328                         this.FillRectangleRel( 
3329                                 rectF, 
3330                                 backColor, 
3331                                 backHatchStyle, 
3332                                 backImage, 
3333                                 backImageWrapMode, 
3334                                 backImageTransparentColor,
3335                                 backImageAlign,
3336                                 backGradientStyle, 
3337                                 backSecondaryColor, 
3338                                 borderColor, 
3339                                 borderWidth, 
3340                                 borderDashStyle, 
3341                                 shadowColor, 
3342                                 shadowOffset,
3343                                 penAlignment,
3344                 circular,
3345                 circularSectorsCount,
3346                 circle3D,
3347                                 BarDrawingStyle.Default,
3348                                 true);
3349                 }
3350
3351                 
3352                 /// <summary>
3353                 /// Draws rectangle or circle (inside rectangle) with shadow.
3354                 /// </summary>
3355                 /// <param name="rectF">Size of rectangle</param>
3356                 /// <param name="backColor">Color of rectangle</param>
3357                 /// <param name="backHatchStyle">Hatch style</param>
3358                 /// <param name="backImage">Back Image</param>
3359                 /// <param name="backImageWrapMode">Image mode</param>
3360                 /// <param name="backImageTransparentColor">Image transparent color.</param>
3361         /// <param name="backImageAlign">Image alignment</param>
3362                 /// <param name="backGradientStyle">Gradient type </param>
3363                 /// <param name="backSecondaryColor">Gradient End Color</param>
3364                 /// <param name="borderColor">Border Color</param>
3365                 /// <param name="borderWidth">Border Width</param>
3366                 /// <param name="borderDashStyle">Border Style</param>
3367                 /// <param name="shadowColor">Shadow Color</param>
3368                 /// <param name="shadowOffset">Shadow Offset</param>
3369                 /// <param name="penAlignment">Pen Alignment</param>
3370                 /// <param name="circular">Draw circular shape inside the rectangle.</param>
3371                 /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
3372                 /// <param name="circle3D">3D Circle must be drawn.</param>
3373                 /// <param name="barDrawingStyle">Bar drawing style.</param>
3374                 /// <param name="isVertical">True if a vertical bar.</param>
3375                 internal void FillRectangleRel( RectangleF rectF, 
3376                         Color backColor, 
3377                         ChartHatchStyle backHatchStyle, 
3378                         string backImage, 
3379                         ChartImageWrapMode backImageWrapMode, 
3380                         Color backImageTransparentColor,
3381                         ChartImageAlignmentStyle backImageAlign,
3382                         GradientStyle backGradientStyle, 
3383                         Color backSecondaryColor, 
3384                         Color borderColor, 
3385                         int borderWidth, 
3386                         ChartDashStyle borderDashStyle, 
3387                         Color shadowColor, 
3388                         int shadowOffset,
3389                         PenAlignment penAlignment,
3390                         bool circular,
3391                         int     circularSectorsCount,
3392                         bool circle3D,
3393                         BarDrawingStyle barDrawingStyle,
3394                         bool isVertical)
3395                 {
3396                         Brush brush = null;
3397                         Brush backBrush = null;
3398
3399                         // Remember SmoothingMode and turn off anti aliasing
3400                         SmoothingMode oldSmoothingMode = this.SmoothingMode;
3401                         if(!circular)
3402                         {
3403                                 this.SmoothingMode = SmoothingMode.Default;
3404                         }
3405
3406                         // Color is empty
3407                         if( backColor.IsEmpty ) 
3408                         {
3409                                 backColor = Color.White;
3410                         }
3411
3412                         if( backSecondaryColor.IsEmpty ) 
3413                         {
3414                                 backSecondaryColor = Color.White;
3415                         }
3416
3417                         if( borderColor.IsEmpty || borderDashStyle == ChartDashStyle.NotSet) 
3418                         {
3419                                 borderWidth = 0;
3420                         }
3421                 
3422                         // Get absolute coordinates
3423                         RectangleF rect = GetAbsoluteRectangle( rectF );
3424                         
3425                         // Rectangle width and height can not be very small value
3426                         if( rect.Width < 1.0F && rect.Width > 0.0F )
3427                         {
3428                                 rect.Width = 1.0F;
3429                         }
3430
3431                         if( rect.Height < 1.0F && rect.Height > 0.0F )
3432                         {
3433                                 rect.Height = 1.0F;
3434                         }
3435
3436                         // Round the values
3437                         rect = Round( rect );
3438
3439                         // For inset alignment resize fill rectangle
3440                         RectangleF fillRect;
3441                         if( penAlignment == PenAlignment.Inset  &&
3442                                 borderWidth > 0)
3443                         {
3444                                 // SVG and Metafiles do not support inset pen styles - use same rectangle
3445                                 if( this.ActiveRenderingType == RenderingType.Svg ||
3446                                         this.IsMetafile)
3447                                 {
3448                                         fillRect = new RectangleF( rect.X, rect.Y, rect.Width, rect.Height);
3449                                 }
3450                 else if (this.Graphics.Transform.Elements[0] != 1f ||
3451                     this.Graphics.Transform.Elements[3] != 1f)
3452                 {
3453                     // Do not reduce filling rectangle if scaling is used in the graphics
3454                     // transformations. Rounding may cause a 1 pixel gap between the border 
3455                     // and the filling.
3456                     fillRect = new RectangleF( rect.X, rect.Y, rect.Width, rect.Height);
3457                 }
3458                                 else
3459                                 {
3460                                         // The fill rectangle is resized because of border size.
3461                                         fillRect = new RectangleF( 
3462                                                 rect.X + borderWidth, 
3463                                                 rect.Y + borderWidth, 
3464                                                 rect.Width - borderWidth * 2f + 1, 
3465                                                 rect.Height - borderWidth * 2f + 1);
3466                                 }
3467                         }
3468                         else
3469                         {
3470                                 // The fill rectangle is same
3471                                 fillRect = rect;
3472                         }
3473
3474                         // Fix for issue #6714:
3475                         // Make sure the rectangle coordinates fit the control. In same cases rectangle width or
3476                         // hight ca be extremly large. Drawing such a rectangle may cause an overflow exception. 
3477                         // The code below restricts the maximum size to double the chart size. See issue 
3478                         // description for more information. -AG.
3479                         if(fillRect.Width > 2f * this._width)
3480                         {
3481                                 fillRect.Width = 2f * this._width;
3482                         }
3483                         if(fillRect.Height > 2f * this._height)
3484                         {
3485                                 fillRect.Height = 2f * this._height;
3486                         }
3487
3488
3489                         if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
3490                         {
3491                                 backBrush = brush;
3492                                 brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor);
3493                         }
3494                         else if( backHatchStyle != ChartHatchStyle.None )
3495                         {
3496                                 brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
3497                         }
3498                         else if( backGradientStyle != GradientStyle.None )
3499                         {
3500                                 // If a gradient type  is set create a brush with gradient
3501                                 brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
3502                         }
3503                         else
3504                         {
3505                                 // Set a bar color.
3506                                 if(backColor == Color.Empty || backColor == Color.Transparent)
3507                                 {
3508                                         brush = null;
3509                                 }
3510                                 else
3511                                 {
3512                                         brush = new SolidBrush(backColor);
3513                                 }
3514                         }
3515
3516                         // Draw shadow
3517                         FillRectangleShadowAbs( rect, shadowColor, shadowOffset, backColor, circular, circularSectorsCount );
3518
3519                         // Draw rectangle image
3520                         if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
3521                         {
3522                                 // Load image
3523                 System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
3524
3525                                 // Prepare image properties (transparent color)
3526                                 ImageAttributes attrib = new ImageAttributes();
3527                                 if(backImageTransparentColor != Color.Empty)
3528                                 {
3529                                         attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
3530                                 }
3531
3532                                 // Draw scaled image
3533                                 RectangleF imageRect = new RectangleF();
3534                                 imageRect.X = fillRect.X;
3535                                 imageRect.Y = fillRect.Y;
3536                                 imageRect.Width = fillRect.Width;
3537                                 imageRect.Height = fillRect.Height;
3538
3539                 SizeF imageAbsSize = new SizeF();
3540
3541                                 // Calculate unscaled image position
3542                                 if(backImageWrapMode == ChartImageWrapMode.Unscaled)
3543                                 {
3544                     ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageAbsSize);
3545
3546                     // Calculate image position
3547                     imageRect.Width = Math.Min(fillRect.Width, imageAbsSize.Width);
3548                     imageRect.Height = Math.Min(fillRect.Height, imageAbsSize.Height);
3549
3550                         // Adjust position with alignment property
3551                                         if(imageRect.Width < fillRect.Width)
3552                                         {
3553                                                 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
3554                                                         backImageAlign == ChartImageAlignmentStyle.Right ||
3555                                                         backImageAlign == ChartImageAlignmentStyle.TopRight)
3556                                                 {
3557                                                         imageRect.X = fillRect.Right - imageRect.Width;
3558                                                 }
3559                                                 else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
3560                                                         backImageAlign == ChartImageAlignmentStyle.Center ||
3561                                                         backImageAlign == ChartImageAlignmentStyle.Top)
3562                                                 {
3563                                                         imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
3564                                                 }
3565                                         }
3566                                         if(imageRect.Height < fillRect.Height)
3567                                         {
3568                                                 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
3569                                                         backImageAlign == ChartImageAlignmentStyle.Bottom ||
3570                                                         backImageAlign == ChartImageAlignmentStyle.BottomLeft)
3571                                                 {
3572                                                         imageRect.Y = fillRect.Bottom - imageRect.Height;
3573                                                 }
3574                                                 else if(backImageAlign == ChartImageAlignmentStyle.Left ||
3575                                                         backImageAlign == ChartImageAlignmentStyle.Center ||
3576                                                         backImageAlign == ChartImageAlignmentStyle.Right)
3577                                                 {
3578                                                         imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
3579                                                 }
3580                                         }
3581
3582                                 }
3583
3584                                 // Fill background with brush
3585                                 if(brush != null)
3586                                 {
3587                                         if(circular)
3588                                                 this.DrawCircleAbs( null, brush, fillRect, circularSectorsCount, circle3D );
3589                                         else
3590                                                 this.FillRectangle( brush, fillRect );
3591                                 }
3592                  
3593                 // Draw image
3594                                 this.DrawImage(image, 
3595                                         new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
3596                                         0, 0,
3597                     (backImageWrapMode == ChartImageWrapMode.Unscaled) ? imageRect.Width * image.Width / imageAbsSize.Width : image.Width,
3598                     (backImageWrapMode == ChartImageWrapMode.Unscaled) ? imageRect.Height * image.Height / imageAbsSize.Height : image.Height,
3599                                         GraphicsUnit.Pixel, 
3600                                         attrib);
3601                         }
3602                                 // Draw rectangle
3603                         else
3604                         {
3605                                 if(backBrush != null && backImageTransparentColor != Color.Empty)
3606                                 {
3607                                         // Fill background with brush
3608                                         if(circular)
3609                                                 this.DrawCircleAbs( null, backBrush, fillRect, circularSectorsCount, circle3D );
3610                                         else
3611                                                 this.FillRectangle( backBrush, fillRect );
3612                                 }
3613
3614                                 if(brush != null)
3615                                 {
3616                                         if(circular)
3617                                                 this.DrawCircleAbs( null, brush, fillRect, circularSectorsCount, circle3D );
3618                                         else
3619                                                 this.FillRectangle( brush, fillRect );
3620                                 }
3621                         }
3622
3623                         // Draw different bar style
3624                         this.DrawRectangleBarStyle(barDrawingStyle, isVertical, fillRect);
3625
3626                         // Draw border
3627                         if( borderWidth > 0 && borderDashStyle != ChartDashStyle.NotSet)
3628                         {
3629                                 // Set a border line color
3630                                 if(_pen.Color != borderColor)
3631                                 {
3632                                         _pen.Color = borderColor;
3633                                 }
3634                         
3635                                 // Set a border line width
3636                                 if(_pen.Width != borderWidth)
3637                                 {
3638                                         _pen.Width = borderWidth;
3639                                 }
3640
3641                                 // Set pen alignment
3642                                 if(_pen.Alignment != penAlignment)
3643                                 {
3644                                         _pen.Alignment = penAlignment;
3645                                 }
3646
3647                                 // Set a border line style
3648                                 if(_pen.DashStyle != GetPenStyle( borderDashStyle ))
3649                                 {
3650                                         _pen.DashStyle = GetPenStyle( borderDashStyle );
3651                                 }
3652
3653                                 // Draw border
3654                                 if(circular)
3655                                 {
3656                                         this.DrawCircleAbs( _pen, null, rect, circularSectorsCount, false );
3657                                 }
3658                                 else
3659                                 {
3660                                         // NOTE: Rectangle with single pixel inset border is drawn 1 pixel larger 
3661                                         // in the .Net Framework. Increase size by 1 pixel to solve the issue.
3662                                         if(_pen.Alignment == PenAlignment.Inset && _pen.Width > 1f)
3663                                         {
3664                                                 rect.Width += 1;
3665                                                 rect.Height += 1;
3666                                         }
3667
3668                                         // Draw rectangle
3669                                         this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width, rect.Height );
3670                                 }
3671                         }
3672
3673                         // Dispose Image and Gradient
3674                         if(brush != null)
3675                         {
3676                                 brush.Dispose();
3677                         }
3678
3679                         // Return old smoothing mode
3680                         this.SmoothingMode = oldSmoothingMode;
3681                 }
3682
3683                 /// <summary>
3684                 /// Draw Shadow for a bar
3685                 /// </summary>
3686                 /// <param name="rect">Bar rectangle</param>
3687                 /// <param name="shadowColor">Shadow Color</param>
3688                 /// <param name="shadowOffset">Shadow Offset</param>
3689                 /// <param name="backColor">Back Color</param>
3690         internal void FillRectangleShadowAbs( 
3691                         RectangleF rect, 
3692                         Color shadowColor, 
3693                         float shadowOffset, 
3694                         Color backColor)
3695                 {
3696                         FillRectangleShadowAbs( 
3697                                 rect, 
3698                                 shadowColor, 
3699                                 shadowOffset, 
3700                                 backColor,
3701                                 false,
3702                                 0);
3703                 }
3704
3705         /// <summary>
3706         /// Draw Shadow for a bar
3707         /// </summary>
3708         /// <param name="rect">Bar rectangle</param>
3709         /// <param name="shadowColor">Shadow Color</param>
3710         /// <param name="shadowOffset">Shadow Offset</param>
3711         /// <param name="backColor">Back Color</param>
3712         /// <param name="circular">Draw circular shape inside the rectangle.</param>
3713         /// <param name="circularSectorsCount">Number of sectors in circle when drawing the polygon.</param>
3714                 internal void FillRectangleShadowAbs( 
3715                         RectangleF rect, 
3716                         Color shadowColor, 
3717                         float shadowOffset, 
3718                         Color backColor,
3719                         bool circular,
3720                         int     circularSectorsCount)
3721                 {
3722                         // Do not draw shadoe for empty rectangle
3723                         if(rect.Height == 0 || rect.Width == 0 || shadowOffset == 0)
3724                         {
3725                                 return;
3726                         }
3727
3728             // Do not draw  shadow if color is IsEmpty or offset is 0
3729             if (shadowOffset == 0 || shadowColor == Color.Empty)
3730             {
3731                 return;
3732             }
3733
3734             // For non-circualr shadow with transparent background - use clipping
3735             bool clippingUsed = false;
3736             Region oldClipRegion = null;
3737             if (!circular && backColor == Color.Transparent)
3738             {
3739                 clippingUsed = true;
3740                 oldClipRegion = this.Clip;
3741                 Region region = new Region();
3742                 region.MakeInfinite();
3743                 region.Xor(rect);
3744                 this.Clip = region;
3745             }
3746             
3747                         // Draw usual or "soft" shadows
3748                         if(!softShadows || circularSectorsCount > 2)
3749                         {
3750                                 RectangleF absolute;
3751                                 RectangleF offset = RectangleF.Empty;
3752
3753                                 absolute = Round( rect );
3754
3755                                 // Change shadow color
3756                 using (SolidBrush shadowBrush = new SolidBrush((shadowColor.A != 255) ? shadowColor : Color.FromArgb(backColor.A / 2, shadowColor)))
3757                 {
3758                     // Shadow Position
3759                     offset.X = absolute.X + shadowOffset;
3760                     offset.Y = absolute.Y + shadowOffset;
3761                     offset.Width = absolute.Width;
3762                     offset.Height = absolute.Height;
3763
3764                     // Draw rectangle
3765                     if (circular)
3766                         this.DrawCircleAbs(null, shadowBrush, offset, circularSectorsCount, false);
3767                     else
3768                         this.FillRectangle(shadowBrush, offset);
3769                 }
3770                         }
3771                         else
3772                         {
3773
3774                                 RectangleF absolute;
3775                                 RectangleF offset = RectangleF.Empty;
3776
3777                                 absolute = Round( rect );
3778                                 
3779
3780                                 // Shadow Position
3781                                 offset.X = absolute.X + shadowOffset - 1;
3782                                 offset.Y = absolute.Y + shadowOffset - 1;
3783                                 offset.Width = absolute.Width + 2;
3784                                 offset.Height = absolute.Height + 2;
3785                                 
3786                                 // Calculate rounded rect radius
3787                                 float   radius = shadowOffset * 0.7f;
3788                                 radius = (float)Math.Max(radius, 2f);
3789                                 radius = (float)Math.Min(radius, offset.Width/4f);
3790                                 radius = (float)Math.Min(radius, offset.Height/4f);
3791                                 radius = (float)Math.Ceiling(radius);
3792                                 if(circular)
3793                                 {
3794                                         radius = offset.Width/2f;
3795                                 }
3796
3797                                 // Create rounded rectangle path
3798                                 GraphicsPath path = new GraphicsPath();
3799                                 if(circular && offset.Width != offset.Height)
3800                                 {
3801                                         float   radiusX = offset.Width/2f;
3802                                         float   radiusY = offset.Height/2f;
3803                                         path.AddLine(offset.X+radiusX, offset.Y, offset.Right-radiusX, offset.Y);
3804                                         path.AddArc(offset.Right-2f*radiusX, offset.Y, 2f*radiusX, 2f*radiusY, 270, 90);
3805                                         path.AddLine(offset.Right, offset.Y + radiusY, offset.Right, offset.Bottom - radiusY);
3806                                         path.AddArc(offset.Right-2f*radiusX, offset.Bottom-2f*radiusY, 2f*radiusX, 2f*radiusY, 0, 90);
3807                                         path.AddLine(offset.Right-radiusX, offset.Bottom, offset.X + radiusX, offset.Bottom);
3808                                         path.AddArc(offset.X, offset.Bottom-2f*radiusY, 2f*radiusX, 2f*radiusY, 90, 90);
3809                                         path.AddLine(offset.X, offset.Bottom-radiusY, offset.X, offset.Y+radiusY);
3810                                         path.AddArc(offset.X, offset.Y, 2f*radiusX, 2f*radiusY, 180, 90);
3811                                 }
3812                                 else
3813                                 {
3814                                         path.AddLine(offset.X+radius, offset.Y, offset.Right-radius, offset.Y);
3815                                         path.AddArc(offset.Right-2f*radius, offset.Y, 2f*radius, 2f*radius, 270, 90);
3816                                         path.AddLine(offset.Right, offset.Y + radius, offset.Right, offset.Bottom - radius);
3817                                         path.AddArc(offset.Right-2f*radius, offset.Bottom-2f*radius, 2f*radius, 2f*radius, 0, 90);
3818                                         path.AddLine(offset.Right-radius, offset.Bottom, offset.X + radius, offset.Bottom);
3819                                         path.AddArc(offset.X, offset.Bottom-2f*radius, 2f*radius, 2f*radius, 90, 90);
3820                                         path.AddLine(offset.X, offset.Bottom-radius, offset.X, offset.Y+radius);
3821                                         path.AddArc(offset.X, offset.Y, 2f*radius, 2f*radius, 180, 90);
3822                                 }
3823
3824                                 PathGradientBrush shadowBrush = new PathGradientBrush(path);
3825                                 shadowBrush.CenterColor = shadowColor;
3826
3827                                 // Set the color along the entire boundary of the path
3828                                 Color[] colors = {Color.Transparent};
3829                                 shadowBrush.SurroundColors = colors;
3830                                 shadowBrush.CenterPoint = new PointF(offset.X + offset.Width/2f, offset.Y + offset.Height/2f);
3831
3832                                 // Define brush focus scale
3833                                 PointF focusScale = new PointF(1-2f*shadowOffset/offset.Width, 1-2f*shadowOffset/offset.Height);
3834                                 if(focusScale.X < 0)
3835                                         focusScale.X = 0;
3836                                 if(focusScale.Y < 0)
3837                                         focusScale.Y = 0;
3838                                 shadowBrush.FocusScales = focusScale;
3839
3840                 // Draw rectangle
3841                                 this.FillPath(shadowBrush, path);
3842                         }
3843
3844             // Reset clip region
3845             if (clippingUsed)
3846             {
3847                 Region region = this.Clip;
3848                 this.Clip = oldClipRegion;
3849                 region.Dispose();
3850             }
3851                 }
3852
3853                 /// <summary>
3854                 /// Gets the path of the polygon which represent the circular area.
3855                 /// </summary>
3856                 /// <param name="position">Circle position.</param>
3857                 /// <param name="polygonSectorsNumber">Number of sectors for the polygon.</param>
3858                 /// <returns>Graphics path of the polygon circle.</returns>
3859                 internal GraphicsPath GetPolygonCirclePath(RectangleF position, int polygonSectorsNumber)
3860                 {
3861                         PointF                  firstPoint = new PointF(position.X + position.Width/2f, position.Y);
3862                         PointF                  centerPoint = new PointF(position.X + position.Width/2f, position.Y + position.Height/2f);
3863                         float                   sectorSize = 0f;
3864                         GraphicsPath    path = new GraphicsPath();
3865                         PointF                  prevPoint = PointF.Empty;
3866                         float                   curentSector = 0f;
3867
3868                         // Get sector size
3869                         if(polygonSectorsNumber <= 2)
3870                         {
3871                                 // Circle sector size
3872                                 sectorSize = 1f;
3873                         }
3874                         else
3875                         {
3876                                 // Polygon sector size
3877                                 sectorSize = 360f / ((float)polygonSectorsNumber);
3878                         }
3879
3880                         // Loop throug all sectors
3881                         for(curentSector = 0f; curentSector < 360f; curentSector += sectorSize)
3882                         {
3883                                 // Create matrix
3884                                 Matrix matrix = new Matrix();
3885                                 matrix.RotateAt(curentSector, centerPoint);
3886
3887                                 // Get point and rotate it
3888                                 PointF[]        points = new PointF[] { firstPoint };
3889                                 matrix.TransformPoints(points);
3890
3891                                 // Add point into the path
3892                                 if(!prevPoint.IsEmpty)
3893                                 {
3894                                         path.AddLine(prevPoint, points[0]);
3895                                 }
3896
3897                                 // Remember last point
3898                                 prevPoint = points[0];
3899                         }
3900
3901                         path.CloseAllFigures();
3902
3903                         return path;
3904                 }
3905
3906                 /// <summary>
3907                 /// Fills and/or draws border as circle or polygon.
3908                 /// </summary>
3909                 /// <param name="pen">Border pen.</param>
3910                 /// <param name="brush">Border brush.</param>
3911                 /// <param name="position">Circle position.</param>
3912                 /// <param name="polygonSectorsNumber">Number of sectors for the polygon.</param>
3913                 /// <param name="circle3D">Indicates that circle should be 3D..</param>
3914                 internal void DrawCircleAbs(Pen pen, Brush brush, RectangleF position, int polygonSectorsNumber, bool circle3D)
3915                 {
3916                         bool    fill3DCircle = (circle3D && brush != null);
3917
3918                         // Draw 2D circle
3919                         if(polygonSectorsNumber <= 2 && !fill3DCircle)
3920                         {
3921                                 if(brush != null)
3922                                 {
3923                                         this.FillEllipse(brush, position);
3924                                 }
3925                                 if(pen != null)
3926                                 {
3927                                         this.DrawEllipse(pen, position);
3928                                 }
3929                         }
3930
3931                                 // Draw circle as polygon with specified number of sectors
3932                         else
3933                         {
3934                                 PointF                  firstPoint = new PointF(position.X + position.Width/2f, position.Y);
3935                                 PointF                  centerPoint = new PointF(position.X + position.Width/2f, position.Y + position.Height/2f);
3936                                 float                   sectorSize = 0f;
3937                                 PointF                  prevPoint = PointF.Empty;
3938                                 float                   curentSector = 0f;
3939
3940                 using (GraphicsPath path = new GraphicsPath())
3941                 {
3942                     // Remember current smoothing mode
3943                     SmoothingMode oldMode = this.SmoothingMode;
3944                     if (fill3DCircle)
3945                     {
3946                         this.SmoothingMode = SmoothingMode.None;
3947                     }
3948
3949                     // Get sector size
3950                     if (polygonSectorsNumber <= 2)
3951                     {
3952                         // Circle sector size
3953                         sectorSize = 1f;
3954                     }
3955                     else
3956                     {
3957                         // Polygon sector size
3958                         sectorSize = 360f / ((float)polygonSectorsNumber);
3959                     }
3960
3961                     // Loop throug all sectors
3962                     for (curentSector = 0f; curentSector < 360f; curentSector += sectorSize)
3963                     {
3964                         // Create matrix
3965                         Matrix matrix = new Matrix();
3966                         matrix.RotateAt(curentSector, centerPoint);
3967
3968                         // Get point and rotate it
3969                         PointF[] points = new PointF[] { firstPoint };
3970                         matrix.TransformPoints(points);
3971
3972                         // Add point into the path
3973                         if (!prevPoint.IsEmpty)
3974                         {
3975                             path.AddLine(prevPoint, points[0]);
3976
3977                             // Fill each segment separatly for the 3D look
3978                             if (fill3DCircle)
3979                             {
3980                                 path.AddLine(points[0], centerPoint);
3981                                 path.AddLine(centerPoint, prevPoint);
3982                                 using (Brush sectorBrush = GetSector3DBrush(brush, curentSector, sectorSize))
3983                                 {
3984                                     this.FillPath(sectorBrush, path);
3985                                 }
3986                                 path.Reset();
3987                             }
3988                         }
3989
3990                         // Remember last point
3991                         prevPoint = points[0];
3992                     }
3993
3994                     path.CloseAllFigures();
3995
3996                     // Fill last segment for the 3D look
3997                     if (!prevPoint.IsEmpty && fill3DCircle)
3998                     {
3999                         path.AddLine(prevPoint, firstPoint);
4000                         path.AddLine(firstPoint, centerPoint);
4001                         path.AddLine(centerPoint, prevPoint);
4002                         using (Brush sectorBrush = GetSector3DBrush(brush, curentSector, sectorSize))
4003                         {
4004                             this.FillPath(sectorBrush, path);
4005                         }
4006                         path.Reset();
4007                     }
4008
4009                     // Restore old mode
4010                     if (fill3DCircle)
4011                     {
4012                         this.SmoothingMode = oldMode;
4013                     }
4014
4015                     if (brush != null && !circle3D)
4016                     {
4017                         this.FillPath(brush, path);
4018                     }
4019                     if (pen != null)
4020                     {
4021                         this.DrawPath(pen, path);
4022                     }
4023                 }                               
4024                         }
4025                 }
4026
4027         /// <summary>
4028         /// Creates 3D sector brush.
4029         /// </summary>
4030         /// <param name="brush">Original brush.</param>
4031         /// <param name="curentSector">Sector position.</param>
4032         /// <param name="sectorSize">Sector size.</param>
4033         /// <returns>3D brush.</returns>
4034         [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily",
4035             Justification = "Too large of a code change to justify making this change")]
4036                 internal Brush GetSector3DBrush(Brush brush, float curentSector, float sectorSize)
4037                 {
4038                         // Get color from the brush
4039                         Color   brushColor = Color.Gray;
4040                         if(brush is HatchBrush)
4041                         {
4042                                 brushColor = ((HatchBrush)brush).BackgroundColor;
4043                         }
4044                         else if(brush is LinearGradientBrush)
4045                         {
4046                                 brushColor = ((LinearGradientBrush)brush).LinearColors[0];
4047                         }
4048                         else if(brush is PathGradientBrush)
4049                         {
4050                                 brushColor = ((PathGradientBrush)brush).CenterColor;
4051                         }
4052                         else if(brush is SolidBrush)
4053                         {
4054                                 brushColor = ((SolidBrush)brush).Color;
4055                         }
4056
4057                         // Adjust sector angle
4058                         curentSector -= sectorSize / 2f;
4059
4060                         // Make adjustment for polygon circle with 5 segments
4061                         // to avoid the issue that bottom segment is too dark
4062                         if(sectorSize == 72f && curentSector == 180f)
4063                         {
4064                 curentSector *= 0.8f;
4065                         }
4066
4067                         // No angles more than 180 
4068                         if(curentSector > 180)
4069                         {
4070                                 curentSector = 360f - curentSector;
4071                         }
4072                         curentSector = curentSector / 180F;
4073
4074                         // Get brush
4075                         brushColor = GetBrightGradientColor( brushColor, curentSector);
4076
4077                         // Get brush
4078                         return new SolidBrush(brushColor);
4079                 }
4080
4081         /// <summary>
4082         /// This method creates gradient color with brightness
4083         /// </summary>
4084         /// <param name="beginColor">Start color for gradient.</param>
4085         /// <param name="position">Position used between Start and end color.</param>
4086         /// <returns>Calculated Gradient color from gradient position</returns>
4087                 internal Color GetBrightGradientColor( Color beginColor, double position )
4088                 {
4089                         double brightness = 0.5;
4090                         if( position < brightness )
4091                         {
4092                                 return GetGradientColor( Color.FromArgb(beginColor.A,255,255,255), beginColor, 1 - brightness + position );
4093                         }
4094                         else if( -brightness + position < 1 )
4095                         {
4096                                 return GetGradientColor( beginColor, Color.Black, -brightness + position);
4097                         }
4098                         else
4099                         {
4100                                 return Color.FromArgb( beginColor.A, 0, 0, 0 );
4101                         }
4102                 }
4103
4104                 /// <summary>
4105                 /// Draw Rectangle using absolute coordinates.
4106                 /// </summary>
4107                 /// <param name="rect">Size of rectangle</param>
4108                 /// <param name="backColor">Color of rectangle</param>
4109                 /// <param name="backHatchStyle">Hatch Style</param>
4110                 /// <param name="backImage">Image URL</param>
4111                 /// <param name="backImageWrapMode">Image Mode</param>
4112                 /// <param name="backImageTransparentColor">Image transparent color.</param>
4113         /// <param name="backImageAlign">Image alignment.</param>
4114                 /// <param name="backGradientStyle">Gradient AxisName</param>
4115                 /// <param name="backSecondaryColor">End Gradient color</param>
4116                 /// <param name="borderColor">Border Color</param>
4117                 /// <param name="borderWidth">Border Width</param>
4118                 /// <param name="borderDashStyle">Border Style</param>
4119                 /// <param name="penAlignment">Border is outside or inside rectangle</param>
4120                 internal void FillRectangleAbs( RectangleF rect, 
4121                         Color backColor, 
4122                         ChartHatchStyle backHatchStyle, 
4123                         string backImage, 
4124                         ChartImageWrapMode backImageWrapMode, 
4125                         Color backImageTransparentColor,
4126                         ChartImageAlignmentStyle backImageAlign,
4127                         GradientStyle backGradientStyle, 
4128                         Color backSecondaryColor, 
4129                         Color borderColor, 
4130                         int borderWidth, 
4131                         ChartDashStyle borderDashStyle, 
4132                         PenAlignment penAlignment )
4133                 {
4134                         Brush brush = null;
4135                         Brush backBrush = null;
4136
4137                         // Turn off Antialias
4138                         SmoothingMode oldMode = this.SmoothingMode;
4139                         this.SmoothingMode = SmoothingMode.None;
4140
4141                         // Color is empty
4142                         if( backColor.IsEmpty ) 
4143                                 backColor = Color.White;
4144
4145                         if( backSecondaryColor.IsEmpty ) 
4146                                 backSecondaryColor = Color.White;
4147
4148                         if( borderColor.IsEmpty ) 
4149                         {
4150                                 borderColor = Color.White;
4151                                 borderWidth = 0;
4152                         }
4153                 
4154                         // Set a border line color
4155                         _pen.Color = borderColor;
4156
4157                         // Set a border line width
4158                         _pen.Width = borderWidth;
4159
4160                         // Set pen alignment
4161                         _pen.Alignment = penAlignment;
4162
4163                         // Set a border line style
4164                         _pen.DashStyle = GetPenStyle( borderDashStyle );
4165
4166                         if( backGradientStyle == GradientStyle.None )
4167                         {
4168                                 // Set a bar color.
4169                                 _solidBrush.Color = backColor;
4170                                 brush = _solidBrush;
4171                         }
4172                         else
4173                         {
4174                                 // If a gradient type  is set create a brush with gradient
4175                                 brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
4176                         }
4177
4178                         if( backHatchStyle != ChartHatchStyle.None )
4179                         {
4180                                 brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
4181                         }
4182
4183                         if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
4184                         {
4185                                 backBrush = brush;
4186                                 brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
4187                         }
4188
4189                         // For inset alignment resize fill rectangle
4190                         RectangleF fillRect;
4191                         
4192                         // The fill rectangle is same
4193                         fillRect = new RectangleF( rect.X + borderWidth, rect.Y + borderWidth, rect.Width - borderWidth * 2, rect.Height - borderWidth * 2 );
4194
4195                         // FillRectangle and DrawRectangle works differently with RectangleF.
4196                         fillRect.Width += 1;
4197                         fillRect.Height += 1;
4198
4199                         // Draw rectangle image
4200                         if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
4201                         {
4202                                 // Load image
4203                 System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
4204                                 
4205
4206                                 // Prepare image properties (transparent color)
4207                                 ImageAttributes attrib = new ImageAttributes();
4208                                 if(backImageTransparentColor != Color.Empty)
4209                                 {
4210                                         attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
4211                                 }
4212
4213                                 // Draw scaled image
4214                                 RectangleF imageRect = new RectangleF();
4215                                 imageRect.X = fillRect.X;
4216                                 imageRect.Y = fillRect.Y;
4217                                 imageRect.Width = fillRect.Width;
4218                                 imageRect.Height = fillRect.Height;
4219
4220                                 // Draw unscaled image using align property
4221                                 if(backImageWrapMode == ChartImageWrapMode.Unscaled)
4222                                 {
4223                     SizeF imageAbsSize = new SizeF();
4224
4225                     ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageAbsSize);
4226
4227                                         // Calculate image position
4228                     imageRect.Width = imageAbsSize.Width;
4229                     imageRect.Height = imageAbsSize.Height;
4230
4231                                         // Adjust position with alignment property
4232                                         if(imageRect.Width < fillRect.Width)
4233                                         {
4234                                                 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
4235                                                         backImageAlign == ChartImageAlignmentStyle.Right ||
4236                                                         backImageAlign == ChartImageAlignmentStyle.TopRight)
4237                                                 {
4238                                                         imageRect.X = fillRect.Right - imageRect.Width;
4239                                                 }
4240                                                 else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
4241                                                         backImageAlign == ChartImageAlignmentStyle.Center ||
4242                                                         backImageAlign == ChartImageAlignmentStyle.Top)
4243                                                 {
4244                                                         imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
4245                                                 }
4246                                         }
4247                                         if(imageRect.Height < fillRect.Height)
4248                                         {
4249                                                 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
4250                                                         backImageAlign == ChartImageAlignmentStyle.Bottom ||
4251                                                         backImageAlign == ChartImageAlignmentStyle.BottomLeft)
4252                                                 {
4253                                                         imageRect.Y = fillRect.Bottom - imageRect.Height;
4254                                                 }
4255                                                 else if(backImageAlign == ChartImageAlignmentStyle.Left ||
4256                                                         backImageAlign == ChartImageAlignmentStyle.Center ||
4257                                                         backImageAlign == ChartImageAlignmentStyle.Right)
4258                                                 {
4259                                                         imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
4260                                                 }
4261                                         }
4262
4263                                 }
4264
4265                                 // Fill background with brush
4266                                 this.FillRectangle( brush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1);
4267
4268                                 // Draw image
4269                                 this.DrawImage(image, 
4270                                         new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
4271                                         0, 0, image.Width, image.Height,
4272                                         GraphicsUnit.Pixel, 
4273                                         attrib);
4274                         }
4275                                 // Draw rectangle
4276                         else
4277                         {
4278                                 if(backBrush != null && backImageTransparentColor != Color.Empty)
4279                                 {
4280                                         // Fill background with brush
4281                                         this.FillRectangle( backBrush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
4282                                 }
4283                                 this.FillRectangle( brush, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
4284                         }
4285
4286                         // Set pen alignment
4287                         if(borderDashStyle != ChartDashStyle.NotSet)
4288                         {
4289                                 if( borderWidth > 1 )
4290                                         this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width + 1, rect.Height + 1 );
4291                                 else if( borderWidth == 1 )
4292                                         this.DrawRectangle( _pen, rect.X, rect.Y, rect.Width, rect.Height );
4293                         }
4294
4295                         // Dispose Image and Gradient
4296                         if( backGradientStyle != GradientStyle.None )
4297                         {
4298                                 brush.Dispose();
4299                         }
4300                         if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
4301                         {
4302                                 brush.Dispose();
4303                         }
4304                         if( backHatchStyle != ChartHatchStyle.None )
4305                         {
4306                                 brush.Dispose();
4307                         }
4308
4309                         // Set Old Smoothing Mode
4310                         this.SmoothingMode = oldMode;
4311                 }
4312
4313                 /// <summary>
4314                 /// Fills graphics path with shadow using absolute coordinates.
4315                 /// </summary>
4316                 /// <param name="path">Graphics path to fill.</param>
4317                 /// <param name="backColor">Color of rectangle</param>
4318                 /// <param name="backHatchStyle">Hatch Style</param>
4319                 /// <param name="backImage">Image URL</param>
4320                 /// <param name="backImageWrapMode">Image Mode</param>
4321                 /// <param name="backImageTransparentColor">Image transparent color.</param>
4322         /// <param name="backImageAlign">Image alignment.</param>
4323                 /// <param name="backGradientStyle">Gradient AxisName</param>
4324                 /// <param name="backSecondaryColor">End Gradient color</param>
4325                 /// <param name="borderColor">Border Color</param>
4326                 /// <param name="borderWidth">Border Width</param>
4327                 /// <param name="borderDashStyle">Border Style</param>
4328                 /// <param name="penAlignment">Border is outside or inside rectangle</param>
4329                 /// <param name="shadowOffset">Shadow offset.</param>
4330                 /// <param name="shadowColor">Shadow color.</param>
4331                 internal void DrawPathAbs( 
4332                         GraphicsPath path, 
4333                         Color backColor, 
4334                         ChartHatchStyle backHatchStyle, 
4335                         string backImage, 
4336                         ChartImageWrapMode backImageWrapMode, 
4337                         Color backImageTransparentColor,
4338                         ChartImageAlignmentStyle backImageAlign,
4339                         GradientStyle backGradientStyle, 
4340                         Color backSecondaryColor, 
4341                         Color borderColor, 
4342                         int borderWidth, 
4343                         ChartDashStyle borderDashStyle, 
4344                         PenAlignment penAlignment,
4345                         int shadowOffset,
4346                         Color shadowColor)
4347                 {
4348                         // Draw patj shadow
4349                         if(shadowOffset != 0 && shadowColor != Color.Transparent)
4350                         {
4351                                 // Save graphics state and apply translate transformation
4352                                 GraphicsState graphicsState = this.Save();
4353                                 this.TranslateTransform(shadowOffset, shadowOffset);
4354
4355                                 if(backColor == Color.Transparent &&
4356                                         backSecondaryColor.IsEmpty )
4357                                 {
4358                                         this.DrawPathAbs(
4359                                                 path,
4360                                                 Color.Transparent,
4361                                                 ChartHatchStyle.None,
4362                                                 String.Empty,
4363                                                 ChartImageWrapMode.Scaled,
4364                                                 Color.Empty,
4365                                                 ChartImageAlignmentStyle.Center,
4366                                                 GradientStyle.None,
4367                                                 Color.Empty,
4368                                                 shadowColor,
4369                                                 borderWidth,
4370                                                 borderDashStyle,
4371                                                 PenAlignment.Center);
4372                                 }
4373                                 else
4374                                 {
4375                                         this.DrawPathAbs(
4376                                                 path,
4377                                                 shadowColor,
4378                                                 ChartHatchStyle.None,
4379                                                 String.Empty,
4380                                                 ChartImageWrapMode.Scaled,
4381                                                 Color.Empty,
4382                                                 ChartImageAlignmentStyle.Center,
4383                                                 GradientStyle.None,
4384                                                 Color.Empty,
4385                                                 Color.Transparent,
4386                                                 0,
4387                                                 ChartDashStyle.NotSet,
4388                                                 PenAlignment.Center);
4389                                 }
4390
4391                                 // Restore graphics state
4392                                 this.Restore(graphicsState);
4393                         }
4394
4395                         // Draw path
4396                         this.DrawPathAbs(
4397                                 path,
4398                                 backColor, 
4399                                 backHatchStyle, 
4400                                 backImage, 
4401                                 backImageWrapMode, 
4402                                 backImageTransparentColor,
4403                                 backImageAlign,
4404                                 backGradientStyle, 
4405                                 backSecondaryColor, 
4406                                 borderColor, 
4407                                 borderWidth, 
4408                                 borderDashStyle, 
4409                                 penAlignment);
4410                 }
4411
4412                 /// <summary>
4413                 /// Fills graphics path using absolute coordinates.
4414                 /// </summary>
4415                 /// <param name="path">Graphics path to fill.</param>
4416                 /// <param name="backColor">Color of rectangle</param>
4417                 /// <param name="backHatchStyle">Hatch Style</param>
4418                 /// <param name="backImage">Image URL</param>
4419                 /// <param name="backImageWrapMode">Image Mode</param>
4420                 /// <param name="backImageTransparentColor">Image transparent color.</param>
4421         /// <param name="backImageAlign">Image alignment.</param>
4422                 /// <param name="backGradientStyle">Gradient AxisName</param>
4423                 /// <param name="backSecondaryColor">End Gradient color</param>
4424                 /// <param name="borderColor">Border Color</param>
4425                 /// <param name="borderWidth">Border Width</param>
4426                 /// <param name="borderDashStyle">Border Style</param>
4427                 /// <param name="penAlignment">Border is outside or inside rectangle</param>
4428                 internal void DrawPathAbs( GraphicsPath path, 
4429                         Color backColor, 
4430                         ChartHatchStyle backHatchStyle, 
4431                         string backImage, 
4432                         ChartImageWrapMode backImageWrapMode, 
4433                         Color backImageTransparentColor,
4434                         ChartImageAlignmentStyle backImageAlign,
4435                         GradientStyle backGradientStyle, 
4436                         Color backSecondaryColor, 
4437                         Color borderColor, 
4438                         int borderWidth, 
4439                         ChartDashStyle borderDashStyle, 
4440                         PenAlignment penAlignment )
4441                 {
4442                         Brush brush = null;
4443                         Brush backBrush = null;
4444
4445                         // Color is empty
4446                         if( backColor.IsEmpty ) 
4447                                 backColor = Color.White;
4448
4449                         if( backSecondaryColor.IsEmpty ) 
4450                                 backSecondaryColor = Color.White;
4451
4452                         if( borderColor.IsEmpty ) 
4453                         {
4454                                 borderColor = Color.White;
4455                                 borderWidth = 0;
4456                         }
4457                 
4458                         // Set pen properties
4459                         _pen.Color = borderColor;
4460                         _pen.Width = borderWidth;
4461                         _pen.Alignment = penAlignment;
4462                         _pen.DashStyle = GetPenStyle( borderDashStyle );
4463
4464                         if( backGradientStyle == GradientStyle.None )
4465                         {
4466                                 // Set solid brush color.
4467                                 _solidBrush.Color = backColor;
4468                                 brush = _solidBrush;
4469                         }
4470                         else
4471                         {
4472                                 // If a gradient type  is set create a brush with gradient
4473                                 RectangleF pathRect = path.GetBounds();
4474                                 pathRect.Inflate(new SizeF(2,2));
4475                                 brush = GetGradientBrush( 
4476                                         pathRect, 
4477                                         backColor, 
4478                                         backSecondaryColor, 
4479                                         backGradientStyle );
4480                         }
4481
4482                         if( backHatchStyle != ChartHatchStyle.None )
4483                         {
4484                                 brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
4485                         }
4486
4487                         if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
4488                         {
4489                                 backBrush = brush;
4490                                 brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
4491                         }
4492
4493                         // For inset alignment resize fill rectangle
4494                         RectangleF fillRect = path.GetBounds();
4495                         
4496                         // Draw rectangle image
4497                         if( backImage.Length > 0 && (backImageWrapMode == ChartImageWrapMode.Unscaled || backImageWrapMode == ChartImageWrapMode.Scaled))
4498                         {
4499                                 // Load image
4500 System.Drawing.Image image = _common.ImageLoader.LoadImage( backImage );
4501
4502                                 // Prepare image properties (transparent color)
4503                                 ImageAttributes attrib = new ImageAttributes();
4504                                 if(backImageTransparentColor != Color.Empty)
4505                                 {
4506                                         attrib.SetColorKey(backImageTransparentColor, backImageTransparentColor, ColorAdjustType.Default);
4507                                 }
4508
4509                                 // Draw scaled image
4510                                 RectangleF imageRect = new RectangleF();
4511                                 imageRect.X = fillRect.X;
4512                                 imageRect.Y = fillRect.Y;
4513                                 imageRect.Width = fillRect.Width;
4514                                 imageRect.Height = fillRect.Height;
4515
4516                                 // Draw unscaled image using align property
4517                                 if(backImageWrapMode == ChartImageWrapMode.Unscaled)
4518                                 {
4519                     SizeF imageSize = new SizeF();
4520
4521                     ImageLoader.GetAdjustedImageSize(image, this.Graphics, ref imageSize);
4522
4523                                         // Calculate image position
4524                     imageRect.Width = imageSize.Width;
4525                     imageRect.Height = imageSize.Height;
4526
4527                                         // Adjust position with alignment property
4528                                         if(imageRect.Width < fillRect.Width)
4529                                         {
4530                                                 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
4531                                                         backImageAlign == ChartImageAlignmentStyle.Right ||
4532                                                         backImageAlign == ChartImageAlignmentStyle.TopRight)
4533                                                 {
4534                                                         imageRect.X = fillRect.Right - imageRect.Width;
4535                                                 }
4536                                                 else if(backImageAlign == ChartImageAlignmentStyle.Bottom ||
4537                                                         backImageAlign == ChartImageAlignmentStyle.Center ||
4538                                                         backImageAlign == ChartImageAlignmentStyle.Top)
4539                                                 {
4540                                                         imageRect.X = fillRect.X + (fillRect.Width - imageRect.Width)/2;
4541                                                 }
4542                                         }
4543                                         if(imageRect.Height < fillRect.Height)
4544                                         {
4545                                                 if(backImageAlign == ChartImageAlignmentStyle.BottomRight ||
4546                                                         backImageAlign == ChartImageAlignmentStyle.Bottom ||
4547                                                         backImageAlign == ChartImageAlignmentStyle.BottomLeft)
4548                                                 {
4549                                                         imageRect.Y = fillRect.Bottom - imageRect.Height;
4550                                                 }
4551                                                 else if(backImageAlign == ChartImageAlignmentStyle.Left ||
4552                                                         backImageAlign == ChartImageAlignmentStyle.Center ||
4553                                                         backImageAlign == ChartImageAlignmentStyle.Right)
4554                                                 {
4555                                                         imageRect.Y = fillRect.Y + (fillRect.Height - imageRect.Height)/2;
4556                                                 }
4557                                         }
4558
4559                                 }
4560
4561                                 // Fill background with brush
4562                                 this.FillPath( brush, path );
4563
4564                                 // Draw image
4565                                 Region oldClipRegion = this.Clip;
4566                                 this.Clip = new Region(path);
4567                                 this.DrawImage(image, 
4568                                         new Rectangle((int)Math.Round(imageRect.X),(int)Math.Round(imageRect.Y), (int)Math.Round(imageRect.Width), (int)Math.Round(imageRect.Height)),
4569                                         0, 0, image.Width, image.Height,
4570                                         GraphicsUnit.Pixel, 
4571                                         attrib);
4572                                 this.Clip = oldClipRegion;
4573                         }
4574                         
4575                                 // Draw rectangle
4576                         else
4577                         {
4578                                 if(backBrush != null && backImageTransparentColor != Color.Empty)
4579                                 {
4580                                         // Fill background with brush
4581                                         this.FillPath( backBrush, path);
4582                                 }
4583                                 this.FillPath( brush, path);
4584                         }
4585
4586                         // Draw border
4587                         if(borderColor != Color.Empty && borderWidth > 0 && borderDashStyle != ChartDashStyle.NotSet)
4588                         {
4589                                 this.DrawPath( _pen, path );
4590                         }
4591                 }
4592
4593                 /// <summary>
4594                 /// Creates brush with specified properties.
4595                 /// </summary>
4596                 /// <param name="rect">Gradient rectangle</param>
4597                 /// <param name="backColor">Color of rectangle</param>
4598                 /// <param name="backHatchStyle">Hatch style</param>
4599                 /// <param name="backImage">Back Image</param>
4600                 /// <param name="backImageWrapMode">Image mode</param>
4601                 /// <param name="backImageTransparentColor">Image transparent color.</param>
4602                 /// <param name="backGradientStyle">Gradient type </param>
4603                 /// <param name="backSecondaryColor">Gradient End Color</param>
4604                 /// <returns>New brush object.</returns>
4605                 internal Brush CreateBrush( 
4606                         RectangleF rect,
4607                         Color backColor, 
4608                         ChartHatchStyle backHatchStyle, 
4609                         string backImage, 
4610                         ChartImageWrapMode backImageWrapMode, 
4611                         Color backImageTransparentColor,
4612                         GradientStyle backGradientStyle, 
4613                         Color backSecondaryColor
4614                         )
4615                 {
4616                         Brush brush = new SolidBrush(backColor);
4617
4618                         if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled)
4619                         {
4620                                 brush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
4621                         }
4622                         else if( backHatchStyle != ChartHatchStyle.None )
4623                         {
4624                                 brush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
4625                         }
4626                         else if( backGradientStyle != GradientStyle.None )
4627                         {
4628                                 // If a gradient type  is set create a brush with gradient
4629                                 brush = GetGradientBrush( rect, backColor, backSecondaryColor, backGradientStyle );
4630                         }
4631
4632                         return brush;
4633                 }
4634
4635                 #endregion
4636
4637                 #region Coordinates converter
4638
4639                 /// <summary>
4640         /// This method takes a RectangleF structure that is using absolute coordinates 
4641         /// and returns a RectangleF object that uses relative coordinates.
4642                 /// </summary>
4643         /// <param name="rectangle">RectangleF structure in absolute coordinates.</param>
4644         /// <returns>RectangleF structure in relative coordinates.</returns>
4645                 public RectangleF GetRelativeRectangle( RectangleF rectangle )
4646                 {
4647             // Check arguments
4648             if (rectangle == null)
4649                 throw new ArgumentNullException("rectangle");
4650             
4651             RectangleF relative = RectangleF.Empty;
4652
4653                         // Convert absolute coordinates to relative coordinates
4654                         relative.X = rectangle.X * 100F / ((float)(_width - 1)); 
4655                         relative.Y = rectangle.Y * 100F / ((float)(_height - 1)); 
4656                         relative.Width = rectangle.Width * 100F / ((float)(_width - 1)); 
4657                         relative.Height = rectangle.Height * 100F / ((float)(_height - 1)); 
4658
4659                         // Return Relative coordinates
4660                         return relative;
4661                 }
4662
4663                 /// <summary>
4664         /// This method takes a PointF object that is using absolute coordinates 
4665         /// and returns a PointF object that uses relative coordinates.
4666                 /// </summary>
4667                 /// <param name="point">PointF object in absolute coordinates.</param>
4668                 /// <returns>PointF object in relative coordinates.</returns>
4669                 public PointF GetRelativePoint( PointF point )
4670                 {
4671             // Check arguments
4672             if (point == null)
4673                 throw new ArgumentNullException("point");
4674             
4675             PointF relative = PointF.Empty;
4676
4677                         // Convert absolute coordinates to relative coordinates
4678                         relative.X = point.X * 100F / ((float)(_width - 1)); 
4679                         relative.Y = point.Y * 100F / ((float)(_height - 1)); 
4680                         
4681                         // Return Relative coordinates
4682                         return relative;
4683                 }
4684
4685
4686                 /// <summary>
4687         /// This method takes a SizeF object that uses absolute coordinates 
4688         /// and returns a SizeF object that uses relative coordinates.
4689                 /// </summary>
4690                 /// <param name="size">SizeF object in absolute coordinates.</param>
4691         /// <returns>SizeF object in relative coordinates.</returns>
4692                 public SizeF GetRelativeSize( SizeF size )
4693                 {
4694             // Check arguments
4695             if (size == null)
4696                 throw new ArgumentNullException("size"); 
4697             
4698             SizeF relative = SizeF.Empty;
4699
4700                         // Convert absolute coordinates to relative coordinates
4701                         relative.Width = size.Width * 100F / ((float)(_width - 1)); 
4702                         relative.Height = size.Height * 100F / ((float)(_height - 1)); 
4703                         
4704                         // Return relative coordinates
4705                         return relative;
4706                 }
4707
4708                 /// <summary>
4709         /// This method takes a PointF object and converts its relative coordinates 
4710         /// to absolute coordinates.
4711                 /// </summary>
4712         /// <param name="point">PointF object in relative coordinates.</param>
4713         /// <returns>PointF object in absolute coordinates.</returns>
4714                 public PointF GetAbsolutePoint( PointF point )
4715                 {
4716             // Check arguments
4717             if (point == null)
4718                 throw new ArgumentNullException("point");
4719
4720                         PointF absolute = PointF.Empty;
4721
4722                         // Convert relative coordinates to absolute coordinates
4723                         absolute.X = point.X * (_width - 1) / 100F; 
4724                         absolute.Y = point.Y * (_height - 1) / 100F; 
4725
4726                         // Return Absolute coordinates
4727                         return absolute;
4728                 }
4729
4730                 /// <summary>
4731         /// This method takes a RectangleF structure and converts its relative coordinates 
4732         /// to absolute coordinates.
4733                 /// </summary>
4734         /// <param name="rectangle">RectangleF object in relative coordinates.</param>
4735         /// <returns>RectangleF object in absolute coordinates.</returns>
4736                 public RectangleF GetAbsoluteRectangle( RectangleF rectangle )
4737                 {
4738             // Check arguments
4739             if (rectangle == null)
4740                 throw new ArgumentNullException("rectangle");
4741
4742                         RectangleF absolute = RectangleF.Empty;
4743
4744                         // Convert relative coordinates to absolute coordinates
4745                         absolute.X = rectangle.X * (_width - 1) / 100F; 
4746                         absolute.Y = rectangle.Y * (_height - 1) / 100F; 
4747                         absolute.Width = rectangle.Width * (_width - 1) / 100F; 
4748                         absolute.Height = rectangle.Height * (_height - 1) / 100F; 
4749
4750                         // Return Absolute coordinates
4751                         return absolute;
4752                 }
4753
4754                 /// <summary>
4755         /// This method takes a SizeF object that uses relative coordinates
4756         /// and returns a SizeF object that uses absolute coordinates.
4757                 /// </summary>
4758         /// <param name="size">SizeF object in relative coordinates.</param>
4759         /// <returns>SizeF object in absolute coordinates.</returns>
4760                 public SizeF GetAbsoluteSize( SizeF size )
4761                 {
4762             // Check arguments
4763             if (size == null)
4764                 throw new ArgumentNullException("size"); 
4765             
4766             SizeF absolute = SizeF.Empty;
4767
4768                         // Convert relative coordinates to absolute coordinates
4769                         absolute.Width = size.Width * (_width - 1) / 100F; 
4770                         absolute.Height = size.Height * (_height - 1) / 100F; 
4771                         
4772                         // Return Absolute coordinates
4773                         return absolute;
4774                 }
4775
4776         
4777                 #endregion
4778
4779                 #region Border drawing helper methods
4780
4781                 /// <summary>
4782                 /// Helper function which creates a rounded rectangle path.
4783                 /// </summary>
4784                 /// <param name="rect">Rectangle coordinates.</param>
4785                 /// <param name="cornerRadius">Array of 4 corners radius.</param>
4786                 /// <returns>Graphics path object.</returns>
4787                 internal GraphicsPath CreateRoundedRectPath(RectangleF rect, float[] cornerRadius)
4788                 {
4789                         // Create rounded rectangle path
4790                         GraphicsPath path = new GraphicsPath();
4791                         path.AddLine(rect.X+cornerRadius[0], rect.Y, rect.Right-cornerRadius[1], rect.Y);
4792                         path.AddArc(rect.Right-2f*cornerRadius[1], rect.Y, 2f*cornerRadius[1], 2f*cornerRadius[2], 270, 90);
4793                         path.AddLine(rect.Right, rect.Y + cornerRadius[2], rect.Right, rect.Bottom - cornerRadius[3]);
4794                         path.AddArc(rect.Right-2f*cornerRadius[4], rect.Bottom-2f*cornerRadius[3], 2f*cornerRadius[4], 2f*cornerRadius[3], 0, 90);
4795                         path.AddLine(rect.Right-cornerRadius[4], rect.Bottom, rect.X + cornerRadius[5], rect.Bottom);
4796                         path.AddArc(rect.X, rect.Bottom-2f*cornerRadius[6], 2f*cornerRadius[5], 2f*cornerRadius[6], 90, 90);
4797                         path.AddLine(rect.X, rect.Bottom-cornerRadius[6], rect.X, rect.Y+cornerRadius[7]);
4798                         path.AddArc(rect.X, rect.Y, 2f*cornerRadius[0], 2f*cornerRadius[7], 180, 90);
4799
4800                         return path;
4801                 }
4802
4803                 /// <summary>
4804                 /// Helper function which draws a shadow of the rounded rect.
4805                 /// </summary>
4806                 /// <param name="rect">Rectangle coordinates.</param>
4807                 /// <param name="cornerRadius">Array of 4 corners radius.</param>
4808                 /// <param name="radius">Rounding radius.</param>
4809                 /// <param name="centerColor">Center color.</param>
4810                 /// <param name="surroundColor">Surrounding color.</param>
4811                 /// <param name="shadowScale">Shadow scale value.</param>
4812                 internal void DrawRoundedRectShadowAbs(RectangleF rect, float[] cornerRadius, float radius, Color centerColor, Color surroundColor, float shadowScale)
4813                 {
4814                         // Create rounded rectangle path
4815                         GraphicsPath path = CreateRoundedRectPath(rect, cornerRadius);
4816
4817                         // Create gradient brush
4818                         PathGradientBrush shadowBrush = new PathGradientBrush(path);
4819                         shadowBrush.CenterColor = centerColor;
4820
4821                         // Set the color along the entire boundary of the path
4822                         Color[] colors = {surroundColor};
4823                         shadowBrush.SurroundColors = colors;
4824                         shadowBrush.CenterPoint = new PointF(rect.X + rect.Width/2f, rect.Y + rect.Height/2f);
4825
4826                         // Define brush focus scale
4827                         PointF focusScale = new PointF(1-shadowScale*radius/rect.Width, 1-shadowScale*radius/rect.Height);
4828                         shadowBrush.FocusScales = focusScale;
4829
4830                         // Draw rounded rectangle
4831                         this.FillPath(shadowBrush, path);
4832
4833                         if( path != null )
4834                         {
4835                                 path.Dispose();
4836                         }
4837                 }
4838
4839                 /// <summary>
4840                 /// Draws 3D border in absolute coordinates.
4841                 /// </summary>
4842                 /// <param name="borderSkin">Border skin object.</param>
4843                 /// <param name="rect">Rectangle of the border (pixel coordinates).</param>
4844                 /// <param name="backColor">Color of rectangle</param>
4845                 /// <param name="backHatchStyle">Hatch style</param>
4846                 /// <param name="backImage">Back Image</param>
4847                 /// <param name="backImageWrapMode">Image mode</param>
4848                 /// <param name="backImageTransparentColor">Image transparent color.</param>
4849         /// <param name="backImageAlign">Image alignment</param>
4850                 /// <param name="backGradientStyle">Gradient type </param>
4851                 /// <param name="backSecondaryColor">Gradient End Color</param>
4852                 /// <param name="borderColor">Border Color</param>
4853                 /// <param name="borderWidth">Border Width</param>
4854                 /// <param name="borderDashStyle">Border Style</param>
4855                 internal void Draw3DBorderRel(
4856                         BorderSkin borderSkin, 
4857                         RectangleF rect, 
4858                         Color backColor, 
4859                         ChartHatchStyle backHatchStyle, 
4860                         string backImage, 
4861                         ChartImageWrapMode backImageWrapMode, 
4862                         Color backImageTransparentColor,
4863                         ChartImageAlignmentStyle backImageAlign,
4864                         GradientStyle backGradientStyle, 
4865                         Color backSecondaryColor, 
4866                         Color borderColor, 
4867                         int borderWidth, 
4868                         ChartDashStyle borderDashStyle)
4869                 {
4870                         Draw3DBorderAbs(borderSkin, GetAbsoluteRectangle(rect), backColor, backHatchStyle, 
4871                                 backImage, backImageWrapMode, backImageTransparentColor, backImageAlign, backGradientStyle, 
4872                                 backSecondaryColor, borderColor, borderWidth, borderDashStyle);
4873                 }
4874
4875
4876                 /// <summary>
4877                 /// Draws 3D border in absolute coordinates.
4878                 /// </summary>
4879                 /// <param name="borderSkin">Border skin object.</param>
4880                 /// <param name="absRect">Rectangle of the border (pixel coordinates).</param>
4881                 /// <param name="backColor">Color of rectangle</param>
4882                 /// <param name="backHatchStyle">Hatch style</param>
4883                 /// <param name="backImage">Back Image</param>
4884                 /// <param name="backImageWrapMode">Image mode</param>
4885                 /// <param name="backImageTransparentColor">Image transparent color.</param>
4886         /// <param name="backImageAlign">Image alignment</param>
4887                 /// <param name="backGradientStyle">Gradient type </param>
4888                 /// <param name="backSecondaryColor">Gradient End Color</param>
4889                 /// <param name="borderColor">Border Color</param>
4890                 /// <param name="borderWidth">Border Width</param>
4891                 /// <param name="borderDashStyle">Border Style</param>
4892                 internal void Draw3DBorderAbs(
4893                         BorderSkin borderSkin, 
4894                         RectangleF absRect, 
4895                         Color backColor, 
4896                         ChartHatchStyle backHatchStyle, 
4897                         string backImage, 
4898                         ChartImageWrapMode backImageWrapMode, 
4899                         Color backImageTransparentColor,
4900                         ChartImageAlignmentStyle backImageAlign,
4901                         GradientStyle backGradientStyle, 
4902                         Color backSecondaryColor, 
4903                         Color borderColor, 
4904                         int borderWidth, 
4905                         ChartDashStyle borderDashStyle)
4906                 {
4907                         // Check input parameters
4908                         if(_common == null || borderSkin.SkinStyle == BorderSkinStyle.None || absRect.Width == 0 || absRect.Height == 0)
4909                         {
4910                                 return;
4911                         }
4912
4913                         // Find required border interface
4914                         IBorderType     borderTypeInterface = _common.BorderTypeRegistry.GetBorderType(borderSkin.SkinStyle.ToString());
4915                         if(borderTypeInterface != null)
4916                         {
4917                 borderTypeInterface.Resolution = this.Graphics.DpiX;
4918                                 // Draw border
4919                                 borderTypeInterface.DrawBorder(this, borderSkin, absRect, backColor, backHatchStyle, backImage, backImageWrapMode, 
4920                                         backImageTransparentColor, backImageAlign, backGradientStyle, backSecondaryColor, 
4921                                         borderColor, borderWidth, borderDashStyle);
4922                         }
4923                 }
4924
4925                 #endregion
4926
4927                 #region Pie Method
4928
4929                 /// <summary>
4930                 /// Helper function that retrieves pie drawing style.
4931                 /// </summary>
4932                 /// <param name="point">Data point to get the drawing style for.</param>
4933                 /// <returns>pie drawing style.</returns>
4934                 internal static PieDrawingStyle GetPieDrawingStyle(DataPoint point)
4935                 {
4936                         // Get column drawing style
4937                         PieDrawingStyle pieDrawingStyle = PieDrawingStyle.Default;
4938                         string styleName = point[CustomPropertyName.PieDrawingStyle];
4939                         if(styleName != null)
4940                         {
4941                                 if(String.Compare(styleName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
4942                                 {
4943                                         pieDrawingStyle = PieDrawingStyle.Default;
4944                                 }
4945                 else if (String.Compare(styleName, "SoftEdge", StringComparison.OrdinalIgnoreCase) == 0)
4946                                 {
4947                                         pieDrawingStyle = PieDrawingStyle.SoftEdge;
4948                                 }
4949                 else if (String.Compare(styleName, "Concave", StringComparison.OrdinalIgnoreCase) == 0)
4950                                 {
4951                                         pieDrawingStyle = PieDrawingStyle.Concave;
4952                                 }                                       
4953                                 else
4954                                 {
4955                                         throw( new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid( styleName, "PieDrawingStyle")));
4956                                 }
4957                         }
4958                         return pieDrawingStyle;
4959                 }
4960
4961                 /// <summary>
4962                 /// Draws a pie defined by an ellipse specified by a Rectangle structure and two radial lines.
4963                 /// </summary>
4964                 /// <param name="rect">Rectangle structure that represents the bounding rectangle that defines the ellipse from which the pie shape comes.</param>
4965                 /// <param name="startAngle">Angle measured in degrees clockwise from the x-axis to the first side of the pie shape.</param>
4966                 /// <param name="sweepAngle">Angle measured in degrees clockwise from the startAngle parameter to the second side of the pie shape.</param>
4967                 /// <param name="backColor">Fill color</param>
4968                 /// <param name="backHatchStyle">Fill Hatch Style</param>
4969                 /// <param name="backImage">Fill texture</param>
4970                 /// <param name="backImageWrapMode">Texture image mode</param>
4971                 /// <param name="backImageTransparentColor">Texture transparent color</param>
4972                 /// <param name="backGradientStyle">Fill Gradient type </param>
4973                 /// <param name="backSecondaryColor">Fill Gradient Second Color</param>
4974                 /// <param name="borderColor">Border Color</param>
4975                 /// <param name="borderWidth">Border Width</param>
4976                 /// <param name="borderDashStyle">Border Style</param>
4977                 /// <param name="shadow">True if shadow is active</param>
4978                 /// <param name="doughnut">True if Doughnut is drawn instead of pie</param>
4979                 /// <param name="doughnutRadius">Internal radius of the doughnut</param>
4980                 /// <param name="pieDrawingStyle">Pie drawing style.</param>
4981                 internal void DrawPieRel( 
4982                         RectangleF rect, 
4983                         float startAngle,
4984                         float sweepAngle,
4985                         Color backColor, 
4986                         ChartHatchStyle backHatchStyle, 
4987                         string backImage, 
4988                         ChartImageWrapMode backImageWrapMode, 
4989                         Color backImageTransparentColor,
4990                         GradientStyle backGradientStyle, 
4991                         Color backSecondaryColor, 
4992                         Color borderColor, 
4993                         int borderWidth, 
4994                         ChartDashStyle borderDashStyle, 
4995                         bool shadow,
4996                         bool doughnut,
4997                         float doughnutRadius,
4998                         PieDrawingStyle pieDrawingStyle
4999                         )
5000                 {
5001                         Pen borderPen = null;   // Pen
5002                         Brush fillBrush;                // Brush
5003
5004                         // Get absolute rectangle
5005                         RectangleF absRect = GetAbsoluteRectangle( rect );
5006
5007                         if( doughnutRadius == 100.0 )
5008                         {
5009                                 doughnut = false;
5010                         }
5011
5012                         if( doughnutRadius == 0.0 )
5013                         {
5014                                 return;
5015                         }
5016
5017                         // Create Brush
5018                         if( backHatchStyle != ChartHatchStyle.None )
5019                         {
5020                                 // Create Hatch Brush
5021                                 fillBrush = GetHatchBrush( backHatchStyle, backColor, backSecondaryColor );
5022                         }
5023                         else if( backGradientStyle != GradientStyle.None ) 
5024                         { 
5025                                 // Create gradient brush
5026                                 if( backGradientStyle == GradientStyle.Center )
5027                                 {
5028                                         fillBrush = GetPieGradientBrush( absRect, backColor, backSecondaryColor );
5029                                 }
5030                                 else
5031                                 {
5032                     using (GraphicsPath path = new GraphicsPath())
5033                     {
5034                         path.AddPie(absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle);
5035                         fillBrush = GetGradientBrush(path.GetBounds(), backColor, backSecondaryColor, backGradientStyle);
5036                     }
5037                                 }
5038                         }
5039                         else if( backImage.Length > 0 && backImageWrapMode != ChartImageWrapMode.Unscaled && backImageWrapMode != ChartImageWrapMode.Scaled )
5040                         { 
5041                                 // Create textured brush
5042                                 fillBrush = GetTextureBrush(backImage, backImageTransparentColor, backImageWrapMode, backColor );
5043                         }
5044                         else
5045                         {
5046                                 // Create solid brush
5047                                 fillBrush = new SolidBrush( backColor );
5048                         }
5049
5050                         // Create border Pen
5051                         borderPen = new Pen( borderColor, borderWidth );
5052                         
5053                         // Set a border line style
5054                         borderPen.DashStyle = GetPenStyle( borderDashStyle );
5055
5056                         // Use rounded line joins
5057                         borderPen.LineJoin = LineJoin.Round;
5058
5059                         // Draw Doughnut
5060                         if( doughnut )
5061                         {
5062                 using (GraphicsPath path = new GraphicsPath())
5063                 {
5064
5065                     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);
5066                     path.AddArc(absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle + sweepAngle, -sweepAngle);
5067
5068                     path.CloseFigure();
5069
5070                     this.FillPath(fillBrush, path);
5071
5072
5073                     // Draw Pie gradien effects
5074                     this.DrawPieGradientEffects(pieDrawingStyle, absRect, startAngle, sweepAngle, doughnutRadius);
5075
5076                     // Draw Doughnut Border
5077                     if (!shadow &&
5078                         borderWidth > 0 &&
5079                         borderDashStyle != ChartDashStyle.NotSet)
5080                     {
5081                         this.DrawPath(borderPen, path);
5082                     }
5083                 }
5084                         }
5085                         else // Draw Pie
5086                         {
5087
5088                                 // Draw Soft shadow for pie slice
5089                                 if( shadow && softShadows )
5090                                 {
5091                                         DrawPieSoftShadow( startAngle, sweepAngle, absRect, backColor );
5092                                 }
5093                                 else 
5094                                 {
5095                                         // Fill Pie for normal shadow or colored pie slice
5096                                         this.FillPie( fillBrush, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
5097
5098                                         // Draw Pie gradien effects
5099                                         this.DrawPieGradientEffects( pieDrawingStyle, absRect, startAngle, sweepAngle, -1f);
5100                                 }
5101
5102                                 
5103                                 // Draw Pie Border
5104                                 if( !shadow  &&
5105                                         borderWidth > 0 &&
5106                                         borderDashStyle != ChartDashStyle.NotSet)
5107                                 {
5108                                         this.DrawPie( borderPen, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
5109                                 }
5110                         }
5111
5112                         // Dispose graphics objects
5113                         if( borderPen != null )
5114                         {
5115                                 borderPen.Dispose();
5116                         }
5117
5118                         if( fillBrush != null )
5119                         {
5120                                 fillBrush.Dispose();
5121                         }
5122                 }
5123
5124                 private void DrawPieGradientEffects( 
5125                         PieDrawingStyle pieDrawingStyle, 
5126                         RectangleF position, 
5127                         float startAngle, 
5128                         float sweepAngle,
5129                         float doughnutRadius)
5130                 {
5131                         if(pieDrawingStyle == PieDrawingStyle.Concave)
5132                         {
5133                                 // Calculate the size of the shadow. Note: For Doughnut chart shadow is drawn 
5134                                 // twice on the outside and inside radius.
5135                                 float minSize = (float)Math.Min(position.Width, position.Height);
5136                                 float shadowSize = minSize * 0.05f;
5137                         
5138                                 // Create brush path
5139                                 RectangleF gradientPath = position;
5140                                 gradientPath.Inflate(-shadowSize, -shadowSize);
5141                                 using(GraphicsPath brushPath = new GraphicsPath())
5142                                 {
5143                                         brushPath.AddEllipse(gradientPath);
5144
5145                                         // Create shadow path
5146                                         using(GraphicsPath path = new GraphicsPath())
5147                                         {
5148                                                 if(doughnutRadius < 0f)
5149                                                 {
5150                                                         path.AddPie(Rectangle.Round(gradientPath), startAngle, sweepAngle);
5151                                                 }
5152                                                 else
5153                                                 {
5154                                                         path.AddArc( 
5155                                                                 gradientPath.X + position.Width * doughnutRadius /200 - 1 - shadowSize, 
5156                                                                 gradientPath.Y + position.Height * doughnutRadius /200 - 1 - shadowSize, 
5157                                                                 gradientPath.Width - position.Width * doughnutRadius / 100 + 2 + 2f * shadowSize, 
5158                                                                 gradientPath.Height - position.Height * doughnutRadius / 100 + 2 + 2f * shadowSize, 
5159                                                                 startAngle, 
5160                                                                 sweepAngle );
5161                                                         path.AddArc( gradientPath.X, gradientPath.Y, gradientPath.Width, gradientPath.Height, startAngle + sweepAngle, -sweepAngle );
5162                                                 }
5163
5164                                                 // Create linear gradient brush
5165                                                 gradientPath.Inflate(1f, 1f);
5166                                                 using(LinearGradientBrush brush = new LinearGradientBrush(
5167                                                                   gradientPath, 
5168                                                                   Color.Red,
5169                                                                   Color.Green, 
5170                                                                   LinearGradientMode.Vertical) )
5171                                                 {
5172                                                         ColorBlend colorBlend = new ColorBlend(3);
5173                                                         colorBlend.Colors[0] = Color.FromArgb(100, Color.Black);
5174                                                         colorBlend.Colors[1] = Color.Transparent;
5175                                                         colorBlend.Colors[2] = Color.FromArgb(140, Color.White);
5176                                                         colorBlend.Positions[0] = 0f;
5177                                                         colorBlend.Positions[1] = 0.5f;
5178                                                         colorBlend.Positions[2] = 1f;
5179                                                         brush.InterpolationColors = colorBlend;
5180
5181                                                         // Fill shadow
5182                                                         this.FillPath( brush, path );
5183
5184                                                 }
5185                                         }
5186                                 }                       
5187                         }
5188                         else if(pieDrawingStyle == PieDrawingStyle.SoftEdge)
5189                         {
5190                                 // Calculate the size of the shadow. Note: For Doughnut chart shadow is drawn 
5191                                 // twice on the outside and inside radius.
5192                                 float minSize = (float)Math.Min(position.Width, position.Height);
5193                                 float shadowSize = minSize/10f;
5194                                 if(doughnutRadius > 0f)
5195                                 {
5196                                         shadowSize = (minSize * doughnutRadius / 100f) / 8f;
5197                                 }
5198
5199                                 // Create brush path
5200                                 using(GraphicsPath brushPath = new GraphicsPath())
5201                                 {
5202                                         brushPath.AddEllipse(position);
5203
5204                                         // Create shadow path
5205                                         using(GraphicsPath path = new GraphicsPath())
5206                                         {
5207                                                 path.AddArc( position.X + shadowSize, position.Y + shadowSize, position.Width - shadowSize * 2f, position.Height - shadowSize * 2f, startAngle, sweepAngle );
5208                                                 path.AddArc( position.X, position.Y, position.Width, position.Height, startAngle + sweepAngle, -sweepAngle );
5209                                                 path.CloseFigure();
5210
5211                                                 // Create shadow brush
5212                                                 using( PathGradientBrush brush = new PathGradientBrush(brushPath) )
5213                                                 {
5214                                                         brush.CenterColor = Color.Transparent;
5215                                                         brush.SurroundColors = new Color[] { Color.FromArgb(100, Color.Black) };
5216
5217                                                         Blend blend = new Blend(3);
5218                                                         blend.Positions[0] = 0f;
5219                                                         blend.Factors[0] = 0f;
5220                                                         blend.Positions[1] = shadowSize / (minSize / 2f);
5221                                                         blend.Factors[1] = 1f;
5222                                                         blend.Positions[2] = 1f;
5223                                                         blend.Factors[2] = 1f;
5224                                                         brush.Blend = blend;
5225
5226                                                         // Fill shadow
5227                                                         this.FillPath( brush, path );
5228                                                 }
5229                                         }
5230
5231                                         // Draw inner shadow for the doughnut chart
5232                                         if(doughnutRadius > 0f)
5233                                         {
5234                                                 // Create brush path
5235                                                 using(GraphicsPath brushInsidePath = new GraphicsPath())
5236                                                 {
5237                                                         RectangleF innerPosition = position;
5238                                                         innerPosition.Inflate(- position.Width * doughnutRadius / 200f + shadowSize, -position.Height * doughnutRadius / 200f + shadowSize);
5239                                                         brushInsidePath.AddEllipse(innerPosition);
5240
5241                                                         // Create shadow path
5242                                                         using(GraphicsPath path = new GraphicsPath())
5243                                                         {
5244                                                                 path.AddArc( innerPosition.X + shadowSize, innerPosition.Y + shadowSize, innerPosition.Width - 2f * shadowSize, innerPosition.Height - 2f * shadowSize, startAngle, sweepAngle );
5245                                                                 path.AddArc( innerPosition.X, innerPosition.Y, innerPosition.Width, innerPosition.Height, startAngle + sweepAngle, -sweepAngle );
5246                                                                 path.CloseFigure();
5247
5248                                                                 // Create shadow brush
5249                                                                 using( PathGradientBrush brushInner = new PathGradientBrush(brushInsidePath) )
5250                                                                 {
5251                                                                         brushInner.CenterColor = Color.FromArgb(100, Color.Black);
5252                                                                         brushInner.SurroundColors = new Color[] { Color.Transparent };
5253
5254                                                                         Blend blend = new Blend(3);
5255                                                                         blend.Positions[0] = 0f;
5256                                                                         blend.Factors[0] = 0f;
5257                                                                         blend.Positions[1] = shadowSize / (innerPosition.Width / 2f);
5258                                                                         blend.Factors[1] = 1f;
5259                                                                         blend.Positions[2] = 1f;
5260                                                                         blend.Factors[2] = 1f;
5261                                                                         brushInner.Blend = blend;
5262
5263                                                                         // Fill shadow
5264                                                                         this.FillPath( brushInner, path );
5265                                                                 }
5266                                                         }
5267                                                 }
5268                                         }
5269                                 }
5270                         }
5271                 }
5272
5273                 /// <summary>
5274                 /// The soft shadow of the pie 
5275                 /// </summary>
5276                 /// <param name="startAngle">Angle measured in degrees clockwise from the x-axis to the first side of the pie shape.</param>
5277                 /// <param name="sweepAngle">Angle measured in degrees clockwise from the startAngle parameter to the second side of the pie shape.</param>
5278                 /// <param name="absRect">Rectangle of the pie in absolute coordinates</param>
5279                 /// <param name="backColor">Fill color</param>
5280                 private void DrawPieSoftShadow( float startAngle, float sweepAngle, RectangleF absRect, Color backColor )
5281                 {
5282                         GraphicsPath path = new GraphicsPath();
5283                         
5284                         path.AddEllipse( absRect.X, absRect.Y, absRect.Width, absRect.Height );
5285
5286                         PathGradientBrush brush = new PathGradientBrush( path );
5287                 
5288                         Color[] colors = {
5289                                                                 Color.FromArgb( 0, backColor ),
5290                                                                 Color.FromArgb( backColor.A, backColor ),   
5291                                                                 Color.FromArgb( backColor.A, backColor )}; 
5292
5293                         float[] relativePositions = {
5294                                                                                         0f,       
5295                                                                                         0.05f,     
5296                                                                                         1.0f};    // at the center point.
5297
5298                         ColorBlend colorBlend = new ColorBlend();
5299                         colorBlend.Colors = colors;
5300                         colorBlend.Positions = relativePositions;
5301                         brush.InterpolationColors = colorBlend;
5302
5303                         this.FillPie( brush, absRect.X, absRect.Y, absRect.Width, absRect.Height, startAngle, sweepAngle );
5304                 }
5305
5306                 #endregion
5307
5308                 #region Arrow Methods
5309
5310                 /// <summary>
5311                 /// Draw Arrow.
5312                 /// </summary>
5313                 /// <param name="position">Position of the arrow</param>
5314                 /// <param name="orientation">Orientation of the arrow - left, right, top, bottom </param>
5315         /// <param name="type">Arrow style: Triangle, Sharp Triangle, Lines</param>
5316                 /// <param name="color">Color of the arrow</param>
5317                 /// <param name="lineWidth">Line width</param>
5318                 /// <param name="lineDashStyle">Line Dash style</param>
5319                 /// <param name="shift">Distance from the chart area</param>
5320                 /// <param name="size">Arrow size</param>
5321                 internal void DrawArrowRel( PointF position, ArrowOrientation orientation, AxisArrowStyle type, Color color, int lineWidth, ChartDashStyle lineDashStyle, double shift, double size )
5322                 {
5323                         // Check if arrow should be drawn
5324                         if(type == AxisArrowStyle.None)
5325                         {
5326                                 return;
5327                         }
5328
5329                         // Set a color
5330             using (SolidBrush brush = new SolidBrush(color))
5331             {
5332                 PointF endPoint = PointF.Empty; // End point of axis line
5333                 PointF[] points; // arrow points
5334                 PointF absolutePosition; // Absolute position of axis
5335
5336                 absolutePosition = GetAbsolutePoint(position);
5337
5338                 // Arrow type is triangle
5339                 if (type == AxisArrowStyle.Triangle)
5340                 {
5341                     points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
5342
5343                     endPoint = GetRelativePoint(endPoint);
5344
5345                     // Draw center line
5346                     DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
5347
5348                     // Draw arrow
5349                     this.FillPolygon(brush, points);
5350
5351                 }
5352                 // Arrow type is sharp triangle
5353                 else if (type == AxisArrowStyle.SharpTriangle)
5354                 {
5355                     points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
5356
5357                     endPoint = GetRelativePoint(endPoint);
5358
5359                     // Draw center line
5360                     DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
5361
5362                     // Draw arrow
5363                     this.FillPolygon(brush, points);
5364
5365                 }
5366                 // Arrow type is 'Lines'
5367                 else if (type == AxisArrowStyle.Lines)
5368                 {
5369                     points = GetArrowShape(absolutePosition, orientation, shift, size, type, ref endPoint);
5370
5371                     points[0] = GetRelativePoint(points[0]);
5372                     points[1] = GetRelativePoint(points[1]);
5373                     points[2] = GetRelativePoint(points[2]);
5374
5375                     endPoint = GetRelativePoint(endPoint);
5376
5377                     // Draw arrow
5378                     DrawLineRel(color, lineWidth, lineDashStyle, position, endPoint);
5379                     DrawLineRel(color, lineWidth, lineDashStyle, points[0], points[2]);
5380                     DrawLineRel(color, lineWidth, lineDashStyle, points[1], points[2]);
5381
5382                 }
5383             }
5384                 }
5385
5386                 /// <summary>
5387                 /// This function calculates points for polygon, which represents 
5388                 /// shape of an arrow. There are four different orientations 
5389                 /// of arrow and three arrow types.
5390                 /// </summary>
5391                 /// <param name="position">Arrow position</param>
5392                 /// <param name="orientation">Arrow orientation ( Left, Right, Top, Bottom )</param>
5393                 /// <param name="shift">Distance from chart area to the arrow</param>
5394                 /// <param name="size">Arrow size</param>
5395         /// <param name="type">Arrow style.</param>
5396                 /// <param name="endPoint">End point of the axis and the beginning of arrow</param>
5397                 /// <returns>Polygon points</returns>
5398                 private PointF[] GetArrowShape( PointF position, ArrowOrientation orientation, double shift, double size, AxisArrowStyle type, ref PointF endPoint )
5399                 {
5400                         PointF[] points = new PointF[3]; // Polygon points
5401                         double sharp; // Size for sharp triangle
5402
5403                         // Four different orientations for AxisArrowStyle
5404                         switch( orientation )
5405                         {
5406                                         // Top orientation
5407                                 case ArrowOrientation.Top:
5408                                         // Get absolute size for arrow
5409                                         // Arrow size has to have the same shape when width and height 
5410                                         // are changed. When the picture is resized, width of the chart 
5411                                         // picture is used only for arrow size.
5412                                         size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
5413                                         shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Height;
5414
5415                                         // Size for sharp and regular triangle
5416                                         if( type == AxisArrowStyle.SharpTriangle )
5417                                                 sharp = size * 4;
5418                                         else
5419                                                 sharp = size * 2;
5420
5421                                         points[0].X = position.X - (float)size;
5422                                         points[0].Y = position.Y - (float)shift;
5423                                         points[1].X = position.X + (float)size;
5424                                         points[1].Y = position.Y - (float)shift;
5425                                         points[2].X = position.X;
5426                                         points[2].Y = position.Y - (float)shift - (float)sharp;
5427                                         // End of the axis line
5428                                         endPoint.X = position.X;
5429                                         if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
5430                                                 endPoint.Y = points[1].Y;
5431                                         else
5432                                                 endPoint.Y = points[2].Y;
5433                                         
5434                                         break;
5435                                         // Bottom orientation
5436                                 case ArrowOrientation.Bottom:
5437                                         // Get absolute size for arrow
5438                                         // Arrow size has to have the same shape when width and height 
5439                                         // are changed. When the picture is resized, width of the chart 
5440                                         // picture is used only for arrow size.
5441                                         size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
5442                                         shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Height;
5443
5444                                         // Size for sharp and regular triangle
5445                                         if( type == AxisArrowStyle.SharpTriangle )
5446                                                 sharp = size * 4;
5447                                         else
5448                                                 sharp = size * 2;
5449
5450                                         points[0].X = position.X - (float)size;
5451                                         points[0].Y = position.Y + (float)shift;
5452                                         points[1].X = position.X + (float)size;
5453                                         points[1].Y = position.Y + (float)shift;
5454                                         points[2].X = position.X;
5455                                         points[2].Y = position.Y + (float)shift + (float)sharp;
5456                                         // End of the axis line
5457                                         endPoint.X = position.X;
5458                                         if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
5459                                                 endPoint.Y = points[1].Y;
5460                                         else
5461                                                 endPoint.Y = points[2].Y;
5462                                         break;
5463                                         // Left orientation
5464                                 case ArrowOrientation.Left:
5465                                         // Get absolute size for arrow
5466                                         size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
5467                                         shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Width;
5468
5469                                         // Size for sharp and regular triangle
5470                                         if( type == AxisArrowStyle.SharpTriangle )
5471                                                 sharp = size * 4;
5472                                         else
5473                                                 sharp = size * 2;
5474
5475                                         points[0].Y = position.Y - (float)size;
5476                                         points[0].X = position.X - (float)shift;
5477                                         points[1].Y = position.Y + (float)size;
5478                                         points[1].X = position.X - (float)shift;
5479                                         points[2].Y = position.Y;
5480                                         points[2].X = position.X - (float)shift - (float)sharp;
5481                                         // End of the axis line
5482                                         endPoint.Y = position.Y;
5483                                         if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
5484                                                 endPoint.X = points[1].X;
5485                                         else
5486                                                 endPoint.X = points[2].X;
5487                                         break;
5488                                         // Right orientation
5489                                 case ArrowOrientation.Right:
5490                                         // Get absolute size for arrow
5491                                         size = GetAbsoluteSize( new SizeF((float)size, (float)size) ).Width;
5492                                         shift = GetAbsoluteSize( new SizeF((float)shift,(float)shift) ).Width;
5493
5494                                         // Size for sharp and regular triangle
5495                                         if( type == AxisArrowStyle.SharpTriangle )
5496                                                 sharp = size * 4;
5497                                         else
5498                                                 sharp = size * 2;
5499
5500                                         points[0].Y = position.Y - (float)size;
5501                                         points[0].X = position.X + (float)shift;
5502                                         points[1].Y = position.Y + (float)size;
5503                                         points[1].X = position.X + (float)shift;
5504                                         points[2].Y = position.Y;
5505                                         points[2].X = position.X + (float)shift + (float)sharp;
5506                                         // End of the axis line
5507                                         endPoint.Y = position.Y;
5508                                         if( type == AxisArrowStyle.SharpTriangle || type == AxisArrowStyle.Triangle )
5509                                                 endPoint.X = points[1].X;
5510                                         else
5511                                                 endPoint.X = points[2].X;
5512                                         break;
5513                         }
5514
5515                         return points;
5516                 }
5517
5518                 #endregion
5519                 
5520                 #region Other methods and properties
5521
5522                 /// <summary>
5523                 /// Helper function that retrieves bar drawing style.
5524                 /// </summary>
5525                 /// <param name="point">Data point to get the drawing style for.</param>
5526                 /// <returns>Bar drawing style.</returns>
5527                 internal static BarDrawingStyle GetBarDrawingStyle(DataPoint point)
5528                 {
5529                         // Get column drawing style
5530                         BarDrawingStyle barDrawingStyle = BarDrawingStyle.Default;
5531                         string styleName = point[CustomPropertyName.DrawingStyle];
5532                         if(styleName != null)
5533                         {
5534                                 if(String.Compare(styleName, "Default", StringComparison.OrdinalIgnoreCase) == 0)
5535                                 {
5536                                         barDrawingStyle = BarDrawingStyle.Default;
5537                                 }
5538                 else if (String.Compare(styleName, "Cylinder", StringComparison.OrdinalIgnoreCase) == 0)
5539                                 {
5540                                         barDrawingStyle = BarDrawingStyle.Cylinder;
5541                                 }
5542                 else if (String.Compare(styleName, "Emboss", StringComparison.OrdinalIgnoreCase) == 0)
5543                                 {
5544                                         barDrawingStyle = BarDrawingStyle.Emboss;
5545                                 }
5546                 else if (String.Compare(styleName, "LightToDark", StringComparison.OrdinalIgnoreCase) == 0)
5547                                 {
5548                                         barDrawingStyle = BarDrawingStyle.LightToDark;
5549                                 }
5550                 else if (String.Compare(styleName, "Wedge", StringComparison.OrdinalIgnoreCase) == 0)
5551                                 {
5552                                         barDrawingStyle = BarDrawingStyle.Wedge;
5553                                 }
5554                                 else
5555                                 {
5556                     throw (new InvalidOperationException(SR.ExceptionCustomAttributeValueInvalid(styleName, "DrawingStyle")));
5557                                 }
5558                         }
5559                         return barDrawingStyle;
5560                 }
5561
5562
5563                 /// <summary>
5564                 /// Find rounding coordinates for a rectangle
5565                 /// </summary>
5566                 /// <param name="rect">Rectangle which has to be rounded</param>
5567                 /// <returns>Rounded rectangle</returns>
5568                 internal RectangleF Round(RectangleF rect)
5569                 {
5570                         float   left = (float)Math.Round( (double)rect.Left );
5571                         float   right = (float)Math.Round( (double)rect.Right );
5572                         float   top = (float)Math.Round( (double)rect.Top );
5573                         float   bottom = (float)Math.Round( (double)rect.Bottom );
5574
5575                         return new RectangleF( left, top, right - left, bottom - top ); 
5576                 }
5577                 
5578                 /// <summary>
5579         /// This method takes a given axis value for a specified axis and returns the relative pixel value.
5580                 /// </summary>
5581                 /// <param name="chartAreaName">Chart area name.</param>
5582         /// <param name="axis">An AxisName enum value that identifies the relevant axis.</param>
5583         /// <param name="axisValue">The axis value that needs to be converted to a relative pixel value.</param>
5584                 /// <returns>The converted axis value, in relative pixel coordinates.</returns>
5585                 public double GetPositionFromAxis( string chartAreaName, AxisName axis, double axisValue )
5586                 {
5587                         if( axis == AxisName.X )
5588                                 return _common.ChartPicture.ChartAreas[chartAreaName].AxisX.GetLinearPosition( axisValue );
5589
5590                         if( axis == AxisName.X2 )
5591                                 return _common.ChartPicture.ChartAreas[chartAreaName].AxisX2.GetLinearPosition( axisValue );
5592
5593                         if( axis == AxisName.Y )
5594                                 return _common.ChartPicture.ChartAreas[chartAreaName].AxisY.GetLinearPosition( axisValue );
5595
5596                         if( axis == AxisName.Y2 )
5597                                 return _common.ChartPicture.ChartAreas[chartAreaName].AxisY2.GetLinearPosition( axisValue );
5598
5599                         return 0;
5600                 }
5601
5602                 /// <summary>
5603                 /// Set picture size
5604                 /// </summary>
5605                 /// <param name="width">Width</param>
5606                 /// <param name="height">Height</param>
5607                 internal void SetPictureSize( int width, int height )
5608                 {
5609                         this._width = width;
5610                         this._height = height;
5611                 }
5612
5613                 /// <summary>
5614                 /// Constructor
5615                 /// </summary>
5616                 /// <param name="common">Common elements class</param>
5617                 internal ChartGraphics(CommonElements common)
5618                 {
5619                         // Set Common elements
5620                         this._common = common;
5621             base.Common = common;
5622                         // Create a pen object
5623                         _pen = new Pen(Color.Black);
5624
5625                         // Create a brush object
5626                         _solidBrush = new SolidBrush(Color.Black);
5627                 }
5628
5629                 /// <summary>
5630                 /// Chart Graphics Anti alias mode
5631                 /// </summary>
5632                 internal AntiAliasingStyles AntiAliasing
5633                 {
5634                         get
5635                         {
5636                                 return _antiAliasing;
5637                         }
5638                         set
5639                         {
5640                                 _antiAliasing = value;
5641
5642                                 // Graphics mode not set
5643                                 if( Graphics == null )
5644                                         return;
5645
5646                                 // Convert Chart's anti alias enumeration to GDI+ SmoothingMode
5647                                 if( (_antiAliasing & AntiAliasingStyles.Graphics) == AntiAliasingStyles.Graphics )
5648                                 {
5649                                         this.SmoothingMode = SmoothingMode.AntiAlias;
5650                                 }
5651                                 else
5652                                 {
5653                                         this.SmoothingMode = SmoothingMode.None;
5654                                 }
5655                         }
5656                 }
5657
5658         /// <summary>
5659         /// Gets reusable pen.
5660         /// </summary>
5661         internal Pen Pen
5662         {
5663             get { return _pen; }
5664         }
5665
5666                 /// <summary>
5667                 /// Sets the clipping region of this Graphics object 
5668                 /// to the rectangle specified by a RectangleF structure.
5669                 /// </summary>
5670                 /// <param name="region">Region rectangle</param>
5671                 internal void SetClip( RectangleF region )
5672                 {
5673                         this.SetClipAbs( GetAbsoluteRectangle( region ) );
5674                 }
5675         
5676                 #endregion
5677
5678                 #region Color manipulation methods
5679
5680         /// <summary>
5681         /// Returns the gradient color from a gradient position.
5682         /// </summary>
5683         /// <param name="beginColor">The color from the gradient beginning</param>
5684         /// <param name="endColor">The color from the gradient end.</param>
5685         /// <param name="relativePosition">The relative position.</param>
5686         /// <returns>Result color.</returns>
5687         static internal Color GetGradientColor(Color beginColor, Color endColor, double relativePosition)
5688                 {
5689                         // Check if position is valid
5690                         if(relativePosition < 0 || relativePosition > 1 || double.IsNaN(relativePosition))
5691                         {
5692                                 return beginColor;
5693                         }
5694                         
5695                         // Extracts Begin color
5696                         int nBRed = beginColor.R;
5697                         int nBGreen = beginColor.G;
5698                         int nBBlue = beginColor.B;
5699
5700                         // Extracts End color
5701                         int nERed = endColor.R;
5702                         int nEGreen = endColor.G;
5703                         int nEBlue = endColor.B;
5704
5705                         // Gradient positions for Red, Green and Blue colors
5706                         double dRRed = nBRed + (nERed - nBRed) * relativePosition;
5707                         double dRGreen = nBGreen + (nEGreen - nBGreen) * relativePosition;
5708                         double dRBlue = nBBlue + (nEBlue - nBBlue) * relativePosition;
5709
5710                         // Make sure colors are in range from 0 to 255
5711                         if(dRRed > 255.0)
5712                                 dRRed = 255.0;
5713                         if(dRRed < 0.0)
5714                                 dRRed = 0.0;
5715                         if(dRGreen > 255.0)
5716                                 dRGreen = 255.0;
5717                         if(dRGreen < 0.0)
5718                                 dRGreen = 0.0;
5719                         if(dRBlue > 255.0)
5720                                 dRBlue = 255.0;
5721                         if(dRBlue < 0.0)
5722                                 dRBlue = 0.0;
5723
5724                         // Return a gradient color position
5725                         return Color.FromArgb(beginColor.A, (int)dRRed, (int)dRGreen, (int)dRBlue);
5726                 }
5727
5728                 #endregion
5729
5730         #region RightToLeft
5731         /// <summary>
5732         /// Returns chart right to left flag 
5733         /// </summary>
5734         internal bool IsRightToLeft
5735         {
5736             get
5737             {
5738                 if (Common == null)
5739                 {
5740                     return false;
5741                 }
5742                 return Common.ChartPicture.RightToLeft == RightToLeft.Yes;
5743             }
5744         }
5745         
5746         #endregion //RightToLeft
5747
5748         #region IDisposable Members
5749         /// <summary>
5750         /// Releases unmanaged and - optionally - managed resources
5751         /// </summary>
5752         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
5753         protected override void Dispose(bool disposing)
5754         {
5755             if (disposing)
5756             {   
5757                 // Free up managed resources
5758                 if (_pen != null)
5759                 {
5760                     _pen.Dispose();
5761                     _pen = null;
5762                 }
5763                 if (_solidBrush != null)
5764                 {
5765                     _solidBrush.Dispose();
5766                     _solidBrush = null;
5767                 }
5768                 if (_myMatrix != null)
5769                 {
5770                     _myMatrix.Dispose();
5771                     _myMatrix = null;
5772                 }
5773             }
5774             base.Dispose(disposing);
5775         }
5776
5777         #endregion
5778     }
5779 }