Example #1
0
        private void RenderHorizontalAxis(Axis axis, Axis perpendicularAxis)
        {
            double y = Plot.Bounds.Bottom;

            switch (axis.Position)
            {
            case AxisPosition.Top:
                y = Plot.Bounds.Top;
                break;

            case AxisPosition.Bottom:
                y = Plot.Bounds.Bottom;
                break;
            }
            if (axis.PositionAtZeroCrossing)
            {
                y = perpendicularAxis.TransformX(0);
            }

            double y0, y1;

            if (axis.ShowMinorTicks)
            {
                GetVerticalTickPositions(axis, axis.TickStyle, axis.MinorTickSize, out y0, out y1);

                foreach (double xValue in minorTickValues)
                {
                    if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum)
                    {
                        continue;
                    }

                    if (majorTickValues.Contains(xValue))
                    {
                        continue;
                    }

                    double x = axis.TransformX(xValue);
                    if (minorPen != null)
                    {
                        RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, minorPen);
                    }
                    RenderLine(x, y + y0, x, y + y1, minorTickPen);
                }
            }

            GetVerticalTickPositions(axis, axis.TickStyle, axis.MajorTickSize, out y0, out y1);

            double maxh  = 0;
            bool   istop = axis.Position == AxisPosition.Top;

            foreach (double xValue in majorTickValues)
            {
                if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum)
                {
                    continue;
                }

                double x = axis.TransformX(xValue);

                if (majorPen != null)
                {
                    RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, majorPen);
                }
                RenderLine(x, y + y0, x, y + y1, majorTickPen);

                if (xValue == 0 && axis.PositionAtZeroCrossing)
                {
                    continue;
                }

                var    pt   = new ScreenPoint(x, istop ? y + y1 - TICK_DIST : y + y1 + TICK_DIST);
                string text = axis.FormatValue(xValue);
                double h    = rc.MeasureText(text, axis.FontFamily, axis.FontSize, axis.FontWeight).Height;

                rc.DrawText(pt, text, Plot.TextColor,
                            axis.FontFamily, axis.FontSize, axis.FontWeight,
                            axis.Angle,
                            HorizontalTextAlign.Center, istop ? VerticalTextAlign.Bottom : VerticalTextAlign.Top);

                maxh = Math.Max(maxh, h);
            }

            if (axis.PositionAtZeroCrossing)
            {
                double x = axis.TransformX(0);
                RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, zeroPen);
            }

            if (axis.ExtraGridlines != null)
            {
                foreach (double x in axis.ExtraGridlines)
                {
                    if (!IsWithin(x, axis.ActualMinimum, axis.ActualMaximum))
                    {
                        continue;
                    }
                    double sx = axis.TransformX(x);
                    RenderLine(sx, Plot.Bounds.Top, sx, Plot.Bounds.Bottom, extraPen);
                }
            }

            // The horizontal axis line
            RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, majorPen);

            // The horizontal axis legend (centered horizontally)
            double legendX             = axis.TransformX((axis.ActualMinimum + axis.ActualMaximum) / 2);
            HorizontalTextAlign halign = HorizontalTextAlign.Center;
            VerticalTextAlign   valign = VerticalTextAlign.Bottom;

            if (axis.PositionAtZeroCrossing)
            {
                legendX = perpendicularAxis.TransformX(perpendicularAxis.ActualMaximum);
            }

            double legendY = rc.Height - AXIS_LEGEND_DIST;

            if (istop)
            {
                legendY = AXIS_LEGEND_DIST;
                valign  = VerticalTextAlign.Top;
            }
            rc.DrawText(new ScreenPoint(legendX, legendY),
                        axis.Title, Plot.TextColor,
                        axis.FontFamily, axis.FontSize, axis.FontWeight, 0, halign, valign);
        }
