/// <summary>
        /// Draws the clipped line segments.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="points">The points.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="stroke">The stroke.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="lineStyle">The line style.</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="aliased">if set to <c>true</c> [aliased].</param>
        public static void DrawClippedLineSegments(
            this IRenderContext rc,
            IList <ScreenPoint> points,
            OxyRect clippingRectangle,
            OxyColor stroke,
            double strokeThickness,
            LineStyle lineStyle,
            OxyPenLineJoin lineJoin,
            bool aliased)
        {
            if (rc.SetClip(clippingRectangle))
            {
                rc.DrawLineSegments(points, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
                rc.ResetClip();
                return;
            }

            var clipping = new CohenSutherlandClipping(clippingRectangle.Left, clippingRectangle.Right, clippingRectangle.Top, clippingRectangle.Bottom);

            var clippedPoints = new List <ScreenPoint>(points.Count);

            for (int i = 0; i + 1 < points.Count; i += 2)
            {
                var s0 = points[i];
                var s1 = points[i + 1];
                if (clipping.ClipLine(ref s0, ref s1))
                {
                    clippedPoints.Add(s0);
                    clippedPoints.Add(s1);
                }
            }

            rc.DrawLineSegments(clippedPoints, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
        }
Beispiel #2
0
        /// <summary>
        /// Draws the polygon within the specified clipping rectangle.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="points">The points.</param>
        /// <param name="minDistSquared">The squared minimum distance between points.</param>
        /// <param name="fill">The fill color.</param>
        /// <param name="stroke">The stroke color.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="lineStyle">The line style.</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="aliased">The aliased.</param>
        public static void DrawClippedPolygon(
            this IRenderContext rc,
            OxyRect clippingRectangle,
            IList <ScreenPoint> points,
            double minDistSquared,
            OxyColor fill,
            OxyColor stroke,
            double strokeThickness = 1.0,
            LineStyle lineStyle    = LineStyle.Solid,
            LineJoin lineJoin      = LineJoin.Miter,
            bool aliased           = false)
        {
            if (lineStyle == LineStyle.None)
            {
                return;
            }

            var outputBuffer = new List <ScreenPoint>();

            ReducePoints(points, minDistSquared, outputBuffer);

            if (rc.SetClip(clippingRectangle))
            {
                rc.DrawPolygon(outputBuffer, fill, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
                rc.ResetClip();
                return;
            }

            var clippedPoints = SutherlandHodgmanClipping.ClipPolygon(clippingRectangle, outputBuffer);

            rc.DrawPolygon(clippedPoints, fill, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
        }
Beispiel #3
0
        /// <summary>
        /// Draws the polygon within the specified clipping rectangle.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="points">The points.</param>
        /// <param name="minDistSquared">The squared minimum distance between points.</param>
        /// <param name="fill">The fill color.</param>
        /// <param name="stroke">The stroke color.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="lineStyle">The line style.</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="aliased">The aliased.</param>
        public static void DrawClippedPolygon(
            this IRenderContext rc,
            OxyRect clippingRectangle,
            IList <ScreenPoint> points,
            double minDistSquared,
            OxyColor fill,
            OxyColor stroke,
            double strokeThickness = 1.0,
            LineStyle lineStyle    = LineStyle.Solid,
            LineJoin lineJoin      = LineJoin.Miter,
            bool aliased           = false)
        {
            if (lineStyle == LineStyle.None)
            {
                return;
            }

            // TODO: minDistSquared should be implemented or removed
            if (rc.SetClip(clippingRectangle))
            {
                rc.DrawPolygon(points, fill, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
                rc.ResetClip();
                return;
            }

            var clippedPoints = SutherlandHodgmanClipping.ClipPolygon(clippingRectangle, points);

            rc.DrawPolygon(clippedPoints, fill, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
        }
Beispiel #4
0
        public override void Render(IRenderContext rc)
        {
            if (rc == null)
            {
                throw new ArgumentNullException(nameof(rc));
            }

            if (!Lines.Any() || Lines.All(a => !a.Any()))
            {
                return;
            }

            VerifyAxes();

            OxyRect clippingRect = GetClippingRect();

            rc.SetClip(clippingRect);

            // Transform all points to screen coordinates
            foreach (IEnumerable <DataPoint> line in Lines)
            {
                int n0   = line.Count();
                var pts0 = new ScreenPoint[n0];
                TransformToScreenCoordinates(n0, pts0, line);

                rc.DrawLine(pts0, Color, StrokeThickness, Dashes?.ToArray() ?? LineStyle.GetDashArray());
            }

            rc.ResetClip();
        }
    public override void Render(IRenderContext rc)
    {
        base.Render(rc);
        var sY          = StartPoint.Y * (AssociatedSeries.Inverted ? -1 : 1);
        var eY          = EndPoint.Y * (AssociatedSeries.Inverted ? -1 : 1);
        var actualStart = new DataPoint(StartPoint.X, sY);
        var actualEnd   = new DataPoint(EndPoint.X, eY);

        _screenEndPoint   = Transform(actualEnd);
        _screenStartPoint = Transform(actualStart);
        var d = _screenEndPoint - _screenStartPoint;

        d.Normalize();
        var n = new ScreenVector(d.Y, -d.X);

        const double minimumSegmentLength = 4;

        var dashArray = LineStyle.GetDashArray();

        if (!(StrokeThickness > 0) || LineStyle == LineStyle.None)
        {
            return;
        }
        rc.DrawReducedLine(
            new[] { _screenStartPoint, _screenEndPoint },
            minimumSegmentLength * minimumSegmentLength,
            GetSelectableColor(ActualColor),
            StrokeThickness,
            EdgeRenderingMode,
            dashArray,
            LineJoin);
    }
        protected void RenderLine(IRenderContext rc, OxyRect clippingRect, IList <ScreenPoint> pointsToRender, OxyColor lineColor, double strokeness, LineStyle lineStyle)
        {
            //var screenPoints = pointsToRender;
            var resampledPoints = ScreenPointHelper.ResamplePoints(pointsToRender, 2);
            //screenPoints = CreateSpline(resampledPoints, 0.5, null, false, 0.25);

            var outputBuffer = new List <ScreenPoint>(pointsToRender.Count);

            if (this.LineStyle == LineStyle.None)
            {
                foreach (ScreenPoint sp in pointsToRender)
                {
                    rc.DrawMarker(clippingRect, sp, MarkerType.Diamond, null, 3, lineColor, lineColor, 1);
                }
            }
            else
            {
                var dash_array = lineStyle.GetDashArray();
                rc.DrawClippedLine(
                    clippingRect,
                    pointsToRender,
                    0,
                    lineColor,
                    strokeness,
                    dash_array,
                    LineJoin.Round,
                    false,
                    outputBuffer);
            }
        }
Beispiel #7
0
 /// <summary>
 /// Initializes a new instance of the <see cref="OxyPen" /> class.
 /// </summary>
 /// <param name="color">The color.</param>
 /// <param name="thickness">The thickness.</param>
 /// <param name="lineStyle">The line style.</param>
 /// <param name="lineJoin">The line join.</param>
 public OxyPen(
     OxyColor color,
     double thickness    = 1.0,
     LineStyle lineStyle = LineStyle.Solid,
     LineJoin lineJoin   = LineJoin.Miter)
 {
     this.Color     = color;
     this.Thickness = thickness;
     this.DashArray = lineStyle.GetDashArray();
     this.LineStyle = lineStyle;
     this.LineJoin  = lineJoin;
 }
Beispiel #8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="OxyPen" /> class.
 /// </summary>
 /// <param name="color">The color.</param>
 /// <param name="thickness">The thickness.</param>
 /// <param name="lineStyle">The line style.</param>
 /// <param name="lineJoin">The line join.</param>
 public OxyPen(
     OxyColor color,
     double thickness = 1.0,
     LineStyle lineStyle = LineStyle.Solid,
     LineJoin lineJoin = LineJoin.Miter)
 {
     this.Color = color;
     this.Thickness = thickness;
     this.DashArray = lineStyle.GetDashArray();
     this.LineStyle = lineStyle;
     this.LineJoin = lineJoin;
 }
        protected void RenderUnClippedLine(IRenderContext rc, IList <ScreenPoint> pointsToRender, OxyColor lineColor, double strokeness, LineStyle lineStyle)
        {
            var screenPoints    = pointsToRender;
            var resampledPoints = ScreenPointHelper.ResamplePoints(pointsToRender, 2);

            screenPoints = CreateSpline(resampledPoints, 0.5, null, false, 0.25);

            var outputBuffer = new List <ScreenPoint>(pointsToRender.Count);

            var dash_array = lineStyle.GetDashArray();

            rc.DrawLine(pointsToRender, lineColor, strokeness, dash_array, LineJoin.Round, false);
        }
        /// <summary>
        /// Draws the clipped line.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="points">The points.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="minDistSquared">The squared minimum distance.</param>
        /// <param name="stroke">The stroke.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="lineStyle">The line style.</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="aliased">if set to <c>true</c> [aliased].</param>
        /// <param name="pointsRendered">The points rendered callback.</param>
        public static void DrawClippedLine(
            this IRenderContext rc,
            IList <ScreenPoint> points,
            OxyRect clippingRectangle,
            double minDistSquared,
            OxyColor stroke,
            double strokeThickness,
            LineStyle lineStyle,
            OxyPenLineJoin lineJoin,
            bool aliased,
            Action <IList <ScreenPoint> > pointsRendered = null)
        {
            var clipping = new CohenSutherlandClipping(clippingRectangle.Left, clippingRectangle.Right, clippingRectangle.Top, clippingRectangle.Bottom);

            var pts = new List <ScreenPoint>();
            int n   = points.Count;

            if (n > 0)
            {
                if (n == 1)
                {
                    pts.Add(points[0]);
                }

                var last = points[0];
                for (int i = 1; i < n; i++)
                {
                    var s0 = points[i - 1];
                    var s1 = points[i];

                    // Clipped version of this and next point.
                    var  sc0      = s0;
                    var  sc1      = s1;
                    bool isInside = clipping.ClipLine(ref sc0, ref sc1);

                    if (!isInside)
                    {
                        // keep the previous coordinate
                        continue;
                    }

                    // render from s0c-s1c
                    double dx = sc1.x - last.x;
                    double dy = sc1.y - last.y;

                    if ((dx * dx) + (dy * dy) > minDistSquared || i == 1 || i == n - 1)
                    {
                        if (!sc0.Equals(last) || i == 1)
                        {
                            pts.Add(sc0);
                        }

                        pts.Add(sc1);
                        last = sc1;
                    }

                    // render the line if we are leaving the clipping region););
                    if (!clipping.IsInside(s1))
                    {
                        if (pts.Count > 0)
                        {
                            EnsureNonEmptyLineIsVisible(pts);
                            rc.DrawLine(pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
                            if (pointsRendered != null)
                            {
                                pointsRendered(pts);
                            }

                            pts = new List <ScreenPoint>();
                        }
                    }
                }

                if (pts.Count > 0)
                {
                    EnsureNonEmptyLineIsVisible(pts);
                    rc.DrawLine(pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);

                    // Execute the 'callback'.
                    if (pointsRendered != null)
                    {
                        pointsRendered(pts);
                    }
                }
            }
        }
        /// <summary>
        /// Draws the clipped line.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="points">The points.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="minDistSquared">The squared minimum distance.</param>
        /// <param name="stroke">The stroke.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="lineStyle">The line style.</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="aliased">if set to <c>true</c> [aliased].</param>
        /// <param name="pointsRendered">The points rendered callback.</param>
        public static void DrawClippedLine(
            this IRenderContext rc,
            IList<ScreenPoint> points,
            OxyRect clippingRectangle,
            double minDistSquared,
            OxyColor stroke,
            double strokeThickness,
            LineStyle lineStyle,
            OxyPenLineJoin lineJoin,
            bool aliased,
            Action<IList<ScreenPoint>> pointsRendered = null)
        {
            var clipping = new CohenSutherlandClipping(clippingRectangle.Left, clippingRectangle.Right, clippingRectangle.Top, clippingRectangle.Bottom);

            var pts = new List<ScreenPoint>();
            int n = points.Count;
            if (n > 0)
            {
                if (n == 1)
                {
                    pts.Add(points[0]);
                }

                var last = points[0];
                for (int i = 1; i < n; i++)
                {
                    var s0 = points[i - 1];
                    var s1 = points[i];

                    // Clipped version of this and next point.
                    var sc0 = s0;
                    var sc1 = s1;
                    bool isInside = clipping.ClipLine(ref sc0, ref sc1);

                    if (!isInside)
                    {
                        // keep the previous coordinate
                        continue;
                    }

                    // render from s0c-s1c
                    double dx = sc1.x - last.x;
                    double dy = sc1.y - last.y;

                    if ((dx * dx) + (dy * dy) > minDistSquared || i == 1 || i == n - 1)
                    {
                        if (!sc0.Equals(last) || i == 1)
                        {
                            pts.Add(sc0);
                        }

                        pts.Add(sc1);
                        last = sc1;
                    }

                    // render the line if we are leaving the clipping region););
                    if (!clipping.IsInside(s1))
                    {
                        if (pts.Count > 0)
                        {
                            EnsureNonEmptyLineIsVisible(pts);
                            rc.DrawLine(pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
                            if (pointsRendered != null)
                            {
                                pointsRendered(pts);
                            }

                            pts = new List<ScreenPoint>();
                        }
                    }
                }

                if (pts.Count > 0)
                {
                    EnsureNonEmptyLineIsVisible(pts);
                    rc.DrawLine(pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);

                    // Execute the 'callback'.
                    if (pointsRendered != null)
                    {
                        pointsRendered(pts);
                    }
                }
            }
        }
        /// <summary>
        /// Draws the polygon within the specified clipping rectangle.
        /// </summary>
        /// <param name="rc">
        /// The render context.
        /// </param>
        /// <param name="points">
        /// The points.
        /// </param>
        /// <param name="clippingRectangle">
        /// The clipping rectangle.
        /// </param>
        /// <param name="minDistSquared">
        /// The squared minimum distance between points.
        /// </param>
        /// <param name="fill">
        /// The fill.
        /// </param>
        /// <param name="stroke">
        /// The stroke.
        /// </param>
        /// <param name="strokeThickness">
        /// The stroke thickness.
        /// </param>
        /// <param name="lineStyle">
        /// The line style.
        /// </param>
        /// <param name="lineJoin">
        /// The line join.
        /// </param>
        /// <param name="aliased">
        /// The aliased.
        /// </param>
        public static void DrawClippedPolygon(
            this IRenderContext rc,
            IList<ScreenPoint> points,
            OxyRect clippingRectangle,
            double minDistSquared,
            OxyColor fill,
            OxyColor stroke,
            double strokeThickness = 1.0,
            LineStyle lineStyle = LineStyle.Solid,
            OxyPenLineJoin lineJoin = OxyPenLineJoin.Miter,
            bool aliased = false)
        {
            if (rc.SetClip(clippingRectangle))
            {
                rc.DrawPolygon(points, fill, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
                rc.ResetClip();
                return;
            }

            var clippedPoints = SutherlandHodgmanClipping.ClipPolygon(clippingRectangle, points);

            rc.DrawPolygon(
                clippedPoints, fill, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
        }
        /// <summary>
        /// Draws the clipped line segments.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="points">The points.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="stroke">The stroke.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="lineStyle">The line style.</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="aliased">if set to <c>true</c> [aliased].</param>
        public static void DrawClippedLineSegments(
            this IRenderContext rc,
            IList<ScreenPoint> points,
            OxyRect clippingRectangle,
            OxyColor stroke,
            double strokeThickness,
            LineStyle lineStyle,
            OxyPenLineJoin lineJoin,
            bool aliased)
        {
            if (rc.SetClip(clippingRectangle))
            {
                rc.DrawLineSegments(points, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
                rc.ResetClip();
                return;
            }

            var clipping = new CohenSutherlandClipping(clippingRectangle.Left, clippingRectangle.Right, clippingRectangle.Top, clippingRectangle.Bottom);

            var clippedPoints = new List<ScreenPoint>(points.Count);
            for (int i = 0; i + 1 < points.Count; i += 2)
            {
                var s0 = points[i];
                var s1 = points[i + 1];
                if (clipping.ClipLine(ref s0, ref s1))
                {
                    clippedPoints.Add(s0);
                    clippedPoints.Add(s1);
                }
            }

            rc.DrawLineSegments(clippedPoints, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
        }
        /// <summary>
        /// Draws the clipped line.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="points">The points.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="minDistSquared">The min dist squared.</param>
        /// <param name="stroke">The stroke.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="lineStyle">The line style.</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="aliased">if set to <c>true</c> [aliased].</param>
        /// <param name="pointsRendered">The points rendered callback.</param>
        public static void DrawClippedLine(
            this IRenderContext rc,
            IList <ScreenPoint> points,
            OxyRect clippingRectangle,
            double minDistSquared,
            OxyColor stroke,
            double strokeThickness,
            LineStyle lineStyle,
            OxyPenLineJoin lineJoin,
            bool aliased,
            Action <IList <ScreenPoint> > pointsRendered = null)
        {
            var clipping = new CohenSutherlandClipping(clippingRectangle.Left, clippingRectangle.Right, clippingRectangle.Top, clippingRectangle.Bottom);

            var pts = new List <ScreenPoint>();
            int n   = points.Count;

            if (n > 0)
            {
                if (n == 1)
                {
                    pts.Add(points[0]);
                }

                var last = points[0];
                for (int i = 1; i < n; i++)
                {
                    var s0 = points[i - 1];
                    var s1 = points[i];

                    // Clipped version of this and next point.
                    var  s0c      = s0;
                    var  s1c      = s1;
                    bool isInside = clipping.ClipLine(ref s0c, ref s1c);
                    s0 = s1;

                    if (!isInside)
                    {
                        // keep the previous coordinate
                        continue;
                    }

                    // render from s0c-s1c
                    double dx = s1c.x - last.x;
                    double dy = s1c.y - last.y;

                    if (dx * dx + dy * dy > minDistSquared || i == 1 || i == n - 1)
                    {
                        if (!s0c.Equals(last) || i == 1)
                        {
                            pts.Add(s0c);
                        }

                        pts.Add(s1c);
                        last = s1c;
                    }

                    // render the line if we are leaving the clipping region););
                    if (!clipping.IsInside(s1))
                    {
                        if (pts.Count > 0)
                        {
                            rc.DrawLine(
                                pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
                            if (pointsRendered != null)
                            {
                                pointsRendered(pts);
                            }

                            pts = new List <ScreenPoint>();
                        }
                    }
                }

                // Check if the line contains two points and they are at the same point
                if (pts.Count == 2)
                {
                    if (pts[0].DistanceTo(pts[1]) < 1)
                    {
                        // Modify to a small horizontal line to make sure it is being rendered
                        pts[1] = new ScreenPoint(pts[0].X + 1, pts[0].Y);
                        pts[0] = new ScreenPoint(pts[0].X - 1, pts[0].Y);
                    }
                }

                // Check if the line contains a single point
                if (pts.Count == 1)
                {
                    // Add a second point to make sure the line is being rendered as a small dot
                    pts.Add(new ScreenPoint(pts[0].X + 1, pts[0].Y));
                    pts[0] = new ScreenPoint(pts[0].X - 1, pts[0].Y);
                }

                if (pts.Count > 0)
                {
                    rc.DrawLine(pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);

                    // Execute the 'callback'.
                    if (pointsRendered != null)
                    {
                        pointsRendered(pts);
                    }
                }
            }
        }
        /// <summary>
        /// Draws the clipped line.
        /// </summary>
        /// <param name="rc">The render context.</param>
        /// <param name="points">The points.</param>
        /// <param name="clippingRectangle">The clipping rectangle.</param>
        /// <param name="minDistSquared">The min dist squared.</param>
        /// <param name="stroke">The stroke.</param>
        /// <param name="strokeThickness">The stroke thickness.</param>
        /// <param name="lineStyle">The line style.</param>
        /// <param name="lineJoin">The line join.</param>
        /// <param name="aliased">if set to <c>true</c> [aliased].</param>
        /// <param name="pointsRendered">The points rendered callback.</param>
        public static void DrawClippedLine(
            this IRenderContext rc,
            IList<ScreenPoint> points,
            OxyRect clippingRectangle,
            double minDistSquared,
            OxyColor stroke,
            double strokeThickness,
            LineStyle lineStyle,
            OxyPenLineJoin lineJoin,
            bool aliased,
            Action<IList<ScreenPoint>> pointsRendered = null)
        {
            var clipping = new CohenSutherlandClipping(clippingRectangle.Left, clippingRectangle.Right, clippingRectangle.Top, clippingRectangle.Bottom);

            var pts = new List<ScreenPoint>();
            int n = points.Count;
            if (n > 0)
            {

                if (n == 1)
                {
                    pts.Add(points[0]);
                }

                var last = points[0];
                for (int i = 1; i < n; i++)
                {
                    var s0 = points[i - 1];
                    var s1 = points[i];

                    // Clipped version of this and next point.
                    var s0c = s0;
                    var s1c = s1;
                    bool isInside = clipping.ClipLine(ref s0c, ref s1c);
                    s0 = s1;

                    if (!isInside)
                    {
                        // keep the previous coordinate
                        continue;
                    }

                    // render from s0c-s1c
                    double dx = s1c.x - last.x;
                    double dy = s1c.y - last.y;

                    if (dx * dx + dy * dy > minDistSquared || i == 1 || i == n - 1)
                    {
                        if (!s0c.Equals(last) || i == 1)
                        {
                            pts.Add(s0c);
                        }

                        pts.Add(s1c);
                        last = s1c;
                    }

                    // render the line if we are leaving the clipping region););
                    if (!clipping.IsInside(s1))
                    {
                        if (pts.Count > 0)
                        {
                            rc.DrawLine(
                                pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);
                            if (pointsRendered != null)
                            {
                                pointsRendered(pts);
                            }

                            pts = new List<ScreenPoint>();
                        }
                    }
                }

                // Check if the line contains two points and they are at the same point
                if (pts.Count == 2)
                {
                    if (pts[0].DistanceTo(pts[1]) < 1)
                    {
                        // Modify to a small horizontal line to make sure it is being rendered
                        pts[1] = new ScreenPoint(pts[0].X + 1, pts[0].Y);
                        pts[0] = new ScreenPoint(pts[0].X - 1, pts[0].Y);
                    }
                }

                // Check if the line contains a single point
                if (pts.Count == 1)
                {
                    // Add a second point to make sure the line is being rendered as a small dot
                    pts.Add(new ScreenPoint(pts[0].X + 1, pts[0].Y));
                    pts[0] = new ScreenPoint(pts[0].X - 1, pts[0].Y);
                }

                if (pts.Count > 0)
                {
                    rc.DrawLine(pts, stroke, strokeThickness, lineStyle.GetDashArray(), lineJoin, aliased);

                    // Execute the 'callback'.
                    if (pointsRendered != null)
                    {
                        pointsRendered(pts);
                    }
                }
            }
        }
        public override void Render(IRenderContext rc, PlotModel model1, AxisLayer axisLayer, int pass)
        {
#if DEBUG_MAP
            Console.WriteLine("render timecategoryaxis " + this.Name);
#endif
            PlotModel model           = this.PlotModel;
            OxyColor  live_color      = OxyColors.Red;
            OxyColor  forecast_color  = OxyColors.Red;
            OxyColor  separator_color = OxyColors.Red;
            OxyColor  grid_color      = OxyColors.Red;
            //OxyColor line_color = OxyColors.Red;
            if (Theme != null)
            {
                AxisStyle style = Theme.GetStyle(ThemeMode) as AxisStyle;
                TitleColor      = Helper.ConvertColorToOxyColor(style.TitleColor);
                TextColor       = Helper.ConvertColorToOxyColor(style.LabelColor);
                TicklineColor   = Helper.ConvertColorToOxyColor(style.LineColor);
                live_color      = Helper.ConvertColorToOxyColor(style.LiveColor);
                forecast_color  = Helper.ConvertColorToOxyColor(style.ForecastColor);
                separator_color = Helper.ConvertColorToOxyColor(style.SepatorColor);
                grid_color      = Helper.ConvertColorToOxyColor(style.GridColor);
            }

            //找到所有的y轴
            if (TimeLines != null)
            {
                //绘制线标值和线条
                FeatureTextIntersector intersector = new FeatureTextIntersector(FeatureTextIntersector.SortStyle.Horizontal, 3);
                for (int i = 0; i < TimeLines.Count; i++)
                {
                    string  label = TimeLines[i].Time.ToString("dd-HH");
                    OxySize size  = rc.MeasureText(label);
                    double  x     = TransformX(TimeLines[i].Index);
                    if (x < model.PlotArea.Left || x > model.PlotArea.Right)
                    {
                        continue;
                    }

                    double y  = model.PlotArea.Bottom;
                    double y2 = y + 5;

                    //if (TimeLines[i].TimeStyle == TimeStyle.Seperator)
                    //    continue;

                    intersector.Add(new FeatureText(label, new ScreenPoint(x, y + 7), size, new ScreenPoint(x, y)));
                }
                List <FeatureText> features = intersector.DiscaredIntersection(this.Angle);
                if (features != null)
                {
                    foreach (FeatureText feature in features)
                    {
                        rc.DrawText(feature.Position, feature.Text, TextColor, this.ActualFont, this.ActualFontSize, 200, this.Angle, HorizontalAlignment.Left, VerticalAlignment.Middle);
                    }
                }
                //绘制纵线
                foreach (Axis axis in model.Axes)
                {
                    if (axis.Position == AxisPosition.Left || axis.Position == AxisPosition.Right)
                    {
                        if (axis is IAxis)
                        {
                            IAxis y_axis = axis as IAxis;
                            if (!y_axis.AxisVisible)
                            {
                                continue;
                            }
                            foreach (TimeLine line in TimeLines)
                            {
                                OxyColor  color     = OxyColors.Red;
                                double    thickness = 1;
                                LineStyle style     = LineStyle.Solid;
                                switch (line.TimeStyle)
                                {
                                case TimeStyle.Forecast:
                                    color = forecast_color;
                                    style = LineStyle.Dash;
                                    break;

                                case TimeStyle.Live:
                                    color = live_color;
                                    break;

                                case TimeStyle.Seperator:
                                    color     = separator_color;
                                    style     = LineStyle.Dash;
                                    thickness = 2;
                                    break;
                                }

                                IList <ScreenPoint> sps = new List <ScreenPoint>();
                                double x   = TransformX(line.Index);
                                double top = y_axis.Bound.Top;
                                sps.Add(new ScreenPoint(x, top));
                                sps.Add(new ScreenPoint(x, y_axis.Bound.Bottom));

                                rc.DrawClippedLine(y_axis.Bound, sps, 2, color, thickness, style.GetDashArray(), LineJoin.Round, false);
                            }
                        }
                    }
                }
            }
        }