/// <summary> /// Renders the transformed points as a line (smoothed if <see cref="InterpolationAlgorithm"/> isn’t <c>null</c>) and markers (if <see cref="MarkerType"/> is not <c>None</c>). /// </summary> /// <param name="rc">The render context.</param> /// <param name="clippingRect">The clipping rectangle.</param> /// <param name="pointsToRender">The points to render.</param> protected virtual void RenderLineAndMarkers(IRenderContext rc, OxyRect clippingRect, IList <ScreenPoint> pointsToRender) { var screenPoints = pointsToRender; if (this.InterpolationAlgorithm != null) { // spline smoothing (should only be used on small datasets) var resampledPoints = ScreenPointHelper.ResamplePoints(pointsToRender, this.MinimumSegmentLength); screenPoints = this.InterpolationAlgorithm.CreateSpline(resampledPoints, false, 0.25); } // clip the line segments with the clipping rectangle if (this.StrokeThickness > 0 && this.ActualLineStyle != LineStyle.None) { this.RenderLine(rc, clippingRect, screenPoints); } if (this.MarkerType != MarkerType.None) { var markerBinOffset = this.MarkerResolution > 0 ? this.Transform(this.MinX, this.MinY) : default(ScreenPoint); rc.DrawMarkers( clippingRect, pointsToRender, this.MarkerType, this.MarkerOutline, new[] { this.MarkerSize }, this.ActualMarkerFill, this.MarkerStroke, this.MarkerStrokeThickness, this.EdgeRenderingMode, this.MarkerResolution, markerBinOffset); } }
/// <summary> /// Renders a chunk of points on the screen. /// </summary> /// <param name="context">Render context.</param> /// <param name="points">Screen points.</param> /// <returns>The list of resampled points.</returns> protected virtual List <ScreenPoint> RenderScreenPoints(AreaRenderContext context, List <ScreenPoint> points) { var final = points; if (context.Reverse) { final.Reverse(); } if (this.InterpolationAlgorithm != null) { var resampled = ScreenPointHelper.ResamplePoints(final, this.MinimumSegmentLength); final = this.InterpolationAlgorithm.CreateSpline(resampled, false, 0.25); } context.RenderContext.DrawClippedLine( context.ClippingRect, final, context.MinDistSquared, this.GetSelectableColor(context.Color), this.StrokeThickness, this.EdgeRenderingMode, context.DashArray, this.LineJoin); return(final); }
public void ResamplePoints() { var points = CreatePointList(); var result = ScreenPointHelper.ResamplePoints(points, 1); Assert.AreEqual(4, result.Count); }
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); } }
/// <summary> /// Renders the transformed points. /// </summary> /// <param name="rc"> /// The render context. /// </param> /// <param name="clippingRect"> /// The clipping rectangle. /// </param> /// <param name="pointsToRender"> /// The points to render. /// </param> protected void RenderPoints(IRenderContext rc, OxyRect clippingRect, IList <ScreenPoint> pointsToRender) { var screenPoints = pointsToRender; if (this.Smooth) { // spline smoothing (should only be used on small datasets) var resampledPoints = ScreenPointHelper.ResamplePoints(pointsToRender, this.MinimumSegmentLength); screenPoints = CanonicalSplineHelper.CreateSpline(resampledPoints, 0.5, null, false, 0.25); } // clip the line segments with the clipping rectangle if (this.StrokeThickness > 0 && this.ActualLineStyle != LineStyle.None) { this.RenderSmoothedLine(rc, clippingRect, screenPoints); } if (this.MarkerType != MarkerType.None) { rc.DrawMarkers( pointsToRender, clippingRect, this.MarkerType, this.MarkerOutline, new[] { this.MarkerSize }, this.MarkerFill, this.MarkerStroke, this.MarkerStrokeThickness); } }
/// <summary> /// Renders a chunk of points on the screen. /// </summary> /// <param name="context">Render context.</param> /// <param name="points">Screen points.</param> /// <returns>The list of resampled points.</returns> protected virtual List <ScreenPoint> RenderScreenPoints(AreaRenderContext context, List <ScreenPoint> points) { var final = points; if (context.Reverse) { final.Reverse(); } if (this.Smooth) { var resampled = ScreenPointHelper.ResamplePoints(final, this.MinimumSegmentLength); final = CanonicalSplineHelper.CreateSpline(resampled, 0.5, null, false, 0.25); } context.RenderContext.DrawClippedLine( context.ClippingRect, final, context.MinDistSquared, this.GetSelectableColor(context.Color), this.StrokeThickness, context.DashArray, this.LineJoin, false); return(final); }
public void GetCentroid() { var points = CreatePointList(); var centroid = ScreenPointHelper.GetCentroid(points); Assert.AreEqual(0.041666, centroid.X, 1e-6); Assert.AreEqual(0.708333, centroid.Y, 1e-6); }
protected TrackerHitResult MyGetNearestInterpolatedPointInternal(List <DataPoint> points, ScreenPoint point) { if (this.XAxis == null || this.YAxis == null || points == null) { return(null); } var spn = default(ScreenPoint); var dpn = default(DataPoint); double index = -1; double minimumDistance = double.MaxValue; for (int i = 0; i + 1 < points.Count; i++) { var p1 = points[i]; var p2 = points[i + 1]; if (!this.IsValidPoint(p1) || !this.IsValidPoint(p2)) { continue; } var sp1 = this.Transform(p1); var sp2 = this.Transform(p2); // Find the nearest point on the line segment. var spl = ScreenPointHelper.FindPointOnLine(point, sp1, sp2); if (ScreenPoint.IsUndefined(spl)) { // P1 && P2 coincident continue; } double l2 = (point - spl).LengthSquared; if (l2 < minimumDistance) { double segmentLength = (sp2 - sp1).Length; double u = segmentLength > 0 ? (spl - sp1).Length / segmentLength : 0; dpn = new DataPoint(p1.X + (u * (p2.X - p1.X)), p1.Y + (u * (p2.Y - p1.Y))); spn = spl; minimumDistance = l2; index = i + u; } } if (minimumDistance < double.MaxValue) { object item = this.GetItem((int)index); return(new MySignalTrackerHitResult(ParentControl, this, dpn, spn, item) { Index = index }); } return(null); }
/// <summary> /// Gets the point on the series that is nearest the specified point. /// </summary> /// <param name="point">The point.</param> /// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param> /// <returns>A TrackerHitResult for the current hit.</returns> public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) { var points = this.Points; if (points == null) { return(null); } var spn = default(ScreenPoint); var dpn = default(DataPoint); double index = -1; double minimumDistance = double.MaxValue; for (int i = 0; i + 1 < points.Count; i += 2) { var p1 = points[i]; var p2 = points[i + 1]; if (!this.IsValidPoint(p1) || !this.IsValidPoint(p2)) { continue; } var sp1 = this.Transform(p1); var sp2 = this.Transform(p2); // Find the nearest point on the line segment. var spl = ScreenPointHelper.FindPointOnLine(point, sp1, sp2); if (ScreenPoint.IsUndefined(spl)) { // P1 && P2 coincident continue; } double l2 = (point - spl).LengthSquared; if (l2 < minimumDistance) { double u = (spl - sp1).Length / (sp2 - sp1).Length; dpn = new DataPoint(p1.X + (u * (p2.X - p1.X)), p1.Y + (u * (p2.Y - p1.Y))); spn = spl; minimumDistance = l2; index = i + u; } } if (minimumDistance < double.MaxValue) { return(new TrackerHitResult(this, dpn, spn, this.GetItem((int)index)) { Index = index }); } return(null); }
protected override HitTestResult HitTestOverride(HitTestArguments args) { if (this.actualBounds == null) { return(null); } return(ScreenPointHelper.IsPointInPolygon(args.Point, this.actualBounds) ? new HitTestResult(this, args.Point) : null); }
/// <summary> /// Tests if the plot element is hit by the specified point. /// </summary> /// <param name="point"> /// The point. /// </param> /// <param name="tolerance"> /// The tolerance. /// </param> /// <returns> /// A hit test result. /// </returns> protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) { if (this.actualBounds == null) { return(null); } // Todo: see if performance can be improved by checking rectangle (with rotation and alignment), not polygon return(ScreenPointHelper.IsPointInPolygon(point, this.actualBounds) ? new HitTestResult(point) : null); }
/// <summary> /// When overridden in a derived class, tests if the plot element is hit by the specified point. /// </summary> /// <param name="args">The hit test arguments.</param> /// <returns> /// The result of the hit test. /// </returns> protected override HitTestResult HitTestOverride(HitTestArguments args) { if (this.actualBounds == null) { return(null); } // Todo: see if performance can be improved by checking rectangle (with rotation and alignment), not polygon return(ScreenPointHelper.IsPointInPolygon(args.Point, this.actualBounds) ? new HitTestResult(this, args.Point) : null); }
/// <summary> /// When overridden in a derived class, tests if the plot element is hit by the specified point. /// </summary> /// <param name="args">The hit test arguments.</param> /// <returns> /// The result of the hit test. /// </returns> protected override HitTestResult HitTestOverride(HitTestArguments args) { if (this.screenPoints == null) { // Points not specified. return(null); } return(ScreenPointHelper.IsPointInPolygon(args.Point, this.screenPoints) ? new HitTestResult(this, args.Point) : null); }
/// <summary> /// Gets the screen points. /// </summary> /// <returns>The list of points to display on screen for this path.</returns> protected override IList <ScreenPoint> GetScreenPoints() { var screenPoints = this.Points.Select(this.Transform).ToList(); if (this.InterpolationAlgorithm != null) { var resampledPoints = ScreenPointHelper.ResamplePoints(screenPoints, this.MinimumSegmentLength); return(this.InterpolationAlgorithm.CreateSpline(resampledPoints, false, 0.25)); } return(this.Points.Select(this.Transform).ToList()); }
/// <summary> /// Gets the screen points. /// </summary> /// <returns>The list of points to display on screen for this path.</returns> protected override IList <ScreenPoint> GetScreenPoints() { var screenPoints = this.Points.Select(this.Transform).ToList(); if (this.Smooth) { var resampledPoints = ScreenPointHelper.ResamplePoints(screenPoints, this.MinimumSegmentLength); return(CanonicalSplineHelper.CreateSpline(resampledPoints, 0.5, null, false, 0.25)); } return(this.Points.Select(this.Transform).ToList()); }
/// <summary> /// When overridden in a derived class, tests if the plot element is hit by the specified point. /// </summary> /// <param name="args">The hit test arguments.</param> /// <returns> /// The result of the hit test. /// </returns> protected override HitTestResult HitTestOverride(HitTestArguments args) { var nearestPoint = ScreenPointHelper.FindNearestPointOnPolyline(args.Point, this.screenPoints); double dist = (args.Point - nearestPoint).Length; if (dist < args.Tolerance) { return(new HitTestResult(this, nearestPoint)); } return(null); }
/// <summary> /// Tests if the plot element is hit by the specified point. /// </summary> /// <param name="point">The point.</param> /// <param name="tolerance">The tolerance.</param> /// <returns> /// A hit test result. /// </returns> protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) { var nearestPoint = ScreenPointHelper.FindNearestPointOnPolyline(point, this.screenPoints); double dist = (point - nearestPoint).Length; if (dist < tolerance) { return(new HitTestResult(nearestPoint)); } return(null); }
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> /// Gets the point on the series that is nearest the specified point. /// </summary> /// <param name="point">The point.</param> /// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param> /// <returns>A TrackerHitResult for the current hit.</returns> public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) { if (this.XAxis == null || this.YAxis == null) { return(null); } if (interpolate) { return(null); } TrackerHitResult result = null; // http://paulbourke.net/geometry/pointlineplane/ double minimumDistance = double.MaxValue; var points = this.ActualPoints; for (int i = 0; i < points.Count; i++) { var p1 = points[i]; var basePoint = new DataPoint(p1.X, this.Base); var sp1 = this.Transform(p1); var sp2 = this.Transform(basePoint); var u = ScreenPointHelper.FindPositionOnLine(point, sp1, sp2); if (double.IsNaN(u)) { continue; } if (u < 0 || u > 1) { continue; // outside line } var sp = sp1 + ((sp2 - sp1) * u); double distance = (point - sp).LengthSquared; if (distance < minimumDistance) { result = new TrackerHitResult( this, new DataPoint(p1.X, p1.Y), new ScreenPoint(sp1.x, sp1.y), this.GetItem(i)); minimumDistance = distance; } } return(result); }
/// <summary> /// Renders the polygon annotation. /// </summary> /// <param name="rc">The render context.</param> public override void Render(IRenderContext rc) { base.Render(rc); if (this.Points == null) { return; } // transform to screen coordinates this.screenPoints = this.Points.Select(this.Transform).ToList(); if (this.screenPoints.Count == 0) { return; } // clip to the area defined by the axes var clippingRectangle = this.GetClippingRect(); const double MinimumSegmentLength = 4; rc.DrawClippedPolygon( clippingRectangle, this.screenPoints, MinimumSegmentLength * MinimumSegmentLength, this.GetSelectableFillColor(this.Fill), this.GetSelectableColor(this.Stroke), this.StrokeThickness, this.EdgeRenderingMode, this.LineStyle, this.LineJoin); if (!string.IsNullOrEmpty(this.Text)) { this.GetActualTextAlignment(out var ha, out var va); var textPosition = this.GetActualTextPosition(() => ScreenPointHelper.GetCentroid(this.screenPoints)); rc.DrawClippedText( clippingRectangle, textPosition, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, this.TextRotation, ha, va); } }
/// <summary> /// Renders the polygon annotation. /// </summary> /// <param name="rc"> /// The render context. /// </param> /// <param name="model"> /// The plot model. /// </param> public override void Render(IRenderContext rc, PlotModel model) { base.Render(rc, model); if (this.Points == null) { return; } // transform to screen coordinates this.screenPoints = this.Points.Select(p => this.Transform(p)).ToList(); if (this.screenPoints.Count == 0) { return; } // clip to the area defined by the axes var clipping = this.GetClippingRect(); const double MinimumSegmentLength = 4; rc.DrawClippedPolygon( this.screenPoints, clipping, MinimumSegmentLength * MinimumSegmentLength, this.GetSelectableFillColor(this.Fill), this.GetSelectableColor(this.Color), this.StrokeThickness, this.LineStyle, this.LineJoin); if (!string.IsNullOrEmpty(this.Text)) { var textPosition = ScreenPointHelper.GetCentroid(this.screenPoints); rc.DrawClippedText( clipping, textPosition, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, 0, HorizontalAlignment.Center, VerticalAlignment.Middle); } }
protected override void RenderLineAndMarkers(IRenderContext rc, OxyRect clippingRect, IList <ScreenPoint> pointsToRender) { if (Smooth) { pointsToRender = CatmullRomSplineHelper.CreateSpline(ScreenPointHelper.ResamplePoints(pointsToRender, MinimumSegmentLength), 0.5, 0.25 / _smoothessMultipler); } if (StrokeThickness > 0.0 && ActualLineStyle != LineStyle.None) { RenderLine(rc, clippingRect, pointsToRender); } if (MarkerType != MarkerType.None) { var binOffset = MarkerResolution > 0 ? Transform(MinX, MinY) : new ScreenPoint(); rc.DrawMarkers(clippingRect, pointsToRender, MarkerType, MarkerOutline, new[] { MarkerSize }, ActualMarkerFill, MarkerStroke, MarkerStrokeThickness, MarkerResolution, binOffset); } }
/// <summary> /// Tests if the plot element is hit by the specified point. /// </summary> /// <param name="point"> /// The point. /// </param> /// <param name="tolerance"> /// The tolerance. /// </param> /// <returns> /// A hit test result. /// </returns> protected internal override HitTestResult HitTest(ScreenPoint point, double tolerance) { if ((point - this.screenStartPoint).Length < tolerance) { return(new HitTestResult(this.screenStartPoint, null, 1)); } if ((point - this.screenEndPoint).Length < tolerance) { return(new HitTestResult(this.screenEndPoint, null, 2)); } var p = ScreenPointHelper.FindPointOnLine(point, this.screenStartPoint, this.screenEndPoint); if ((p - point).Length < tolerance) { return(new HitTestResult(p)); } return(null); }
/// <summary> /// Gets the point on the series that is nearest the specified point. /// </summary> /// <param name="point">The point.</param> /// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c> .</param> /// <returns>A TrackerHitResult for the current hit.</returns> public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) { for (int i = 0; i < this.slicePoints.Count; i++) { if (ScreenPointHelper.IsPointInPolygon(point, this.slicePoints[i])) { var slice = this.slices[i]; var item = this.GetItem(i); return(new TrackerHitResult { Series = this, Position = point, Item = item, Index = i, Text = StringHelper.Format(this.ActualCulture, this.TrackerFormatString, slice, this.Title, slice.Label, slice.Value, slice.Value / this.total) }); } } return(null); }
/// <summary> /// When overridden in a derived class, tests if the plot element is hit by the specified point. /// </summary> /// <param name="args">The hit test arguments.</param> /// <returns> /// The result of the hit test. /// </returns> protected override HitTestResult HitTestOverride(HitTestArguments args) { if ((args.Point - this.screenStartPoint).Length < args.Tolerance) { return(new HitTestResult(this, this.screenStartPoint, null, 1)); } if ((args.Point - this.screenEndPoint).Length < args.Tolerance) { return(new HitTestResult(this, this.screenEndPoint, null, 2)); } var p = ScreenPointHelper.FindPointOnLine(args.Point, this.screenStartPoint, this.screenEndPoint); if ((p - args.Point).Length < args.Tolerance) { return(new HitTestResult(this, p)); } return(null); }
/// <summary> /// Gets the point on the curve that is nearest the specified point. /// </summary> /// <param name="points">The point list.</param> /// <param name="startIdx">The index to start from.</param> /// <param name="point">The point.</param> /// <returns>A tracker hit result if a point was found.</returns> /// <remarks>The Text property of the result will not be set, since the formatting depends on the various series.</remarks> protected TrackerHitResult GetNearestInterpolatedPointInternal(List <DataPoint> points, int startIdx, ScreenPoint point) { if (this.XAxis == null || this.YAxis == null || points == null) { return(null); } var spn = default(ScreenPoint); var dpn = default(DataPoint); double index = -1; double minimumDistance = double.MaxValue; for (int i = startIdx; i + 1 < points.Count; i++) { var p1 = points[i]; var p2 = points[i + 1]; if (!this.IsValidPoint(p1) || !this.IsValidPoint(p2)) { continue; } var sp1 = this.Transform(p1); var sp2 = this.Transform(p2); // Find the nearest point on the line segment. var spl = ScreenPointHelper.FindPointOnLine(point, sp1, sp2); if (ScreenPoint.IsUndefined(spl)) { // P1 && P2 coincident continue; } double l2 = (point - spl).LengthSquared; if (l2 < minimumDistance) { double segmentLength = (sp2 - sp1).Length; double u = segmentLength > 0 ? (spl - sp1).Length / segmentLength : 0; dpn = this.InverseTransform(spl); spn = spl; minimumDistance = l2; index = i + u; } } if (minimumDistance < double.MaxValue) { var item = this.GetItem((int)Math.Round(index)); return(new TrackerHitResult { Series = this, DataPoint = dpn, Position = spn, Item = item, Index = index }); } return(null); }
/// <summary> /// Renders the series on the specified rendering context. /// </summary> /// <param name="rc">The rendering context.</param> /// <param name="model">The owner plot model.</param> public override void Render(IRenderContext rc, PlotModel model) { var actualPoints = this.ActualPoints; var actualPoints2 = this.ActualPoints2; int n0 = actualPoints.Count; if (n0 == 0) { return; } this.VerifyAxes(); double minDistSquared = this.MinimumSegmentLength * this.MinimumSegmentLength; var clippingRect = this.GetClippingRect(); rc.SetClip(clippingRect); // Transform all points to screen coordinates IList <ScreenPoint> pts0 = new ScreenPoint[n0]; for (int i = 0; i < n0; i++) { pts0[i] = this.XAxis.Transform(actualPoints[i].X, actualPoints[i].Y, this.YAxis); } int n1 = actualPoints2.Count; IList <ScreenPoint> pts1 = new ScreenPoint[n1]; for (int i = 0; i < n1; i++) { int j = this.Reverse2 ? n1 - 1 - i : i; pts1[j] = this.XAxis.Transform(actualPoints2[i].X, actualPoints2[i].Y, this.YAxis); } if (this.Smooth) { var rpts0 = ScreenPointHelper.ResamplePoints(pts0, this.MinimumSegmentLength); var rpts1 = ScreenPointHelper.ResamplePoints(pts1, this.MinimumSegmentLength); pts0 = CanonicalSplineHelper.CreateSpline(rpts0, 0.5, null, false, 0.25); pts1 = CanonicalSplineHelper.CreateSpline(rpts1, 0.5, null, false, 0.25); } var dashArray = this.ActualDashArray; // draw the clipped lines rc.DrawClippedLine( clippingRect, pts0, minDistSquared, this.GetSelectableColor(this.ActualColor), this.StrokeThickness, dashArray, this.LineJoin, false); rc.DrawClippedLine( clippingRect, pts1, minDistSquared, this.GetSelectableColor(this.ActualColor2), this.StrokeThickness, dashArray, this.LineJoin, false); // combine the two lines and draw the clipped area var pts = new List <ScreenPoint>(); pts.AddRange(pts1); pts.AddRange(pts0); // pts = SutherlandHodgmanClipping.ClipPolygon(clippingRect, pts); rc.DrawClippedPolygon(clippingRect, pts, minDistSquared, this.GetSelectableFillColor(this.ActualFill), OxyColors.Undefined); var markerSizes = new[] { this.MarkerSize }; // draw the markers on top rc.DrawMarkers( clippingRect, pts0, this.MarkerType, null, markerSizes, this.MarkerFill, this.MarkerStroke, this.MarkerStrokeThickness, 1); rc.DrawMarkers( clippingRect, pts1, this.MarkerType, null, markerSizes, this.MarkerFill, this.MarkerStroke, this.MarkerStrokeThickness, 1); rc.ResetClip(); }
/// <summary> /// Renders data points from the specified index to the specified maximum x, skipping NaN values. /// </summary> /// <param name="actualPoints">Points list.</param> /// <param name="chunksOfPoints">A list where chunks will be placed.</param> /// <param name="startIndex">The start index of the points to render.</param> /// <param name="maximumX">The maximum X coordinate to render.</param> /// <param name="rc">Render context</param> /// <param name="clippingRect">Clipping rectangle.</param> /// <param name="minDistSquared">Minimal distance squared.</param> /// <param name="reverse">Reverse points.</param> /// <param name="color">Stroke color.</param> private void RenderChunkedPoints(List <DataPoint> actualPoints, List <List <ScreenPoint> > chunksOfPoints, int startIndex, double maximumX, IRenderContext rc, OxyRect clippingRect, double minDistSquared, bool reverse, OxyColor color) { var dashArray = this.ActualDashArray; var screenPoints = new List <ScreenPoint>(); Action <List <ScreenPoint> > finalizeChunk = list => { var final = list; if (reverse) { final.Reverse(); } if (this.Smooth) { var resampled = ScreenPointHelper.ResamplePoints(final, this.MinimumSegmentLength); final = CanonicalSplineHelper.CreateSpline(resampled, 0.5, null, false, 0.25); } chunksOfPoints.Add(final); rc.DrawClippedLine( clippingRect, final, minDistSquared, this.GetSelectableColor(color), this.StrokeThickness, dashArray, this.LineJoin, false); }; int clipCount = 0; for (int i = startIndex; i < actualPoints.Count; i++) { var point = actualPoints[i]; if (double.IsNaN(point.Y)) { if (screenPoints.Count == 0) { continue; } finalizeChunk(screenPoints); screenPoints = new List <ScreenPoint>(); } else { var sp = this.XAxis.Transform(point.X, point.Y, this.YAxis); screenPoints.Add(sp); } // We break after two points were seen beyond xMax to ensure glitch-free rendering. clipCount += point.x > maximumX ? 1 : 0; if (clipCount > 1) { break; } } if (screenPoints.Count > 0) { finalizeChunk(screenPoints); } }
/// <summary> /// Gets the nearest point. /// </summary> /// <param name="point">The point.</param> /// <param name="interpolate">interpolate if set to <c>true</c> .</param> /// <returns>A TrackerHitResult for the current hit.</returns> public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) { if (this.XAxis == null || this.YAxis == null) { return(null); } double minimumDistance = double.MaxValue; var result = new TrackerHitResult(this, DataPoint.Undefined, ScreenPoint.Undefined); foreach (var item in this.Items) { foreach (var outlier in item.Outliers) { var sp = this.Transform(item.X, outlier); double d = (sp - point).LengthSquared; if (d < minimumDistance) { result.DataPoint = new DataPoint(item.X, outlier); result.Position = sp; result.Item = item; result.Text = this.Format( this.OutlierTrackerFormatString, item, this.Title, this.XAxis.GetValue(result.DataPoint.X), outlier); minimumDistance = d; } } // check if we are inside the box rectangle var rect = this.GetBoxRect(item); if (rect.Contains(point)) { result.DataPoint = new DataPoint(item.X, this.YAxis.InverseTransform(point.Y)); result.Position = this.Transform(result.DataPoint); result.Item = item; result.Text = this.Format( this.TrackerFormatString, item, this.Title, this.XAxis.GetValue(result.DataPoint.X), item.UpperWhisker, item.BoxTop, item.Median, item.BoxBottom, item.LowerWhisker); minimumDistance = 0; } var topWhisker = this.Transform(item.X, item.UpperWhisker); var bottomWhisker = this.Transform(item.X, item.LowerWhisker); // check if we are near the line var p = ScreenPointHelper.FindPointOnLine(point, topWhisker, bottomWhisker); double d2 = (p - point).LengthSquared; if (d2 < minimumDistance) { result.DataPoint = this.InverseTransform(p); result.Position = this.Transform(result.DataPoint); result.Item = item; result.Text = this.Format( this.TrackerFormatString, item, this.Title, this.XAxis.GetValue(result.DataPoint.X), item.UpperWhisker, item.BoxTop, item.Median, item.BoxBottom, item.LowerWhisker); minimumDistance = d2; } } if (minimumDistance < double.MaxValue) { return(result); } return(null); }
/// <summary> /// Gets the nearest point. /// </summary> /// <param name="point">The point.</param> /// <param name="interpolate">interpolate if set to <c>true</c> .</param> /// <returns>A TrackerHitResult for the current hit.</returns> public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate) { if (this.XAxis == null || this.YAxis == null) { return(null); } double minimumDistance = double.MaxValue; TrackerHitResult result = null; foreach (var item in this.ActualItems) { foreach (var outlier in item.Outliers) { var sp = this.Transform(item.X, outlier); double d = (sp - point).LengthSquared; if (d < minimumDistance) { result = new TrackerHitResult { Series = this, DataPoint = new DataPoint(item.X, outlier), Position = sp, Item = item, Text = StringHelper.Format( this.ActualCulture, this.OutlierTrackerFormatString, item, this.Title, this.XAxis.Title ?? DefaultXAxisTitle, this.XAxis.GetValue(item.X), outlier) }; minimumDistance = d; } } var hitPoint = DataPoint.Undefined; // check if we are inside the box rectangle var rect = this.GetBoxRect(item); if (rect.Contains(point)) { hitPoint = new DataPoint(item.X, this.YAxis.InverseTransform(point.Y)); minimumDistance = 0; } var topWhisker = this.Transform(item.X, item.UpperWhisker); var bottomWhisker = this.Transform(item.X, item.LowerWhisker); // check if we are near the line var p = ScreenPointHelper.FindPointOnLine(point, topWhisker, bottomWhisker); double d2 = (p - point).LengthSquared; if (d2 < minimumDistance) { hitPoint = this.InverseTransform(p); minimumDistance = d2; } if (hitPoint.IsDefined()) { result = new TrackerHitResult { Series = this, DataPoint = hitPoint, Position = this.Transform(hitPoint), Item = item, Text = StringHelper.Format( this.ActualCulture, this.TrackerFormatString, item, this.Title, this.XAxis.Title ?? DefaultXAxisTitle, this.XAxis.GetValue(item.X), this.YAxis.GetValue(item.UpperWhisker), this.YAxis.GetValue(item.BoxTop), this.YAxis.GetValue(item.Median), this.YAxis.GetValue(item.BoxBottom), this.YAxis.GetValue(item.LowerWhisker), this.YAxis.GetValue(item.Mean)) }; } } if (minimumDistance < double.MaxValue) { return(result); } return(null); }