Example #2
0
        private void RenderVerticalAxis(Axis axis, Axis perpendicularAxis)
        {
            double x = Plot.Bounds.Left;

            switch (axis.Position)
            {
            case AxisPosition.Left:
                x = Plot.Bounds.Left;
                break;

            case AxisPosition.Right:
                x = Plot.Bounds.Right;
                break;
            }
            if (axis.PositionAtZeroCrossing)
            {
                x = perpendicularAxis.TransformX(0);
            }

            double x0, x1;

            if (axis.ShowMinorTicks)
            {
                GetHorizontalTickPositions(axis, axis.TickStyle, axis.MinorTickSize, out x0, out x1);
                foreach (double yValue in minorTickValues)
                {
                    if (yValue < axis.ActualMinimum || yValue > axis.ActualMaximum)
                    {
                        continue;
                    }

                    if (majorTickValues.Contains(yValue))
                    {
                        continue;
                    }
                    double y = axis.TransformX(yValue);

                    if (minorPen != null)
                    {
                        RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, minorPen);
                    }

                    RenderLine(x + x0, y, x + x1, y, minorTickPen);
                }
            }

            GetHorizontalTickPositions(axis, axis.TickStyle, axis.MajorTickSize, out x0, out x1);
            double maxw = 0;

            bool isleft = axis.Position == AxisPosition.Left;

            foreach (double yValue in majorTickValues)
            {
                if (yValue < axis.ActualMinimum || yValue > axis.ActualMaximum)
                {
                    continue;
                }

                double y = axis.TransformX(yValue);

                if (majorPen != null)
                {
                    RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, majorPen);
                }

                RenderLine(x + x0, y, x + x1, y, majorTickPen);

                if (yValue == 0 && axis.PositionAtZeroCrossing)
                {
                    continue;
                }

                var    pt   = new ScreenPoint(isleft ? x + x1 - TICK_DIST : x + x1 + TICK_DIST, y);
                string text = axis.FormatValue(yValue);
                double w    = rc.MeasureText(text, axis.FontFamily, axis.FontSize, axis.FontWeight).Height;
                rc.DrawText(pt, text, Plot.TextColor,
                            axis.FontFamily, axis.FontSize, axis.FontWeight,
                            axis.Angle,
                            isleft ? HorizontalTextAlign.Right : HorizontalTextAlign.Left, VerticalTextAlign.Middle);
                maxw = Math.Max(maxw, w);
            }

            if (axis.PositionAtZeroCrossing)
            {
                double y = axis.TransformX(0);
                RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, zeroPen);
            }

            if (axis.ExtraGridlines != null)
            {
                foreach (double y in axis.ExtraGridlines)
                {
                    if (!IsWithin(y, axis.ActualMinimum, axis.ActualMaximum))
                    {
                        continue;
                    }
                    double sy = axis.TransformX(y);
                    RenderLine(Plot.Bounds.Left, sy, Plot.Bounds.Right, sy, extraPen);
                }
            }

            RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, majorPen);

            double ymid = axis.TransformX((axis.ActualMinimum + axis.ActualMaximum) / 2);

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

            if (axis.PositionAtZeroCrossing)
            {
                ymid = perpendicularAxis.TransformX(perpendicularAxis.ActualMaximum);
                // valign = axis.IsReversed ? VerticalTextAlign.Top : VerticalTextAlign.Bottom;
            }

            if (isleft)
            {
                x = AXIS_LEGEND_DIST;
            }
            else
            {
                x      = rc.Width - AXIS_LEGEND_DIST;
                valign = VerticalTextAlign.Bottom;
            }

            rc.DrawText(new ScreenPoint(x, ymid), axis.Title, Plot.TextColor,
                        axis.FontFamily, axis.FontSize, axis.FontWeight,
                        -90, halign, valign);
        }
        private void RenderVerticalAxis(Axis axis, Axis perpendicularAxis)
        {
            double x = Plot.Bounds.Left;
            switch (axis.Position)
            {
                case AxisPosition.Left:
                    x = Plot.Bounds.Left;
                    break;
                case AxisPosition.Right:
                    x = Plot.Bounds.Right;
                    break;
            }
            if (axis.PositionAtZeroCrossing)
                x = perpendicularAxis.TransformX(0);

            double x0, x1;

            if (axis.ShowMinorTicks)
            {
                GetHorizontalTickPositions(axis, axis.TickStyle, axis.MinorTickSize, out x0, out x1);
                foreach (double yValue in minorTickValues)
                {
                    if (yValue < axis.ActualMinimum || yValue > axis.ActualMaximum)
                    {
                        continue;
                    }

                    if (majorTickValues.Contains(yValue))
                    {
                        continue;
                    }
                    double y = axis.TransformX(yValue);

                    if (minorPen != null)
                    {
                        RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, minorPen);
                    }

                    RenderLine(x + x0, y, x + x1, y, minorTickPen);
                }
            }

            GetHorizontalTickPositions(axis, axis.TickStyle, axis.MajorTickSize, out x0, out x1);
            double maxw = 0;

            bool isleft = axis.Position == AxisPosition.Left;

            foreach (double yValue in majorTickValues)
            {
                if (yValue < axis.ActualMinimum || yValue > axis.ActualMaximum)
                    continue;

                double y = axis.TransformX(yValue);

                if (majorPen != null)
                {
                    RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, majorPen);
                }

                RenderLine(x + x0, y, x + x1, y, majorTickPen);

                if (yValue == 0 && axis.PositionAtZeroCrossing)
                    continue;

                var pt = new ScreenPoint(isleft ? x + x1 - TICK_DIST : x + x1 + TICK_DIST, y);
                string text = axis.FormatValue(yValue);
                double w = rc.MeasureText(text, axis.FontFamily, axis.FontSize, axis.FontWeight).Height;
                rc.DrawText(pt, text, Plot.TextColor,
                            axis.FontFamily, axis.FontSize, axis.FontWeight,
                            axis.Angle,
                            isleft ? HorizontalTextAlign.Right : HorizontalTextAlign.Left, VerticalTextAlign.Middle);
                maxw = Math.Max(maxw, w);
            }

            if (axis.PositionAtZeroCrossing)
            {
                double y = axis.TransformX(0);
                RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, zeroPen);
            }

            if (axis.ExtraGridlines != null)
                foreach (double y in axis.ExtraGridlines)
                {
                    if (!IsWithin(y, axis.ActualMinimum, axis.ActualMaximum))
                        continue;
                    double sy = axis.TransformX(y);
                    RenderLine(Plot.Bounds.Left, sy, Plot.Bounds.Right, sy, extraPen);
                }

            RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, majorPen);

            double ymid = axis.TransformX((axis.ActualMinimum + axis.ActualMaximum)/2);

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

            if (axis.PositionAtZeroCrossing)
            {
                ymid = perpendicularAxis.TransformX(perpendicularAxis.ActualMaximum);
                // valign = axis.IsReversed ? VerticalTextAlign.Top : VerticalTextAlign.Bottom;
            }

            if (isleft)
            {
                x = AXIS_LEGEND_DIST;
            }
            else
            {
                x = rc.Width - AXIS_LEGEND_DIST;
                valign = VerticalTextAlign.Bottom;
            }

            rc.DrawText(new ScreenPoint(x, ymid), axis.Title, Plot.TextColor,
                        axis.FontFamily, axis.FontSize, axis.FontWeight,
                        -90, halign, valign);
        }
        /// <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);
            }
        }
        private void RenderHorizontalAxis(Axis axis, Axis perpendicularAxis)
        {
            double y = Plot.Bounds.Bottom;
            switch (axis.Position)
            {
                case AxisPosition.Top:
                    y = Plot.Bounds.Top;
                    break;
                case AxisPosition.Bottom:
                    y = Plot.Bounds.Bottom;
                    break;
            }
            if (axis.PositionAtZeroCrossing)
            {
                y = perpendicularAxis.TransformX(0);
            }

            double y0, y1;

            if (axis.ShowMinorTicks)
            {
                GetVerticalTickPositions(axis, axis.TickStyle, axis.MinorTickSize, out y0, out y1);

                foreach (double xValue in minorTickValues)
                {
                    if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum)
                    {
                        continue;
                    }

                    if (majorTickValues.Contains(xValue))
                    {
                        continue;
                    }

                    double x = axis.TransformX(xValue);
                    if (minorPen != null)
                    {
                        RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, minorPen);
                    }
                    RenderLine(x, y + y0, x, y + y1, minorTickPen);
                }
            }

            GetVerticalTickPositions(axis, axis.TickStyle, axis.MajorTickSize, out y0, out y1);

            double maxh = 0;
            bool istop = axis.Position == AxisPosition.Top;
            foreach (double xValue in majorTickValues)
            {
                if (xValue < axis.ActualMinimum || xValue > axis.ActualMaximum)
                {
                    continue;
                }

                double x = axis.TransformX(xValue);

                if (majorPen != null)
                {
                    RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, majorPen);
                }
                RenderLine(x, y + y0, x, y + y1, majorTickPen);

                if (xValue == 0 && axis.PositionAtZeroCrossing)
                    continue;

                var pt = new ScreenPoint(x, istop ? y + y1 - TICK_DIST : y + y1 + TICK_DIST);
                string text = axis.FormatValue(xValue);
                double h = rc.MeasureText(text, axis.FontFamily, axis.FontSize, axis.FontWeight).Height;

                rc.DrawText(pt, text, Plot.TextColor,
                            axis.FontFamily, axis.FontSize, axis.FontWeight,
                            axis.Angle,
                            HorizontalTextAlign.Center, istop ? VerticalTextAlign.Bottom : VerticalTextAlign.Top);

                maxh = Math.Max(maxh, h);
            }

            if (axis.PositionAtZeroCrossing)
            {
                double x = axis.TransformX(0);
                RenderLine(x, Plot.Bounds.Top, x, Plot.Bounds.Bottom, zeroPen);
            }

            if (axis.ExtraGridlines != null)
            {
                foreach (double x in axis.ExtraGridlines)
                {
                    if (!IsWithin(x, axis.ActualMinimum, axis.ActualMaximum))
                        continue;
                    double sx = axis.TransformX(x);
                    RenderLine(sx, Plot.Bounds.Top, sx, Plot.Bounds.Bottom, extraPen);
                }
            }

            // The horizontal axis line
            RenderLine(Plot.Bounds.Left, y, Plot.Bounds.Right, y, majorPen);

            // The horizontal axis legend (centered horizontally)
            double legendX = axis.TransformX((axis.ActualMinimum + axis.ActualMaximum)/2);
            HorizontalTextAlign halign = HorizontalTextAlign.Center;
            VerticalTextAlign valign = VerticalTextAlign.Bottom;

            if (axis.PositionAtZeroCrossing)
            {
                legendX = perpendicularAxis.TransformX(perpendicularAxis.ActualMaximum);
            }

            double legendY = rc.Height - AXIS_LEGEND_DIST;
            if (istop)
            {
                legendY = AXIS_LEGEND_DIST;
                valign = VerticalTextAlign.Top;
            }
            rc.DrawText(new ScreenPoint(legendX, legendY),
                        axis.Title, Plot.TextColor,
                        axis.FontFamily, axis.FontSize, axis.FontWeight, 0, halign, valign);
        }
