/// <summary>
        /// Gets position of the axis break line. Break line may be shown as a single
        /// line or two lines separated with a spacing.
        /// </summary>
        /// <param name="graph">Chart graphics.</param>
        /// <param name="nextSegment">Next segment reference.</param>
        /// <returns>Position of the axis break line in pixel coordinates.</returns>
        internal RectangleF GetBreakLinePosition(ChartGraphics graph, AxisScaleSegment nextSegment)
        {
            // Start with the plotting rectangle position
            RectangleF breakPosition = this.axis.PlotAreaPosition.ToRectangleF();

            // Find maximum scale value of the current segment and minimuj of the next
            double from = this.axis.GetLinearPosition(nextSegment.ScaleMinimum);
            double to   = this.axis.GetLinearPosition(this.ScaleMaximum);

            if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left)
            {
                breakPosition.Y      = (float)Math.Min(from, to);
                breakPosition.Height = (float)Math.Max(from, to);
            }
            else
            {
                breakPosition.X     = (float)Math.Min(from, to);
                breakPosition.Width = (float)Math.Max(from, to);;
            }

            // Convert to pixels
            breakPosition = Rectangle.Round(graph.GetAbsoluteRectangle(breakPosition));

            // Add border width
            if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left)
            {
                breakPosition.Height = (float)Math.Abs(breakPosition.Y - breakPosition.Height);
                breakPosition.X     -= this.axis.ChartArea.BorderWidth;
                breakPosition.Width += 2 * this.axis.ChartArea.BorderWidth;
            }
            else
            {
                breakPosition.Width   = (float)Math.Abs(breakPosition.X - breakPosition.Width);
                breakPosition.Y      -= this.axis.ChartArea.BorderWidth;
                breakPosition.Height += 2 * this.axis.ChartArea.BorderWidth;
            }

            return(breakPosition);
        }
        /// <summary>
        /// Paints the axis break line.
        /// </summary>
        /// <param name="graph">Chart graphics to use.</param>
        /// <param name="nextSegment">Axis scale segment next to current.</param>
        internal void PaintBreakLine(ChartGraphics graph, AxisScaleSegment nextSegment)
        {
            // Get break line position
            RectangleF breakPosition = this.GetBreakLinePosition(graph, nextSegment);

            // Get top line graphics path
            GraphicsPath breakLinePathTop    = this.GetBreakLinePath(breakPosition, true);
            GraphicsPath breakLinePathBottom = null;

            // Clear break line space using chart color behind the area
            if (breakPosition.Width > 0f && breakPosition.Height > 0f)
            {
                // Get bottom line graphics path
                breakLinePathBottom = this.GetBreakLinePath(breakPosition, false);

                // Clear plotting area background
                using (GraphicsPath fillPath = new GraphicsPath())
                {
                    // Create fill path out of top and bottom break lines
                    fillPath.AddPath(breakLinePathTop, true);
                    fillPath.Reverse();
                    fillPath.AddPath(breakLinePathBottom, true);
                    fillPath.CloseAllFigures();

                    // Use chart back color to fill the area
                    using (Brush fillBrush = this.GetChartFillBrush(graph))
                    {
                        graph.FillPath(fillBrush, fillPath);

                        // Check if shadow exsits in chart area
                        if (this.axis.ChartArea.ShadowOffset != 0 && !this.axis.ChartArea.ShadowColor.IsEmpty)
                        {
                            // Clear shadow
                            RectangleF shadowPartRect = breakPosition;
                            if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left)
                            {
                                shadowPartRect.Y      += this.axis.ChartArea.ShadowOffset;
                                shadowPartRect.Height -= this.axis.ChartArea.ShadowOffset;
                                shadowPartRect.X       = shadowPartRect.Right - 1;
                                shadowPartRect.Width   = this.axis.ChartArea.ShadowOffset + 2;
                            }
                            else
                            {
                                shadowPartRect.X     += this.axis.ChartArea.ShadowOffset;
                                shadowPartRect.Width -= this.axis.ChartArea.ShadowOffset;
                                shadowPartRect.Y      = shadowPartRect.Bottom - 1;
                                shadowPartRect.Height = this.axis.ChartArea.ShadowOffset + 2;
                            }
                            graph.FillRectangle(fillBrush, shadowPartRect);

                            // Draw new shadow
                            using (GraphicsPath shadowPath = new GraphicsPath())
                            {
                                shadowPath.AddPath(breakLinePathTop, false);

                                // Define maximum size
                                float size = this.axis.ChartArea.ShadowOffset;
                                if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left)
                                {
                                    size = Math.Min(size, breakPosition.Height);
                                }
                                else
                                {
                                    size = Math.Min(size, breakPosition.Width);
                                }

                                // Define step to increase transperancy
                                int transparencyStep = (int)(this.axis.ChartArea.ShadowColor.A / size);

                                // Set clip region to achieve spacing of the shadow
                                // Start with the plotting rectangle position
                                RectangleF clipRegion = graph.GetAbsoluteRectangle(this.axis.PlotAreaPosition.ToRectangleF());
                                if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left)
                                {
                                    clipRegion.X     += this.axis.ChartArea.ShadowOffset;
                                    clipRegion.Width += this.axis.ChartArea.ShadowOffset;
                                }
                                else
                                {
                                    clipRegion.Y      += this.axis.ChartArea.ShadowOffset;
                                    clipRegion.Height += this.axis.ChartArea.ShadowOffset;
                                }
                                graph.SetClip(graph.GetRelativeRectangle(clipRegion));

                                // Draw several lines to form shadow
                                for (int index = 0; index < size; index++)
                                {
                                    using (Matrix newMatrix = new Matrix())
                                    {
                                        // Shift top break line by 1 pixel
                                        if (this.axis.AxisPosition == AxisPosition.Right || this.axis.AxisPosition == AxisPosition.Left)
                                        {
                                            newMatrix.Translate(0f, 1f);
                                        }
                                        else
                                        {
                                            newMatrix.Translate(1f, 0f);
                                        }
                                        shadowPath.Transform(newMatrix);
                                    }

                                    // Get line color
                                    Color color = Color.FromArgb(
                                        this.axis.ChartArea.ShadowColor.A - transparencyStep * index,
                                        this.axis.ChartArea.ShadowColor);

                                    using (Pen shadowPen = new Pen(color, 1))
                                    {
                                        // Draw shadow
                                        graph.DrawPath(shadowPen, shadowPath);
                                    }
                                }

                                graph.ResetClip();
                            }
                        }
                    }
                }
            }

            // Draw Separator Line(s)
            if (this.axis.ScaleBreakStyle.BreakLineStyle != BreakLineStyle.None)
            {
                using (Pen pen = new Pen(this.axis.ScaleBreakStyle.LineColor, this.axis.ScaleBreakStyle.LineWidth))
                {
                    // Set line style
                    pen.DashStyle = graph.GetPenStyle(this.axis.ScaleBreakStyle.LineDashStyle);

                    // Draw break lines
                    graph.DrawPath(pen, breakLinePathTop);
                    if (breakPosition.Width > 0f && breakPosition.Height > 0f)
                    {
                        graph.DrawPath(pen, breakLinePathBottom);
                    }
                }
            }

            // Dispose break line paths
            breakLinePathTop.Dispose();
            breakLinePathTop = null;
            if (breakLinePathBottom != null)
            {
                breakLinePathBottom.Dispose();
                breakLinePathBottom = null;
            }
        }
 /// <summary>
 /// Helper method which calculates chart area plotting position in pixels.
 /// </summary>
 /// <param name="area">Chart area to get the plotting area position.</param>
 /// <param name="chartGraphics">Chart graphics object.</param>
 /// <returns>Chart area ploting area position in pixels.</returns>
 private RectangleF GetChartAreaPlottingPosition(ChartArea area, ChartGraphics chartGraphics)
 {
     RectangleF plottingRect = area.Position.ToRectangleF();
     plottingRect.X += (area.Position.Width / 100F) * area.InnerPlotPosition.X;
     plottingRect.Y += (area.Position.Height / 100F) * area.InnerPlotPosition.Y;
     plottingRect.Width = (area.Position.Width / 100F) * area.InnerPlotPosition.Width;
     plottingRect.Height = (area.Position.Height / 100F) * area.InnerPlotPosition.Height;
     plottingRect = chartGraphics.GetAbsoluteRectangle(plottingRect);
     return plottingRect;
 }
        /// <summary>
        /// Get arrow path for the specified annotation position
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        private GraphicsPath GetArrowPath(
            ChartGraphics graphics,
            RectangleF position)
        {
            // Get absolute position
            RectangleF positionAbs = graphics.GetAbsoluteRectangle(position);
            PointF     firstPoint  = positionAbs.Location;
            PointF     secondPoint = new PointF(positionAbs.Right, positionAbs.Bottom);

            // Calculate arrow length
            float deltaX      = secondPoint.X - firstPoint.X;
            float deltaY      = secondPoint.Y - firstPoint.Y;
            float arrowLength = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);

            // Create unrotated graphics path for the arrow started at the annotation location
            // and going to the right for the length of the rotated arrow.
            GraphicsPath path = new GraphicsPath();

            PointF[] points       = null;
            float    pointerRatio = 2.1f;

            if (this.ArrowStyle == ArrowStyle.Simple)
            {
                points = new PointF[] {
                    firstPoint,
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y - this.ArrowSize * pointerRatio),
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y - this.ArrowSize),
                    new PointF(firstPoint.X + arrowLength, firstPoint.Y - this.ArrowSize),
                    new PointF(firstPoint.X + arrowLength, firstPoint.Y + this.ArrowSize),
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y + this.ArrowSize),
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y + this.ArrowSize * pointerRatio)
                };
            }
            else if (this.ArrowStyle == ArrowStyle.DoubleArrow)
            {
                points = new PointF[] {
                    firstPoint,
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y - this.ArrowSize * pointerRatio),
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y - this.ArrowSize),
                    new PointF(firstPoint.X + arrowLength - this.ArrowSize * pointerRatio, firstPoint.Y - this.ArrowSize),
                    new PointF(firstPoint.X + arrowLength - this.ArrowSize * pointerRatio, firstPoint.Y - this.ArrowSize * pointerRatio),
                    new PointF(firstPoint.X + arrowLength, firstPoint.Y),
                    new PointF(firstPoint.X + arrowLength - this.ArrowSize * pointerRatio, firstPoint.Y + this.ArrowSize * pointerRatio),
                    new PointF(firstPoint.X + arrowLength - this.ArrowSize * pointerRatio, firstPoint.Y + this.ArrowSize),
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y + this.ArrowSize),
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y + this.ArrowSize * pointerRatio)
                };
            }
            else if (this.ArrowStyle == ArrowStyle.Tailed)
            {
                float tailRatio = 2.1f;
                points = new PointF[] {
                    firstPoint,
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y - this.ArrowSize * pointerRatio),
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y - this.ArrowSize),
                    new PointF(firstPoint.X + arrowLength, firstPoint.Y - this.ArrowSize * tailRatio),
                    new PointF(firstPoint.X + arrowLength - this.ArrowSize * tailRatio, firstPoint.Y),
                    new PointF(firstPoint.X + arrowLength, firstPoint.Y + this.ArrowSize * tailRatio),
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y + this.ArrowSize),
                    new PointF(firstPoint.X + this.ArrowSize * pointerRatio, firstPoint.Y + this.ArrowSize * pointerRatio)
                };
            }
            else
            {
                throw (new InvalidOperationException(SR.ExceptionAnnotationArrowStyleUnknown));
            }

            path.AddLines(points);
            path.CloseAllFigures();

            // Calculate arrow angle
            float angle = (float)(Math.Atan(deltaY / deltaX) * 180f / Math.PI);

            if (deltaX < 0)
            {
                angle += 180f;
            }

            // Rotate arrow path around the first point
            using (Matrix matrix = new Matrix())
            {
                matrix.RotateAt(angle, firstPoint);
                path.Transform(matrix);
            }

            return(path);
        }
        /// <summary>
        /// Paints the annotation object on the specified graphics.
        /// </summary>
        /// <param name="graphics">
        /// A <see cref="ChartGraphics"/>
        /// </param>
        /// <param name="chart">
        /// Reference to the <see cref="Chart"/> control that owns the annotation.
        /// </param>
        override internal void Paint(Chart chart, ChartGraphics graphics)
        {
            // Get annotation position in relative coordinates
            PointF firstPoint  = PointF.Empty;
            PointF anchorPoint = PointF.Empty;
            SizeF  size        = SizeF.Empty;

            GetRelativePosition(out firstPoint, out size, out anchorPoint);
            PointF secondPoint = new PointF(firstPoint.X + size.Width, firstPoint.Y + size.Height);

            // Create selection rectangle
            RectangleF selectionRect = new RectangleF(firstPoint, new SizeF(secondPoint.X - firstPoint.X, secondPoint.Y - firstPoint.Y));

            // Get text position
            RectangleF rectanglePosition = new RectangleF(selectionRect.Location, selectionRect.Size);

            if (rectanglePosition.Width < 0)
            {
                rectanglePosition.X     = rectanglePosition.Right;
                rectanglePosition.Width = -rectanglePosition.Width;
            }
            if (rectanglePosition.Height < 0)
            {
                rectanglePosition.Y      = rectanglePosition.Bottom;
                rectanglePosition.Height = -rectanglePosition.Height;
            }

            // Check if position is valid
            if (float.IsNaN(rectanglePosition.X) ||
                float.IsNaN(rectanglePosition.Y) ||
                float.IsNaN(rectanglePosition.Right) ||
                float.IsNaN(rectanglePosition.Bottom))
            {
                return;
            }

            if (this.Common.ProcessModePaint)
            {
                // Do not draw border if size is less that 10 pixels
                RectangleF absRectanglePosition = graphics.GetAbsoluteRectangle(rectanglePosition);
                if (absRectanglePosition.Width > 30f &&
                    absRectanglePosition.Height > 30f)
                {
                    // Draw rectangle
                    graphics.Draw3DBorderRel(
                        _borderSkin,
                        rectanglePosition,
                        this.BackColor,
                        this.BackHatchStyle,
                        String.Empty,
                        ChartImageWrapMode.Scaled,
                        Color.Empty,
                        ChartImageAlignmentStyle.Center,
                        this.BackGradientStyle,
                        this.BackSecondaryColor,
                        this.LineColor,
                        this.LineWidth,
                        this.LineDashStyle);
                }
            }

            // Call base class to paint text, selection handles and process hot regions
            base.Paint(chart, graphics);
        }
        /// <summary>
        /// Draws text in specified rectangle.
        /// </summary>
        /// <param name="graphics">Chart graphics.</param>
        /// <param name="textPosition">Text position.</param>
        /// <param name="noSpacingForCenteredText">True if text allowed to be outside of position when centered.</param>
        /// <param name="getTextPosition">True if position text must be returned by the method.</param>
        /// <returns>Text actual position if required.</returns>
        internal RectangleF DrawText(ChartGraphics graphics, RectangleF textPosition, bool noSpacingForCenteredText, bool getTextPosition)
        {
            RectangleF textActualPosition = RectangleF.Empty;

            //***************************************************************
            //** Adjust text position uing text spacing
            //***************************************************************
            bool       annotationRelative = false;
            RectangleF textSpacing        = GetTextSpacing(out annotationRelative);
            float      spacingScaleX      = 1f;
            float      spacingScaleY      = 1f;

            if (annotationRelative)
            {
                if (textPosition.Width > 25f)
                {
                    spacingScaleX = textPosition.Width / 50f;
                    spacingScaleX = Math.Max(1f, spacingScaleX);
                }
                if (textPosition.Height > 25f)
                {
                    spacingScaleY = textPosition.Height / 50f;
                    spacingScaleY = Math.Max(1f, spacingScaleY);
                }
            }

            RectangleF textPositionWithSpacing = new RectangleF(textPosition.Location, textPosition.Size);

            textPositionWithSpacing.Width  -= (textSpacing.Width + textSpacing.X) * spacingScaleX;
            textPositionWithSpacing.X      += textSpacing.X * spacingScaleX;
            textPositionWithSpacing.Height -= (textSpacing.Height + textSpacing.Y) * spacingScaleY;
            textPositionWithSpacing.Y      += textSpacing.Y * spacingScaleY;

            //***************************************************************
            //** Replace new line characters
            //***************************************************************
            string titleText = this.ReplaceKeywords(this.Text.Replace("\\n", "\n"));

            //***************************************************************
            //** Check if centered text require spacing.
            //** Use only half of the spacing required.
            //** Apply only for 1 line of text.
            //***************************************************************
            if (noSpacingForCenteredText &&
                titleText.IndexOf('\n') == -1)
            {
                if (this.Alignment == ContentAlignment.MiddleCenter ||
                    this.Alignment == ContentAlignment.MiddleLeft ||
                    this.Alignment == ContentAlignment.MiddleRight)
                {
                    textPositionWithSpacing.Y       = textPosition.Y;
                    textPositionWithSpacing.Height  = textPosition.Height;
                    textPositionWithSpacing.Height -= textSpacing.Height / 2f + textSpacing.Y / 2f;
                    textPositionWithSpacing.Y      += textSpacing.Y / 2f;
                }
                if (this.Alignment == ContentAlignment.BottomCenter ||
                    this.Alignment == ContentAlignment.MiddleCenter ||
                    this.Alignment == ContentAlignment.TopCenter)
                {
                    textPositionWithSpacing.X      = textPosition.X;
                    textPositionWithSpacing.Width  = textPosition.Width;
                    textPositionWithSpacing.Width -= textSpacing.Width / 2f + textSpacing.X / 2f;
                    textPositionWithSpacing.X     += textSpacing.X / 2f;
                }
            }

            // Draw text
            using (Brush textBrush = new SolidBrush(this.ForeColor))
            {
                using (StringFormat format = new StringFormat(StringFormat.GenericTypographic))
                {
                    //***************************************************************
                    //** Set text format
                    //***************************************************************
                    format.FormatFlags = format.FormatFlags ^ StringFormatFlags.LineLimit;
                    format.Trimming    = StringTrimming.EllipsisCharacter;
                    if (this.Alignment == ContentAlignment.BottomRight ||
                        this.Alignment == ContentAlignment.MiddleRight ||
                        this.Alignment == ContentAlignment.TopRight)
                    {
                        format.Alignment = StringAlignment.Far;
                    }
                    if (this.Alignment == ContentAlignment.BottomCenter ||
                        this.Alignment == ContentAlignment.MiddleCenter ||
                        this.Alignment == ContentAlignment.TopCenter)
                    {
                        format.Alignment = StringAlignment.Center;
                    }
                    if (this.Alignment == ContentAlignment.BottomCenter ||
                        this.Alignment == ContentAlignment.BottomLeft ||
                        this.Alignment == ContentAlignment.BottomRight)
                    {
                        format.LineAlignment = StringAlignment.Far;
                    }
                    if (this.Alignment == ContentAlignment.MiddleCenter ||
                        this.Alignment == ContentAlignment.MiddleLeft ||
                        this.Alignment == ContentAlignment.MiddleRight)
                    {
                        format.LineAlignment = StringAlignment.Center;
                    }

                    //***************************************************************
                    //** Set shadow color and offset
                    //***************************************************************
                    Color     textShadowColor  = ChartGraphics.GetGradientColor(this.ForeColor, Color.Black, 0.8);
                    int       textShadowOffset = 1;
                    TextStyle textStyle        = this.TextStyle;
                    if (textStyle == TextStyle.Shadow &&
                        ShadowOffset != 0)
                    {
                        // Draw shadowed text
                        textShadowColor  = ShadowColor;
                        textShadowOffset = ShadowOffset;
                    }

                    if (textStyle == TextStyle.Shadow)
                    {
                        textShadowColor = (textShadowColor.A != 255) ? textShadowColor : Color.FromArgb(textShadowColor.A / 2, textShadowColor);
                    }

                    //***************************************************************
                    //** Get text actual position
                    //***************************************************************
                    if (getTextPosition)
                    {
                        // Measure text size
                        SizeF textSize = graphics.MeasureStringRel(
                            this.ReplaceKeywords(_text.Replace("\\n", "\n")),
                            this.Font,
                            textPositionWithSpacing.Size,
                            format);

                        // Get text position
                        textActualPosition = new RectangleF(textPositionWithSpacing.Location, textSize);
                        if (this.Alignment == ContentAlignment.BottomRight ||
                            this.Alignment == ContentAlignment.MiddleRight ||
                            this.Alignment == ContentAlignment.TopRight)
                        {
                            textActualPosition.X += textPositionWithSpacing.Width - textSize.Width;
                        }
                        if (this.Alignment == ContentAlignment.BottomCenter ||
                            this.Alignment == ContentAlignment.MiddleCenter ||
                            this.Alignment == ContentAlignment.TopCenter)
                        {
                            textActualPosition.X += (textPositionWithSpacing.Width - textSize.Width) / 2f;
                        }
                        if (this.Alignment == ContentAlignment.BottomCenter ||
                            this.Alignment == ContentAlignment.BottomLeft ||
                            this.Alignment == ContentAlignment.BottomRight)
                        {
                            textActualPosition.Y += textPositionWithSpacing.Height - textSize.Height;
                        }
                        if (this.Alignment == ContentAlignment.MiddleCenter ||
                            this.Alignment == ContentAlignment.MiddleLeft ||
                            this.Alignment == ContentAlignment.MiddleRight)
                        {
                            textActualPosition.Y += (textPositionWithSpacing.Height - textSize.Height) / 2f;
                        }

                        // Do not allow text to go outside annotation position
                        textActualPosition.Intersect(textPositionWithSpacing);
                    }

                    RectangleF absPosition = graphics.GetAbsoluteRectangle(textPositionWithSpacing);
                    Title.DrawStringWithStyle(
                        graphics,
                        titleText,
                        this.TextStyle,
                        this.Font,
                        absPosition,
                        this.ForeColor,
                        textShadowColor,
                        textShadowOffset,
                        format,
                        TextOrientation.Auto
                        );
                }
            }

            return(textActualPosition);
        }