/// <summary> /// Renders the transformed points. /// </summary> /// <param name="rc"> /// The render context. /// </param> /// <param name="clippingRect"> /// The clipping rect. /// </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> /// 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 (ScreenPointHelper.IsPointInPolygon(point, this.screenPoints)) { return(new HitTestResult(point)); } 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="point"> /// The point. /// </param> /// <returns> /// A tracker hit result if a point was found. /// </returns> protected TrackerHitResult GetNearestInterpolatedPointInternal(IList <IDataPoint> points, ScreenPoint point) { 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++) { var p1 = points[i]; var p2 = points[i + 1]; if (!this.IsValidPoint(p1, this.XAxis, this.YAxis) || !this.IsValidPoint(p2, this.XAxis, this.YAxis)) { 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) { object item = this.GetItem((int)index); return(new TrackerHitResult(this, dpn, spn, item) { Index = index }); } 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); }
/// <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, HorizontalTextAlign.Center, VerticalTextAlign.Middle); } }
/// <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 (interpolate) { return(null); } TrackerHitResult result = null; // http://local.wasp.uwa.edu.au/~pbourke/geometry/pointline/ double minimumDistance = double.MaxValue; var points = this.Points; 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> /// 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) { 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 = StringHelper.Format( this.ActualCulture, this.OutlierTrackerFormatString, item, this.Title, 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 = StringHelper.Format( this.ActualCulture, this.TrackerFormatString, item, this.Title, 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 = StringHelper.Format( this.ActualCulture, this.TrackerFormatString, item, this.Title, result.DataPoint.X, item.UpperWhisker, item.BoxTop, item.Median, item.BoxBottom, item.LowerWhisker); minimumDistance = d2; } } if (minimumDistance < double.MaxValue) { return(result); } 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) { if (this.Points.Count == 0) { return; } if (this.XAxis == null || this.YAxis == null) { Trace("Axis not defined."); return; } double minDistSquared = this.MinimumSegmentLength * this.MinimumSegmentLength; var clippingRect = this.GetClippingRect(); // Transform all points to screen coordinates var points = this.Points; int n0 = points.Count; IList <ScreenPoint> pts0 = new ScreenPoint[n0]; for (int i = 0; i < n0; i++) { pts0[i] = this.XAxis.Transform(points[i].X, points[i].Y, this.YAxis); } int n1 = this.points2.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(this.points2[i].X, this.points2[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); } // draw the clipped lines rc.DrawClippedLine( pts0, clippingRect, minDistSquared, this.GetSelectableColor(this.ActualColor), this.StrokeThickness, this.ActualLineStyle, this.LineJoin, false); rc.DrawClippedLine( pts1, clippingRect, minDistSquared, this.GetSelectableColor(this.ActualColor), this.StrokeThickness, this.ActualLineStyle, 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(pts, clippingRect, minDistSquared, this.GetSelectableFillColor(this.Fill), null); // draw the markers on top rc.DrawMarkers( pts0, clippingRect, this.MarkerType, null, new[] { this.MarkerSize }, this.MarkerFill, this.MarkerStroke, this.MarkerStrokeThickness, 1); rc.DrawMarkers( pts1, clippingRect, this.MarkerType, null, new[] { this.MarkerSize }, this.MarkerFill, this.MarkerStroke, this.MarkerStrokeThickness, 1); }