Example #6
0
        /// <summary>
        /// Renders the specified axis.
        /// </summary>
        /// <param name="axis">The axis.</param>
        /// <param name="pass">The render pass.</param>
        /// <exception cref="System.InvalidOperationException">Magnitude axis not defined.</exception>
        public override void Render(Axis axis, int pass)
        {
            base.Render(axis, pass);

            var magnitudeAxis = this.Plot.DefaultMagnitudeAxis;

            if (axis.RelatedAxis != null)
            {
                magnitudeAxis = axis.RelatedAxis as MagnitudeAxis;
            }

            if (magnitudeAxis == null)
            {
                throw new InvalidOperationException("Magnitude axis not defined.");
            }

            double eps = axis.MinorStep * 1e-3;

            if (axis.ShowMinorTicks)
            {
                foreach (double value in this.MinorTickValues)
                {
                    if (value < axis.ActualMinimum - eps || value > axis.ActualMaximum + eps)
                    {
                        continue;
                    }

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

                    var pt = magnitudeAxis.Transform(magnitudeAxis.ActualMaximum, value, axis);

                    if (this.MinorPen != null)
                    {
                        this.rc.DrawLine(magnitudeAxis.MidPoint.x, magnitudeAxis.MidPoint.y, pt.x, pt.y, this.MinorPen, false);
                    }
                }
            }

            var  angleAxis    = (AngleAxis)axis;
            bool isFullCircle = Math.Abs(Math.Abs(angleAxis.EndAngle - angleAxis.StartAngle) - 360) < 1e-6;

            foreach (double value in this.MajorTickValues)
            {
                // skip the last value (overlapping with the first)
                if (isFullCircle && value > axis.ActualMaximum - eps)
                {
                    continue;
                }

                if (value < axis.ActualMinimum - eps || value > axis.ActualMaximum + eps)
                {
                    continue;
                }

                ScreenPoint pt = magnitudeAxis.Transform(magnitudeAxis.ActualMaximum, value, axis);
                if (this.MajorPen != null)
                {
                    this.rc.DrawLine(
                        magnitudeAxis.MidPoint.x, magnitudeAxis.MidPoint.y, pt.x, pt.y, this.MajorPen, false);
                }
            }

            foreach (double value in this.MajorLabelValues)
            {
                // skip the last value (overlapping with the first)
                if (isFullCircle && value > axis.ActualMaximum - eps)
                {
                    continue;
                }

                var    pt    = magnitudeAxis.Transform(magnitudeAxis.ActualMaximum, value, axis);
                double angle = Math.Atan2(pt.y - magnitudeAxis.MidPoint.y, pt.x - magnitudeAxis.MidPoint.x);

                // add some margin
                pt.x += Math.Cos(angle) * axis.AxisTickToLabelDistance;
                pt.y += Math.Sin(angle) * axis.AxisTickToLabelDistance;

                // Convert to degrees
                angle *= 180 / Math.PI;

                string text = axis.FormatValue(value);

                var ha = HorizontalAlignment.Left;
                var va = VerticalAlignment.Middle;

                if (Math.Abs(Math.Abs(angle) - 90) < 10)
                {
                    ha    = HorizontalAlignment.Center;
                    va    = angle > 90 ? VerticalAlignment.Top : VerticalAlignment.Bottom;
                    angle = 0;
                }
                else if (angle > 90 || angle < -90)
                {
                    angle -= 180;
                    ha     = HorizontalAlignment.Right;
                }

                this.rc.DrawMathText(
                    pt, text, axis.ActualTextColor, axis.ActualFont, axis.ActualFontSize, axis.ActualFontWeight, angle, ha, va);
            }
        }
        /// <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);
            }
        }
        public override void Render(Axis axis)
        {
            base.Render(axis);

            var perpendicularAxis = Plot.DefaultXAxis;
            bool isHorizontal = true;

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

            switch (axis.Position)
            {
                case AxisPosition.Left:
                    apos = Plot.PlotArea.Left;
                    isHorizontal = false;
                    break;
                case AxisPosition.Right:
                    apos = Plot.PlotArea.Right;
                    isHorizontal = false;
                    break;
                case AxisPosition.Top:
                    apos = Plot.PlotArea.Top;
                    perpendicularAxis = Plot.DefaultYAxis;
                    break;
                case AxisPosition.Bottom:
                    apos = Plot.PlotArea.Bottom;
                    perpendicularAxis = Plot.DefaultYAxis;
                    break;
            }

            if (axis.PositionAtZeroCrossing)
            {
                apos = perpendicularAxis.Transform(0);
            }

            double a0, a1;

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

                foreach (double value in MinorTickValues)
                {
                    if (value < axis.ActualMinimum || value > axis.ActualMaximum)
                    {
                        continue;
                    }

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

                    double transformedValue = axis.Transform(value);

                    if (MinorPen != null)
                    {
                        if (isHorizontal)
                        {
                            rc.DrawLine(transformedValue, Plot.PlotArea.Top, transformedValue, Plot.PlotArea.Bottom, MinorPen);

                        }
                        else
                        {
                            rc.DrawLine(Plot.PlotArea.Left, transformedValue, Plot.PlotArea.Right, transformedValue, MinorPen);
                        }
                    }
                    if (isHorizontal)
                    {
                        rc.DrawLine(transformedValue, apos + a0, transformedValue, apos + a1, MinorTickPen);

                    }
                    else
                    {
                        rc.DrawLine(apos + a0, transformedValue, apos + a1, transformedValue, MinorTickPen);
                    }
                }
            }

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

            double maxWidth = 0;
            double maxHeight = 0;

            foreach (double value in MajorTickValues)
            {
                if (value < axis.ActualMinimum || value > axis.ActualMaximum)
                    continue;

                double transformedValue = axis.Transform(value);

                if (MajorPen != null)
                {
                    if (isHorizontal)
                    {
                        rc.DrawLine(transformedValue, Plot.PlotArea.Top, transformedValue, Plot.PlotArea.Bottom, MajorPen);

                    }
                    else
                    {
                        rc.DrawLine(Plot.PlotArea.Left, transformedValue, Plot.PlotArea.Right, transformedValue, MajorPen);
                    }
                }

                if (isHorizontal)
                {
                    rc.DrawLine(transformedValue, apos + a0, transformedValue, apos + a1, MajorTickPen);

                }
                else
                {
                    rc.DrawLine(apos + a0, transformedValue, apos + a1, transformedValue, MajorTickPen);
                }

                if (value == 0 && axis.PositionAtZeroCrossing)
                    continue;

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

                }

                string text = axis.FormatValue(value);
                var size = rc.DrawMathText(pt, text, Plot.TextColor,
                             axis.FontFamily, axis.FontSize, axis.FontWeight,
                             axis.Angle, ha, va);

                maxWidth = Math.Max(maxWidth, size.Width);
                maxHeight = Math.Max(maxHeight, size.Height);
            }

            if (axis.PositionAtZeroCrossing)
            {
                double t0 = axis.Transform(0);
                if (isHorizontal)
                {
                    rc.DrawLine(t0, Plot.PlotArea.Top, t0, Plot.PlotArea.Bottom, ZeroPen);

                }
                else
                {
                    rc.DrawLine(Plot.PlotArea.Left, t0, Plot.PlotArea.Right, t0, ZeroPen);
                }
            }

            if (axis.ExtraGridlines != null)
            {
                foreach (double value in axis.ExtraGridlines)
                {
                    if (!IsWithin(value, axis.ActualMinimum, axis.ActualMaximum))
                        continue;

                    double transformedValue = axis.Transform(value);
                    if (isHorizontal)
                    {
                        rc.DrawLine(transformedValue, Plot.PlotArea.Top, transformedValue, Plot.PlotArea.Bottom, ExtraPen);

                    }
                    else
                    {
                        rc.DrawLine(Plot.PlotArea.Left, transformedValue, Plot.PlotArea.Right, transformedValue, ExtraPen);
                    }
                }
            }
            if (isHorizontal)
            {
                rc.DrawLine(Plot.PlotArea.Left, apos, Plot.PlotArea.Right, apos, MajorPen);

            }
            else
            {
                rc.DrawLine(apos, Plot.PlotArea.Top, apos, Plot.PlotArea.Bottom, MajorPen);
            }

            if (!String.IsNullOrWhiteSpace(axis.Title))
            {
                // Axis legend
                double ymid = axis.Transform((axis.ActualMinimum + axis.ActualMaximum) / 2);
                double angle = -90;
                var lpt = new ScreenPoint();

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

                if (axis.PositionAtZeroCrossing)
                {
                    ymid = perpendicularAxis.Transform(perpendicularAxis.ActualMaximum);
                    // valign = axis.IsReversed ? VerticalTextAlign.Top : VerticalTextAlign.Bottom;
                }

                switch (axis.Position)
                {
                    case AxisPosition.Left:
                        lpt = new ScreenPoint(AXIS_LEGEND_DIST, ymid);
                        break;
                    case AxisPosition.Right:
                        lpt = new ScreenPoint(rc.Width - AXIS_LEGEND_DIST, ymid);
                        valign = VerticalTextAlign.Bottom;
                        break;
                    case AxisPosition.Top:
                        lpt = new ScreenPoint(ymid, AXIS_LEGEND_DIST);
                        halign = HorizontalTextAlign.Center;
                        valign = VerticalTextAlign.Top;
                        angle = 0;
                        break;
                    case AxisPosition.Bottom:
                        lpt = new ScreenPoint(ymid, rc.Height - AXIS_LEGEND_DIST);
                        halign = HorizontalTextAlign.Center;
                        valign = VerticalTextAlign.Bottom;
                        angle = 0;
                        break;
                }

                rc.DrawText(lpt, axis.Title, Plot.TextColor,
                            axis.FontFamily, axis.FontSize, axis.FontWeight,
                            angle, halign, valign);
            }
        }
        public override void Render(Axis axis)
        {
            base.Render(axis);

            var  perpendicularAxis = Plot.DefaultXAxis;
            bool isHorizontal      = true;

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

            switch (axis.Position)
            {
            case AxisPosition.Left:
                apos         = Plot.PlotArea.Left;
                isHorizontal = false;
                break;

            case AxisPosition.Right:
                apos         = Plot.PlotArea.Right;
                isHorizontal = false;
                break;

            case AxisPosition.Top:
                apos = Plot.PlotArea.Top;
                perpendicularAxis = Plot.DefaultYAxis;
                break;

            case AxisPosition.Bottom:
                apos = Plot.PlotArea.Bottom;
                perpendicularAxis = Plot.DefaultYAxis;
                break;
            }

            if (axis.PositionAtZeroCrossing)
            {
                apos = perpendicularAxis.Transform(0);
            }

            double a0, a1;

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

                foreach (double value in MinorTickValues)
                {
                    if (value < axis.ActualMinimum || value > axis.ActualMaximum)
                    {
                        continue;
                    }

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

                    double transformedValue = axis.Transform(value);

                    if (MinorPen != null)
                    {
                        if (isHorizontal)
                        {
                            rc.DrawLine(transformedValue, Plot.PlotArea.Top, transformedValue, Plot.PlotArea.Bottom, MinorPen);
                        }
                        else
                        {
                            rc.DrawLine(Plot.PlotArea.Left, transformedValue, Plot.PlotArea.Right, transformedValue, MinorPen);
                        }
                    }
                    if (isHorizontal)
                    {
                        rc.DrawLine(transformedValue, apos + a0, transformedValue, apos + a1, MinorTickPen);
                    }
                    else
                    {
                        rc.DrawLine(apos + a0, transformedValue, apos + a1, transformedValue, MinorTickPen);
                    }
                }
            }

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

            double maxWidth  = 0;
            double maxHeight = 0;

            foreach (double value in MajorTickValues)
            {
                if (value < axis.ActualMinimum || value > axis.ActualMaximum)
                {
                    continue;
                }

                double transformedValue = axis.Transform(value);

                if (MajorPen != null)
                {
                    if (isHorizontal)
                    {
                        rc.DrawLine(transformedValue, Plot.PlotArea.Top, transformedValue, Plot.PlotArea.Bottom, MajorPen);
                    }
                    else
                    {
                        rc.DrawLine(Plot.PlotArea.Left, transformedValue, Plot.PlotArea.Right, transformedValue, MajorPen);
                    }
                }

                if (isHorizontal)
                {
                    rc.DrawLine(transformedValue, apos + a0, transformedValue, apos + a1, MajorTickPen);
                }
                else
                {
                    rc.DrawLine(apos + a0, transformedValue, apos + a1, transformedValue, MajorTickPen);
                }

                if (value == 0 && axis.PositionAtZeroCrossing)
                {
                    continue;
                }

                var pt = new ScreenPoint();
                var ha = HorizontalTextAlign.Right;
                var va = VerticalTextAlign.Middle;
                switch (axis.Position)
                {
                case AxisPosition.Left:
                    pt = new ScreenPoint(apos + a1 - TICK_DIST, transformedValue);
                    GetRotatedAlignments(axis.Angle, HorizontalTextAlign.Right, VerticalTextAlign.Middle, out ha, out va);
                    break;

                case AxisPosition.Right:
                    pt = new ScreenPoint(apos + a1 + TICK_DIST, transformedValue);
                    GetRotatedAlignments(axis.Angle, HorizontalTextAlign.Left, VerticalTextAlign.Middle, out ha, out va);
                    break;

                case AxisPosition.Top:
                    pt = new ScreenPoint(transformedValue, apos + a1 - TICK_DIST);
                    GetRotatedAlignments(axis.Angle, HorizontalTextAlign.Center, VerticalTextAlign.Bottom, out ha, out va);
                    break;

                case AxisPosition.Bottom:
                    pt = new ScreenPoint(transformedValue, apos + a1 + TICK_DIST);
                    GetRotatedAlignments(axis.Angle, HorizontalTextAlign.Center, VerticalTextAlign.Top, out ha, out va);
                    break;
                }

                string text = axis.FormatValue(value);
                var    size = rc.DrawMathText(pt, text, Plot.TextColor,
                                              axis.FontFamily, axis.FontSize, axis.FontWeight,
                                              axis.Angle, ha, va);

                maxWidth  = Math.Max(maxWidth, size.Width);
                maxHeight = Math.Max(maxHeight, size.Height);
            }

            if (axis.PositionAtZeroCrossing)
            {
                double t0 = axis.Transform(0);
                if (isHorizontal)
                {
                    rc.DrawLine(t0, Plot.PlotArea.Top, t0, Plot.PlotArea.Bottom, ZeroPen);
                }
                else
                {
                    rc.DrawLine(Plot.PlotArea.Left, t0, Plot.PlotArea.Right, t0, ZeroPen);
                }
            }

            if (axis.ExtraGridlines != null)
            {
                foreach (double value in axis.ExtraGridlines)
                {
                    if (!IsWithin(value, axis.ActualMinimum, axis.ActualMaximum))
                    {
                        continue;
                    }

                    double transformedValue = axis.Transform(value);
                    if (isHorizontal)
                    {
                        rc.DrawLine(transformedValue, Plot.PlotArea.Top, transformedValue, Plot.PlotArea.Bottom, ExtraPen);
                    }
                    else
                    {
                        rc.DrawLine(Plot.PlotArea.Left, transformedValue, Plot.PlotArea.Right, transformedValue, ExtraPen);
                    }
                }
            }
            if (isHorizontal)
            {
                rc.DrawLine(Plot.PlotArea.Left, apos, Plot.PlotArea.Right, apos, MajorPen);
            }
            else
            {
                rc.DrawLine(apos, Plot.PlotArea.Top, apos, Plot.PlotArea.Bottom, MajorPen);
            }

            if (!String.IsNullOrWhiteSpace(axis.Title))
            {
                // Axis legend
                double ymid  = axis.Transform((axis.ActualMinimum + axis.ActualMaximum) / 2);
                double angle = -90;
                var    lpt   = new ScreenPoint();

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

                if (axis.PositionAtZeroCrossing)
                {
                    ymid = perpendicularAxis.Transform(perpendicularAxis.ActualMaximum);
                    // valign = axis.IsReversed ? VerticalTextAlign.Top : VerticalTextAlign.Bottom;
                }

                switch (axis.Position)
                {
                case AxisPosition.Left:
                    lpt = new ScreenPoint(AXIS_LEGEND_DIST, ymid);
                    break;

                case AxisPosition.Right:
                    lpt    = new ScreenPoint(rc.Width - AXIS_LEGEND_DIST, ymid);
                    valign = VerticalTextAlign.Bottom;
                    break;

                case AxisPosition.Top:
                    lpt    = new ScreenPoint(ymid, AXIS_LEGEND_DIST);
                    halign = HorizontalTextAlign.Center;
                    valign = VerticalTextAlign.Top;
                    angle  = 0;
                    break;

                case AxisPosition.Bottom:
                    lpt    = new ScreenPoint(ymid, rc.Height - AXIS_LEGEND_DIST);
                    halign = HorizontalTextAlign.Center;
                    valign = VerticalTextAlign.Bottom;
                    angle  = 0;
                    break;
                }

                rc.DrawText(lpt, axis.Title, Plot.TextColor,
                            axis.FontFamily, axis.FontSize, axis.FontWeight,
                            angle, halign, valign);
            }
        }