コード例 #1
0
ファイル: AxisRenderer.cs プロジェクト: ylatuya/oxyplot
        public void Render(Axis axis)
        {
            if (axis == null)
            {
                return;
            }

            axis.GetTickValues(out majorTickValues, out minorTickValues);

            CreatePens(axis);

            if (axis.IsHorizontal())
            {
                RenderHorizontalAxis(axis, Plot.DefaultYAxis);
            }
            if (axis.IsVertical())
            {
                RenderVerticalAxis(axis, Plot.DefaultXAxis);
            }
            if (axis.Position == AxisPosition.Angle)
            {
                RenderAngleAxis(axis, Plot.DefaultMagnitudeAxis);
            }
            if (axis.Position == AxisPosition.Magnitude)
            {
                RenderMagnitudeAxis(axis, Plot.DefaultAngleAxis);
            }
        }
コード例 #2
0
        public void Render(Axis axis)
        {
            if (axis == null)
                return;

            axis.GetTickValues(out majorTickValues, out minorTickValues);

            CreatePens(axis);

            if (axis.IsHorizontal())
            {
                RenderHorizontalAxis(axis, Plot.DefaultYAxis);
            }
            if (axis.IsVertical())
            {
                RenderVerticalAxis(axis, Plot.DefaultXAxis);
            }
            if (axis.Position == AxisPosition.Angle)
            {
                RenderAngleAxis(axis, Plot.DefaultMagnitudeAxis);
            }
            if (axis.Position == AxisPosition.Magnitude)
            {
                RenderMagnitudeAxis(axis, Plot.DefaultAngleAxis);
            }
        }
        /// <summary>
        /// Renders the specified axis.
        /// </summary>
        /// <param name="axis">The axis.</param>
        /// <param name="pass">The pass.</param>
        public override void Render(Axis axis, int pass)
        {
            base.Render(axis, pass);

            double totalShift = axis.PositionTierMinShift;
            double tierSize   = axis.PositionTierSize - this.Plot.AxisTierDistance;

            // store properties locally for performance
            double plotAreaLeft   = this.Plot.PlotArea.Left;
            double plotAreaRight  = this.Plot.PlotArea.Right;
            double plotAreaTop    = this.Plot.PlotArea.Top;
            double plotAreaBottom = this.Plot.PlotArea.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;
            }

            if (axis.PositionAtZeroCrossing)
            {
                var perpendicularAxis = axis.IsHorizontal() ? this.Plot.DefaultYAxis : this.Plot.DefaultXAxis;
                axisPosition = perpendicularAxis.Transform(0);
            }

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

            if (pass == 1)
            {
                this.RenderMajorItems(axis, axisPosition, titlePosition);
            }
        }
        /// <summary>
        /// Gets the axis title position, rotation and alignment.
        /// </summary>
        /// <param name="axis">
        /// The axis.
        /// </param>
        /// <param name="titlePosition">
        /// The title position.
        /// </param>
        /// <param name="angle">
        /// The angle.
        /// </param>
        /// <param name="halign">
        /// The horizontal alignment.
        /// </param>
        /// <param name="valign">
        /// The vertical alignment.
        /// </param>
        /// <returns>
        /// The <see cref="ScreenPoint"/>.
        /// </returns>
        protected virtual ScreenPoint GetAxisTitlePositionAndAlignment(
            Axis axis,
            double titlePosition,
            ref double angle,
            ref HorizontalAlignment halign,
            ref VerticalAlignment valign)
        {
            double middle = axis.IsHorizontal()
                                ? Lerp(axis.ScreenMin.X, axis.ScreenMax.X, axis.TitlePosition)
                                : Lerp(axis.ScreenMax.Y, axis.ScreenMin.Y, axis.TitlePosition);

            if (axis.PositionAtZeroCrossing)
            {
                var perpendicularAxis = axis.IsHorizontal() ? this.Plot.DefaultYAxis : this.Plot.DefaultXAxis;
                middle = perpendicularAxis.Transform(perpendicularAxis.ActualMaximum);
            }

            switch (axis.Position)
            {
            case AxisPosition.Left:
                return(new ScreenPoint(titlePosition, middle));

            case AxisPosition.Right:
                valign = VerticalAlignment.Bottom;
                return(new ScreenPoint(titlePosition, middle));

            case AxisPosition.Top:
                halign = HorizontalAlignment.Center;
                valign = VerticalAlignment.Top;
                angle  = 0;
                return(new ScreenPoint(middle, titlePosition));

            case AxisPosition.Bottom:
                halign = HorizontalAlignment.Center;
                valign = VerticalAlignment.Bottom;
                angle  = 0;
                return(new ScreenPoint(middle, titlePosition));

            default:
                throw new ArgumentOutOfRangeException("axis");
            }
        }
        /// <summary>
        /// Renders the axis title.
        /// </summary>
        /// <param name="axis">
        /// The axis.
        /// </param>
        /// <param name="titlePosition">
        /// The title position.
        /// </param>
        private void RenderAxisTitle(Axis axis, double titlePosition)
        {
            bool isHorizontal = axis.IsHorizontal();

            OxySize?maxSize = null;

            if (axis.ClipTitle)
            {
                // Calculate the title clipping dimensions
                double screenLength = isHorizontal
                                          ? Math.Abs(axis.ScreenMax.X - axis.ScreenMin.X)
                                          : Math.Abs(axis.ScreenMax.Y - axis.ScreenMin.Y);

                maxSize = new OxySize(screenLength * axis.TitleClippingLength, double.MaxValue);
            }

            double angle = -90;

            var halign = HorizontalAlignment.Center;
            var valign = VerticalAlignment.Top;

            var lpt = this.GetAxisTitlePositionAndAlignment(axis, titlePosition, ref angle, ref halign, ref valign);

            this.rc.SetToolTip(axis.ToolTip);
            this.rc.DrawMathText(
                lpt,
                axis.ActualTitle,
                axis.ActualTitleColor,
                axis.ActualTitleFont,
                axis.ActualTitleFontSize,
                axis.ActualTitleFontWeight,
                angle,
                halign,
                valign,
                maxSize);
            this.rc.SetToolTip(null);
        }
        /// <summary>
        /// Renders the minor items.
        /// </summary>
        /// <param name="axis">
        /// The axis.
        /// </param>
        /// <param name="axisPosition">
        /// The axis position.
        /// </param>
        private void RenderMinorItems(Axis axis, double axisPosition)
        {
            double eps           = axis.ActualMinorStep * 1e-3;
            double actualMinimum = axis.ActualMinimum;
            double actualMaximum = axis.ActualMaximum;

            double plotAreaLeft   = this.Plot.PlotArea.Left;
            double plotAreaRight  = this.Plot.PlotArea.Right;
            double plotAreaTop    = this.Plot.PlotArea.Top;
            double plotAreaBottom = this.Plot.PlotArea.Bottom;
            bool   isHorizontal   = axis.IsHorizontal();

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

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

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

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

                if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps)
                {
                    continue;
                }

                double 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 (this.MinorPen != null)
                {
                    if (isHorizontal)
                    {
                        minorSegments.Add(new ScreenPoint(transformedValue, plotAreaTop));
                        minorSegments.Add(new ScreenPoint(transformedValue, plotAreaBottom));
                    }
                    else
                    {
                        if (transformedValue < plotAreaTop || transformedValue > plotAreaBottom)
                        {
                        }

                        minorSegments.Add(new ScreenPoint(plotAreaLeft, transformedValue));
                        minorSegments.Add(new ScreenPoint(plotAreaRight, transformedValue));
                    }
                }

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

            // Draw all the line segments);
            if (this.MinorPen != null)
            {
                this.rc.DrawLineSegments(minorSegments, this.MinorPen);
            }

            if (this.MinorTickPen != null)
            {
                this.rc.DrawLineSegments(minorTickSegments, this.MinorTickPen);
            }
        }
        /// <summary>
        /// Renders the major items.
        /// </summary>
        /// <param name="axis">
        /// The axis.
        /// </param>
        /// <param name="axisPosition">
        /// The axis position.
        /// </param>
        /// <param name="titlePosition">
        /// The title position.
        /// </param>
        private void RenderMajorItems(Axis axis, double axisPosition, double titlePosition)
        {
            double eps = axis.ActualMinorStep * 1e-3;

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

            double plotAreaLeft   = this.Plot.PlotArea.Left;
            double plotAreaRight  = this.Plot.PlotArea.Right;
            double plotAreaTop    = this.Plot.PlotArea.Top;
            double plotAreaBottom = this.Plot.PlotArea.Bottom;
            bool   isHorizontal   = axis.IsHorizontal();

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

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

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

                if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps)
                {
                    continue;
                }

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

                if (this.MajorPen != null)
                {
                    if (isHorizontal)
                    {
                        majorSegments.Add(new ScreenPoint(transformedValue, plotAreaTop));
                        majorSegments.Add(new ScreenPoint(transformedValue, plotAreaBottom));
                    }
                    else
                    {
                        majorSegments.Add(new ScreenPoint(plotAreaLeft, transformedValue));
                        majorSegments.Add(new ScreenPoint(plotAreaRight, transformedValue));
                    }
                }

                if (axis.TickStyle != TickStyle.None)
                {
                    if (isHorizontal)
                    {
                        majorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a0));
                        majorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a1));
                    }
                    else
                    {
                        majorTickSegments.Add(new ScreenPoint(axisPosition + a0, transformedValue));
                        majorTickSegments.Add(new ScreenPoint(axisPosition + a1, transformedValue));
                    }
                }
            }

            // Render the axis labels (numbers or category names)
            foreach (double value in this.MajorLabelValues)
            {
                if (value < actualMinimum - eps || value > actualMaximum + eps)
                {
                    continue;
                }

                if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps)
                {
                    continue;
                }

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

                var pt = new ScreenPoint();
                var ha = HorizontalAlignment.Right;
                var va = VerticalAlignment.Middle;
                switch (axis.Position)
                {
                case AxisPosition.Left:
                    pt = new ScreenPoint(axisPosition + a1 - axis.AxisTickToLabelDistance, transformedValue);
                    this.GetRotatedAlignments(
                        axis.Angle, HorizontalAlignment.Right, VerticalAlignment.Middle, out ha, out va);
                    break;

                case AxisPosition.Right:
                    pt = new ScreenPoint(axisPosition + a1 + axis.AxisTickToLabelDistance, transformedValue);
                    this.GetRotatedAlignments(
                        axis.Angle, HorizontalAlignment.Left, VerticalAlignment.Middle, out ha, out va);
                    break;

                case AxisPosition.Top:
                    pt = new ScreenPoint(transformedValue, axisPosition + a1 - axis.AxisTickToLabelDistance);
                    this.GetRotatedAlignments(
                        axis.Angle, HorizontalAlignment.Center, VerticalAlignment.Bottom, out ha, out va);
                    break;

                case AxisPosition.Bottom:
                    pt = new ScreenPoint(transformedValue, axisPosition + a1 + axis.AxisTickToLabelDistance);
                    this.GetRotatedAlignments(
                        axis.Angle, HorizontalAlignment.Center, VerticalAlignment.Top, out ha, out va);
                    break;
                }

                string text = axis.FormatValue(value);
                this.rc.DrawMathText(
                    pt,
                    text,
                    axis.ActualTextColor,
                    axis.ActualFont,
                    axis.ActualFontSize,
                    axis.ActualFontWeight,
                    axis.Angle,
                    ha,
                    va);
            }

            // Draw the zero crossing line
            if (axis.PositionAtZeroCrossing && this.ZeroPen != null)
            {
                double t0 = axis.Transform(0);
                if (isHorizontal)
                {
                    this.rc.DrawLine(t0, plotAreaTop, t0, plotAreaBottom, this.ZeroPen);
                }
                else
                {
                    this.rc.DrawLine(plotAreaLeft, t0, plotAreaRight, t0, this.ZeroPen);
                }
            }

            // Draw extra grid lines
            if (axis.ExtraGridlines != null && this.ExtraPen != null)
            {
                foreach (double value in axis.ExtraGridlines)
                {
                    if (!this.IsWithin(value, actualMinimum, actualMaximum))
                    {
                        continue;
                    }

                    double transformedValue = axis.Transform(value);
                    if (isHorizontal)
                    {
                        this.rc.DrawLine(transformedValue, plotAreaTop, transformedValue, plotAreaBottom, this.ExtraPen);
                    }
                    else
                    {
                        this.rc.DrawLine(plotAreaLeft, transformedValue, plotAreaRight, transformedValue, this.ExtraPen);
                    }
                }
            }

            // Draw the axis line (across the tick marks)
            if (isHorizontal)
            {
                this.rc.DrawLine(
                    axis.Transform(actualMinimum),
                    axisPosition,
                    axis.Transform(actualMaximum),
                    axisPosition,
                    this.AxislinePen);
            }
            else
            {
                this.rc.DrawLine(
                    axisPosition,
                    axis.Transform(actualMinimum),
                    axisPosition,
                    axis.Transform(actualMaximum),
                    this.AxislinePen);
            }

            // Draw the axis title
            if (!string.IsNullOrEmpty(axis.ActualTitle))
            {
                this.RenderAxisTitle(axis, titlePosition);
            }

            if (this.MajorPen != null)
            {
                this.rc.DrawLineSegments(majorSegments, this.MajorPen);
            }

            if (this.MajorTickPen != null)
            {
                this.rc.DrawLineSegments(majorTickSegments, this.MajorTickPen);
            }
        }
        /// <summary>
        /// The render.
        /// </summary>
        /// <param name="axis">
        /// The axis.
        /// </param>
        /// <param name="pass">
        /// The render pass.
        /// </param>
        public override void Render(Axis axis, int pass)
        {
            base.Render(axis, pass);

            double totalShift = axis.PositionTierMinShift;
            double tierSize = axis.PositionTierSize - this.Plot.AxisTierDistance;

            // store properties locally for performance
            double plotAreaLeft = this.Plot.PlotArea.Left;
            double plotAreaRight = this.Plot.PlotArea.Right;
            double plotAreaTop = this.Plot.PlotArea.Top;
            double plotAreaBottom = this.Plot.PlotArea.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;
            }

            if (axis.PositionAtZeroCrossing)
            {
                var perpendicularAxis = axis.IsHorizontal() ? this.Plot.DefaultYAxis : this.Plot.DefaultXAxis;
                axisPosition = perpendicularAxis.Transform(0);
            }

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

            if (pass == 1)
            {
                this.RenderMajorItems(axis, axisPosition, titlePosition);
            }
        }
        /// <summary>
        /// Renders the minor items.
        /// </summary>
        /// <param name="axis">
        /// The axis.
        /// </param>
        /// <param name="axisPosition">
        /// The axis position.
        /// </param>
        private void RenderMinorItems(Axis axis, double axisPosition)
        {
            double eps = axis.ActualMinorStep * 1e-3;
            double actualMinimum = axis.ActualMinimum;
            double actualMaximum = axis.ActualMaximum;

            double plotAreaLeft = this.Plot.PlotArea.Left;
            double plotAreaRight = this.Plot.PlotArea.Right;
            double plotAreaTop = this.Plot.PlotArea.Top;
            double plotAreaBottom = this.Plot.PlotArea.Bottom;
            bool isHorizontal = axis.IsHorizontal();

            double a0;
            double a1;
            var minorSegments = new List<ScreenPoint>();
            var minorTickSegments = new List<ScreenPoint>();
            this.GetTickPositions(axis, axis.TickStyle, axis.MinorTickSize, axis.Position, out a0, out a1);

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

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

                if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps)
                {
                    continue;
                }

                double 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 (this.MinorPen != null)
                {
                    if (isHorizontal)
                    {
                        minorSegments.Add(new ScreenPoint(transformedValue, plotAreaTop));
                        minorSegments.Add(new ScreenPoint(transformedValue, plotAreaBottom));
                    }
                    else
                    {
                        if (transformedValue < plotAreaTop || transformedValue > plotAreaBottom)
                        {
                        }

                        minorSegments.Add(new ScreenPoint(plotAreaLeft, transformedValue));
                        minorSegments.Add(new ScreenPoint(plotAreaRight, transformedValue));
                    }
                }

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

            // Draw all the line segments);
            if (this.MinorPen != null)
            {
                this.rc.DrawLineSegments(minorSegments, this.MinorPen);
            }

            if (this.MinorTickPen != null)
            {
                this.rc.DrawLineSegments(minorTickSegments, this.MinorTickPen);
            }
        }
        /// <summary>
        /// Renders the major items.
        /// </summary>
        /// <param name="axis">
        /// The axis.
        /// </param>
        /// <param name="axisPosition">
        /// The axis position.
        /// </param>
        /// <param name="titlePosition">
        /// The title position.
        /// </param>
        private void RenderMajorItems(Axis axis, double axisPosition, double titlePosition)
        {
            double eps = axis.ActualMinorStep * 1e-3;

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

            double plotAreaLeft = this.Plot.PlotArea.Left;
            double plotAreaRight = this.Plot.PlotArea.Right;
            double plotAreaTop = this.Plot.PlotArea.Top;
            double plotAreaBottom = this.Plot.PlotArea.Bottom;
            bool isHorizontal = axis.IsHorizontal();

            double a0;
            double a1;
            var majorSegments = new List<ScreenPoint>();
            var majorTickSegments = new List<ScreenPoint>();
            this.GetTickPositions(axis, axis.TickStyle, axis.MajorTickSize, axis.Position, out a0, out a1);

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

                if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps)
                {
                    continue;
                }

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

                if (this.MajorPen != null)
                {
                    if (isHorizontal)
                    {
                        majorSegments.Add(new ScreenPoint(transformedValue, plotAreaTop));
                        majorSegments.Add(new ScreenPoint(transformedValue, plotAreaBottom));
                    }
                    else
                    {
                        majorSegments.Add(new ScreenPoint(plotAreaLeft, transformedValue));
                        majorSegments.Add(new ScreenPoint(plotAreaRight, transformedValue));
                    }
                }

                if (axis.TickStyle != TickStyle.None)
                {
                    if (isHorizontal)
                    {
                        majorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a0));
                        majorTickSegments.Add(new ScreenPoint(transformedValue, axisPosition + a1));
                    }
                    else
                    {
                        majorTickSegments.Add(new ScreenPoint(axisPosition + a0, transformedValue));
                        majorTickSegments.Add(new ScreenPoint(axisPosition + a1, transformedValue));
                    }
                }
            }

            // Render the axis labels (numbers or category names)
            foreach (double value in this.MajorLabelValues)
            {
                if (value < actualMinimum - eps || value > actualMaximum + eps)
                {
                    continue;
                }

                if (axis.PositionAtZeroCrossing && Math.Abs(value) < eps)
                {
                    continue;
                }

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

                var pt = new ScreenPoint();
                var ha = HorizontalTextAlign.Right;
                var va = VerticalTextAlign.Middle;
                switch (axis.Position)
                {
                    case AxisPosition.Left:
                        pt = new ScreenPoint(axisPosition + a1 - axis.AxisTickToLabelDistance, transformedValue);
                        this.GetRotatedAlignments(
                            axis.Angle, HorizontalTextAlign.Right, VerticalTextAlign.Middle, out ha, out va);
                        break;
                    case AxisPosition.Right:
                        pt = new ScreenPoint(axisPosition + a1 + axis.AxisTickToLabelDistance, transformedValue);
                        this.GetRotatedAlignments(
                            axis.Angle, HorizontalTextAlign.Left, VerticalTextAlign.Middle, out ha, out va);
                        break;
                    case AxisPosition.Top:
                        pt = new ScreenPoint(transformedValue, axisPosition + a1 - axis.AxisTickToLabelDistance);
                        this.GetRotatedAlignments(
                            axis.Angle, HorizontalTextAlign.Center, VerticalTextAlign.Bottom, out ha, out va);
                        break;
                    case AxisPosition.Bottom:
                        pt = new ScreenPoint(transformedValue, axisPosition + a1 + axis.AxisTickToLabelDistance);
                        this.GetRotatedAlignments(
                            axis.Angle, HorizontalTextAlign.Center, VerticalTextAlign.Top, out ha, out va);
                        break;
                }

                string text = axis.FormatValue(value);
                this.rc.DrawMathText(
                    pt, 
                    text, 
                    axis.ActualTextColor, 
                    axis.ActualFont, 
                    axis.ActualFontSize, 
                    axis.ActualFontWeight, 
                    axis.Angle, 
                    ha, 
                    va);
            }

            // Draw the zero crossing line
            if (axis.PositionAtZeroCrossing && this.ZeroPen != null)
            {
                double t0 = axis.Transform(0);
                if (isHorizontal)
                {
                    this.rc.DrawLine(t0, plotAreaTop, t0, plotAreaBottom, this.ZeroPen);
                }
                else
                {
                    this.rc.DrawLine(plotAreaLeft, t0, plotAreaRight, t0, this.ZeroPen);
                }
            }

            // Draw extra grid lines
            if (axis.ExtraGridlines != null && this.ExtraPen != null)
            {
                foreach (double value in axis.ExtraGridlines)
                {
                    if (!this.IsWithin(value, actualMinimum, actualMaximum))
                    {
                        continue;
                    }

                    double transformedValue = axis.Transform(value);
                    if (isHorizontal)
                    {
                        this.rc.DrawLine(transformedValue, plotAreaTop, transformedValue, plotAreaBottom, this.ExtraPen);
                    }
                    else
                    {
                        this.rc.DrawLine(plotAreaLeft, transformedValue, plotAreaRight, transformedValue, this.ExtraPen);
                    }
                }
            }

            // Draw the axis line (across the tick marks)
            if (isHorizontal)
            {
                this.rc.DrawLine(
                    axis.Transform(actualMinimum), 
                    axisPosition, 
                    axis.Transform(actualMaximum), 
                    axisPosition, 
                    this.AxislinePen);
            }
            else
            {
                this.rc.DrawLine(
                    axisPosition, 
                    axis.Transform(actualMinimum), 
                    axisPosition, 
                    axis.Transform(actualMaximum), 
                    this.AxislinePen);
            }

            // Draw the axis title
            if (!string.IsNullOrEmpty(axis.ActualTitle))
            {
                this.RenderAxisTitle(axis, titlePosition);
            }

            if (this.MajorPen != null)
            {
                this.rc.DrawLineSegments(majorSegments, this.MajorPen);
            }

            if (this.MajorTickPen != null)
            {
                this.rc.DrawLineSegments(majorTickSegments, this.MajorTickPen);
            }
        }
        /// <summary>
        /// Renders the axis title.
        /// </summary>
        /// <param name="axis">
        /// The axis.
        /// </param>
        /// <param name="titlePosition">
        /// The title position.
        /// </param>
        private void RenderAxisTitle(Axis axis, double titlePosition)
        {
            bool isHorizontal = axis.IsHorizontal();

            OxySize? maxSize = null;

            if (axis.ClipTitle)
            {
                // Calculate the title clipping dimensions
                double screenLength = isHorizontal
                                          ? Math.Abs(axis.ScreenMax.X - axis.ScreenMin.X)
                                          : Math.Abs(axis.ScreenMax.Y - axis.ScreenMin.Y);

                maxSize = new OxySize(screenLength * axis.TitleClippingLength, double.MaxValue);
            }

            double angle = -90;

            var halign = HorizontalTextAlign.Center;
            var valign = VerticalTextAlign.Top;

            var lpt = this.GetAxisTitlePositionAndAlignment(axis, titlePosition, ref angle, ref halign, ref valign);

            this.rc.SetToolTip(axis.ToolTip);
            this.rc.DrawText(
                lpt, 
                axis.ActualTitle, 
                axis.ActualTitleColor, 
                axis.ActualTitleFont, 
                axis.ActualTitleFontSize, 
                axis.ActualTitleFontWeight, 
                angle, 
                halign, 
                valign, 
                maxSize);
            this.rc.SetToolTip(null);
        }
        /// <summary>
        /// Gets the axis title position, rotation and alignment.
        /// </summary>
        /// <param name="axis">
        /// The axis.
        /// </param>
        /// <param name="titlePosition">
        /// The title position.
        /// </param>
        /// <param name="angle">
        /// The angle.
        /// </param>
        /// <param name="halign">
        /// The horizontal alignment.
        /// </param>
        /// <param name="valign">
        /// The vertical alignment.
        /// </param>
        /// <returns>
        /// The <see cref="ScreenPoint"/>.
        /// </returns>
        protected virtual ScreenPoint GetAxisTitlePositionAndAlignment(
            Axis axis, 
            double titlePosition, 
            ref double angle, 
            ref HorizontalTextAlign halign, 
            ref VerticalTextAlign valign)
        {
            double middle = axis.IsHorizontal()
                                ? Lerp(axis.ScreenMin.X, axis.ScreenMax.X, axis.TitlePosition)
                                : Lerp(axis.ScreenMax.Y, axis.ScreenMin.Y, axis.TitlePosition);

            if (axis.PositionAtZeroCrossing)
            {
                var perpendicularAxis = axis.IsHorizontal() ? this.Plot.DefaultYAxis : this.Plot.DefaultXAxis;
                middle = perpendicularAxis.Transform(perpendicularAxis.ActualMaximum);
            }

            switch (axis.Position)
            {
                case AxisPosition.Left:
                    return new ScreenPoint(titlePosition, middle);
                case AxisPosition.Right:
                    valign = VerticalTextAlign.Bottom;
                    return new ScreenPoint(titlePosition, middle);
                case AxisPosition.Top:
                    halign = HorizontalTextAlign.Center;
                    valign = VerticalTextAlign.Top;
                    angle = 0;
                    return new ScreenPoint(middle, titlePosition);
                case AxisPosition.Bottom:
                    halign = HorizontalTextAlign.Center;
                    valign = VerticalTextAlign.Bottom;
                    angle = 0;
                    return new ScreenPoint(middle, titlePosition);
                default:
                    throw new ArgumentOutOfRangeException("axis");
            }
        }