/// <summary>
        /// Renders the minor items.
        /// </summary>
        /// <param name="axis">The axis.</param>
        /// <param name="axisPosition">The axis position.</param>
        protected virtual void RenderMinorItems(AxisBase axis, double axisPosition)
        {
            var eps           = axis.ActualMinorStep * 1e-3;
            var actualMinimum = axis.ActualMinimum;
            var actualMaximum = axis.ActualMaximum;

            var plotAreaLeft   = Editor.CurveArea.Left;
            var plotAreaRight  = Editor.CurveArea.Right;
            var plotAreaTop    = Editor.CurveArea.Top;
            var plotAreaBottom = Editor.CurveArea.Bottom;
            var isHorizontal   = axis.IsHorizontal();

            double a0;
            double a1;
            var    minorSegments     = new List <Point>();
            var    minorTickSegments = new List <Point>();

            GetTickPositions(axis, axis.TickStyle, axis.MinorTickSize, axis.Position, out a0, out a1);

            foreach (var value in MinorTickValues)
            {
                if (value < actualMinimum - eps || value > actualMaximum + eps)
                {
                    continue;
                }

                if (MajorTickValues.Contains(value))
                {
                    continue;
                }

                var transformedValue = axis.Transform(value);

                if (isHorizontal)
                {
                    SnapTo(plotAreaLeft, ref transformedValue);
                    SnapTo(plotAreaRight, ref transformedValue);
                }
                else
                {
                    SnapTo(plotAreaTop, ref transformedValue);
                    SnapTo(plotAreaBottom, ref transformedValue);
                }

                // Draw the minor grid line
                if (isHorizontal)
                {
                    minorSegments.Add(new Point(transformedValue, plotAreaTop));
                    minorSegments.Add(new Point(transformedValue, plotAreaBottom));
                }
                else
                {
                    minorSegments.Add(new Point(plotAreaLeft, transformedValue));
                    minorSegments.Add(new Point(plotAreaRight, transformedValue));
                }

                // Draw the minor tick
                if (axis.TickStyle != TickStyle.None && axis.MinorTickSize > 0)
                {
                    if (isHorizontal)
                    {
                        minorTickSegments.Add(new Point(transformedValue, axisPosition + a0));
                        minorTickSegments.Add(new Point(transformedValue, axisPosition + a1));
                    }
                    else
                    {
                        minorTickSegments.Add(new Point(axisPosition + a0, transformedValue));
                        minorTickSegments.Add(new Point(axisPosition + a1, transformedValue));
                    }
                }
            }

            // Draw all the line segments
            DrawingContext.DrawLineSegments(minorSegments, MinorColor);
            DrawingContext.DrawLineSegments(minorTickSegments, MinorTickColor);
        }
 /// <summary>
 /// Renders the axis title.
 /// </summary>
 /// <param name="axis">The axis.</param>
 /// <param name="titlePosition">The title position.</param>
 protected virtual void RenderAxisTitle(AxisBase axis, double titlePosition)
 {
     // TODO
 }
        /// <summary>
        /// Renders the major items.
        /// </summary>
        /// <param name="axis">The axis.</param>
        /// <param name="axisPosition">The axis position.</param>
        /// <param name="drawAxisLine">Draw the axis line if set to <c>true</c>.</param>
        protected virtual void RenderMajorItems(AxisBase axis, double axisPosition, bool drawAxisLine)
        {
            var eps = axis.ActualMinorStep * 1e-3;

            var actualMinimum = axis.ActualMinimum;
            var actualMaximum = axis.ActualMaximum;

            var plotAreaLeft   = Editor.CurveArea.Left;
            var plotAreaRight  = Editor.CurveArea.Right;
            var plotAreaTop    = Editor.CurveArea.Top;
            var plotAreaBottom = Editor.CurveArea.Bottom;
            var isHorizontal   = axis.IsHorizontal();

            double a0;
            double a1;
            var    majorSegments     = new List <Point>();
            var    majorTickSegments = new List <Point>();

            GetTickPositions(axis, axis.TickStyle, axis.MajorTickSize, axis.Position, out a0, out a1);

            foreach (var value in MajorTickValues)
            {
                if (value < actualMinimum - eps || value > actualMaximum + eps)
                {
                    continue;
                }

                var transformedValue = axis.Transform(value);
                if (isHorizontal)
                {
                    SnapTo(plotAreaLeft, ref transformedValue);
                    SnapTo(plotAreaRight, ref transformedValue);
                }
                else
                {
                    SnapTo(plotAreaTop, ref transformedValue);
                    SnapTo(plotAreaBottom, ref transformedValue);
                }

                if (isHorizontal)
                {
                    majorSegments.Add(new Point(transformedValue, plotAreaTop));
                    majorSegments.Add(new Point(transformedValue, plotAreaBottom));
                }
                else
                {
                    majorSegments.Add(new Point(plotAreaLeft, transformedValue));
                    majorSegments.Add(new Point(plotAreaRight, transformedValue));
                }

                if (axis.TickStyle != TickStyle.None && axis.MajorTickSize > 0)
                {
                    if (isHorizontal)
                    {
                        majorTickSegments.Add(new Point(transformedValue, axisPosition + a0));
                        majorTickSegments.Add(new Point(transformedValue, axisPosition + a1));
                    }
                    else
                    {
                        majorTickSegments.Add(new Point(axisPosition + a0, transformedValue));
                        majorTickSegments.Add(new Point(axisPosition + a1, transformedValue));
                    }
                }
            }

            // Render the axis labels (numbers or category names)
            var hAlign = HorizontalAlignment.Left;
            var vAlign = VerticalAlignment.Top;

            switch (axis.Position)
            {
            case AxisPosition.Left:
                hAlign = HorizontalAlignment.Right;
                vAlign = VerticalAlignment.Center;
                break;

            case AxisPosition.Right:
                hAlign = HorizontalAlignment.Left;
                vAlign = VerticalAlignment.Center;
                break;

            case AxisPosition.Top:
                hAlign = HorizontalAlignment.Center;
                vAlign = VerticalAlignment.Bottom;
                break;

            case AxisPosition.Bottom:
                hAlign = HorizontalAlignment.Center;
                vAlign = VerticalAlignment.Top;
                break;

            case AxisPosition.None:
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
            var texts         = new List <string>();
            var textPositions = new List <Point>();

            foreach (var value in MajorLabelValues)
            {
                if (value < actualMinimum - eps || value > actualMaximum + eps)
                {
                    continue;
                }

                var transformedValue = axis.Transform(value);
                if (isHorizontal)
                {
                    SnapTo(plotAreaLeft, ref transformedValue);
                    SnapTo(plotAreaRight, ref transformedValue);
                }
                else
                {
                    SnapTo(plotAreaTop, ref transformedValue);
                    SnapTo(plotAreaBottom, ref transformedValue);
                }

                var point = new Point();
                switch (axis.Position)
                {
                case AxisPosition.Left:
                    point = new Point(axisPosition + a1 - axis.AxisTickToLabelDistance, transformedValue);
                    break;

                case AxisPosition.Right:
                    point = new Point(axisPosition + a1 + axis.AxisTickToLabelDistance, transformedValue);
                    break;

                case AxisPosition.Top:
                    point = new Point(transformedValue, axisPosition + a1 - axis.AxisTickToLabelDistance);
                    break;

                case AxisPosition.Bottom:
                    point = new Point(transformedValue, axisPosition + a1 + axis.AxisTickToLabelDistance);
                    break;

                case AxisPosition.None:
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                var text = axis.FormatValue(value);
                texts.Add(text);
                textPositions.Add(point);
            }
            // Batch all the texts together
            DrawingContext.DrawTexts(textPositions, TextColor, texts, axis.FontFamily, axis.FontSize, axis.FontWeight, hAlign, vAlign);

            if (drawAxisLine)
            {
                // Draw the axis line (across the tick marks)
                if (isHorizontal)
                {
                    DrawingContext.DrawLine(new Point(axis.Transform(actualMinimum), axisPosition), new Point(axis.Transform(actualMaximum), axisPosition), AxislineColor);
                }
                else
                {
                    DrawingContext.DrawLine(new Point(axisPosition, axis.Transform(actualMinimum)), new Point(axisPosition, axis.Transform(actualMaximum)), AxislineColor);
                }
            }
            DrawingContext.DrawLineSegments(majorSegments, MajorColor, 2);
            DrawingContext.DrawLineSegments(majorTickSegments, MajorTickColor, 2);
        }
        /// <summary>
        /// Renders the specified axis.
        /// </summary>
        /// <param name="axis">The axis.</param>
        /// <param name="pass">The pass.</param>
        public void Render(AxisBase axis, int pass)
        {
            if (axis == null)
            {
                throw new ArgumentNullException(nameof(axis));
            }

            axis.GetTickValues(out majorLabelValues, out majorTickValues, out minorTickValues);
            var totalShift = axis.AxisDistance + axis.PositionTierMinShift;
            var tierSize   = axis.PositionTierSize - Editor.AxisTierDistance;

            // store properties locally for performance
            var plotAreaLeft   = Editor.CurveArea.Left;
            var plotAreaRight  = Editor.CurveArea.Right;
            var plotAreaTop    = Editor.CurveArea.Top;
            var plotAreaBottom = Editor.CurveArea.Bottom;

            // Axis position (x or y screen coordinate)
            double axisPosition  = 0;
            double titlePosition = 0;

            switch (axis.Position)
            {
            case AxisPosition.Left:
                axisPosition  = plotAreaLeft - totalShift;
                titlePosition = axisPosition - tierSize;
                break;

            case AxisPosition.Right:
                axisPosition  = plotAreaRight + totalShift;
                titlePosition = axisPosition + tierSize;
                break;

            case AxisPosition.Top:
                axisPosition  = plotAreaTop - totalShift;
                titlePosition = axisPosition - tierSize;
                break;

            case AxisPosition.Bottom:
                axisPosition  = plotAreaBottom + totalShift;
                titlePosition = axisPosition + tierSize;
                break;

            case AxisPosition.None:
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (pass == 0)
            {
                RenderMinorItems(axis, axisPosition);
            }

            if (pass == 1)
            {
                RenderMajorItems(axis, axisPosition, true);
                RenderAxisTitle(axis, titlePosition);
            }
        }