public void IsInside() { var clipping = new CohenSutherlandClipping(0, 1, 0, 1); Assert.IsTrue(clipping.IsInside(0.5, 0.5)); Assert.IsFalse(clipping.IsInside(-0.5, 0.5)); }
public void EndpointsOutsideArea2() { var clipping = new CohenSutherlandClipping(new OxyRect(0.3, -0.5, 0.5, 1)); var p0 = new ScreenPoint(0, 0); var p1 = new ScreenPoint(1, 0); Assert.IsTrue(clipping.ClipLine(ref p0, ref p1)); Assert.AreEqual(new ScreenPoint(0.3, 0), p0); Assert.AreEqual(new ScreenPoint(0.8, 0), p1); }
public void EndpointsOutsideArea() { var clipping = new CohenSutherlandClipping(new OxyRect(0, 0, 1, 1)); var p0 = new ScreenPoint(0.3, -0.2); var p1 = new ScreenPoint(0.6, 1.3); Assert.IsTrue(clipping.ClipLine(ref p0, ref p1)); Assert.AreEqual(0, p0.Y); Assert.AreEqual(1, p1.Y); }
public void ClipLine_EndpointsInsideArea() { var clipping = new CohenSutherlandClipping(0, 1, 0, 1); var p0 = new ScreenPoint(0.3, 0.2); var p1 = new ScreenPoint(0.6, 0.8); Assert.IsTrue(clipping.ClipLine(ref p0, ref p1)); Assert.AreEqual(0.2, p0.Y); Assert.AreEqual(0.8, p1.Y); }
public void ClipLine_LineOutsideArea() { var clipping = new CohenSutherlandClipping(0, 1, 0, 1); var p0 = new ScreenPoint(0.3, -0.2); var p1 = new ScreenPoint(0.6, -0.2); Assert.IsFalse(clipping.ClipLine(ref p0, ref p1)); Assert.AreEqual(-0.2, p0.Y); Assert.AreEqual(-0.2, p1.Y); }
public void LineOutsideArea() { var clipping = new CohenSutherlandClipping(new OxyRect(0, 0, 1, 1)); var p0 = new ScreenPoint(0.3, -0.2); var p1 = new ScreenPoint(0.6, -0.2); Assert.IsFalse(clipping.ClipLine(ref p0, ref p1)); Assert.AreEqual(-0.2, p0.Y); Assert.AreEqual(-0.2, p1.Y); }
public void ClipLine_EndpointsOutsideArea() { var clipping = new CohenSutherlandClipping(0, 1, 0, 1); var p0 = new ScreenPoint(0.3, -0.2); var p1 = new ScreenPoint(0.6, 1.3); Assert.IsTrue(clipping.ClipLine(ref p0, ref p1)); Assert.AreEqual(0, p0.Y); Assert.AreEqual(1, p1.Y); }
public void EndpointsInsideArea() { var clipping = new CohenSutherlandClipping(new OxyRect(0, 0, 1, 1)); var p0 = new ScreenPoint(0.3, 0.2); var p1 = new ScreenPoint(0.6, 0.8); Assert.IsTrue(clipping.ClipLine(ref p0, ref p1)); Assert.AreEqual(0.2, p0.Y); Assert.AreEqual(0.8, p1.Y); }
public void OutsidePoint() { var clipping = new CohenSutherlandClipping(new OxyRect(0, 0, 1, 1)); Assert.IsFalse(clipping.IsInside(new ScreenPoint(-0.5, 0.5))); }
/// <summary> /// Renders the annotation on the specified context. /// </summary> /// <param name="rc">The render context.</param> public override void Render(IRenderContext rc) { base.Render(rc); this.CalculateActualMinimumsMaximums(); this.screenPoints = this.GetScreenPoints(); var clippingRectangle = this.GetClippingRect(); const double MinimumSegmentLength = 4; var clippedPoints = new List <ScreenPoint>(); var dashArray = this.LineStyle.GetDashArray(); if (this.StrokeThickness > 0 && this.LineStyle != LineStyle.None) { rc.DrawClippedLine( clippingRectangle, this.screenPoints, MinimumSegmentLength * MinimumSegmentLength, this.GetSelectableColor(this.Color), this.StrokeThickness, dashArray, this.LineJoin, this.Aliased, null, clippedPoints.AddRange); } var margin = this.TextMargin; this.GetActualTextAlignment(out var ha, out var va); if (ha == HorizontalAlignment.Center) { margin = 0; } else { margin *= this.TextLinePosition < 0.5 ? 1 : -1; } if (GetPointAtRelativeDistance(clippedPoints, this.TextLinePosition, margin, out var position, out var angle)) { if (angle < -90) { angle += 180; } if (angle > 90) { angle -= 180; } switch (this.TextOrientation) { case AnnotationTextOrientation.Horizontal: angle = 0; break; case AnnotationTextOrientation.Vertical: angle = -90; break; } // Apply 'padding' to the position var angleInRadians = angle / 180 * Math.PI; var f = 1; if (ha == HorizontalAlignment.Right) { f = -1; } if (ha == HorizontalAlignment.Center) { f = 0; } position += new ScreenVector(f * this.TextPadding * Math.Cos(angleInRadians), f * this.TextPadding * Math.Sin(angleInRadians)); if (!string.IsNullOrEmpty(this.Text)) { var textPosition = this.GetActualTextPosition(() => position); if (this.TextPosition.IsDefined()) { angle = this.TextRotation; } if (this.ClipText) { var cs = new CohenSutherlandClipping(clippingRectangle); if (cs.IsInside(position)) { rc.DrawClippedText( clippingRectangle, textPosition, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, angle, this.TextHorizontalAlignment, this.TextVerticalAlignment); } } else { rc.DrawText( textPosition, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, angle, ha, va); } } } }
/// <summary> /// Renders the annotation on the specified context. /// </summary> /// <param name="rc">The render context.</param> /// <param name="model">The model.</param> public override void Render(IRenderContext rc, PlotModel model) { base.Render(rc, model); this.CalculateActualMinimumsMaximums(); this.screenPoints = this.GetScreenPoints(); // clip to the area defined by the axes var clippingRectangle = OxyRect.Create( this.ClipByXAxis ? this.XAxis.ScreenMin.X : PlotModel.PlotArea.Left, this.ClipByYAxis ? this.YAxis.ScreenMin.Y : PlotModel.PlotArea.Top, this.ClipByXAxis ? this.XAxis.ScreenMax.X : PlotModel.PlotArea.Right, this.ClipByYAxis ? this.YAxis.ScreenMax.Y : PlotModel.PlotArea.Bottom); const double MinimumSegmentLength = 4; var clippedPoints = new List <ScreenPoint>(); var dashArray = this.LineStyle.GetDashArray(); rc.DrawClippedLine( clippingRectangle, this.screenPoints, MinimumSegmentLength * MinimumSegmentLength, this.GetSelectableColor(this.Color), this.StrokeThickness, dashArray, this.LineJoin, this.aliased, null, clippedPoints.AddRange); ScreenPoint position; double angle; double margin = this.TextMargin; if (this.TextHorizontalAlignment == HorizontalAlignment.Center) { margin = 0; } else { margin *= this.TextLinePosition < 0.5 ? 1 : -1; } if (GetPointAtRelativeDistance(clippedPoints, this.TextLinePosition, margin, out position, out angle)) { if (angle < -90) { angle += 180; } if (angle > 90) { angle -= 180; } switch (this.TextOrientation) { case AnnotationTextOrientation.Horizontal: angle = 0; break; case AnnotationTextOrientation.Vertical: angle = -90; break; } // Apply 'padding' to the position var angleInRadians = angle / 180 * Math.PI; var f = 1; if (this.TextHorizontalAlignment == HorizontalAlignment.Right) { f = -1; } if (this.TextHorizontalAlignment == HorizontalAlignment.Center) { f = 0; } position += new ScreenVector(f * this.TextPadding * Math.Cos(angleInRadians), f * this.TextPadding * Math.Sin(angleInRadians)); if (!string.IsNullOrEmpty(this.Text)) { var textPosition = this.GetActualTextPosition(() => position); if (this.TextPosition.IsDefined()) { angle = this.TextRotation; } if (this.ClipText) { var cs = new CohenSutherlandClipping(clippingRectangle); if (cs.IsInside(position)) { rc.DrawClippedText( clippingRectangle, textPosition, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, angle, this.TextHorizontalAlignment, this.TextVerticalAlignment); } } else { rc.DrawText( textPosition, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, angle, this.TextHorizontalAlignment, this.TextVerticalAlignment); } } } }
/// <summary> /// Renders the line 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); bool aliased = false; double actualMinimumX = Math.Max(this.MinimumX, this.XAxis.ActualMinimum); double actualMaximumX = Math.Min(this.MaximumX, this.XAxis.ActualMaximum); double actualMinimumY = Math.Max(this.MinimumY, this.YAxis.ActualMinimum); double actualMaximumY = Math.Min(this.MaximumY, this.YAxis.ActualMaximum); if (!this.ClipByXAxis) { double right = XAxis.InverseTransform(PlotModel.PlotArea.Right); double left = XAxis.InverseTransform(PlotModel.PlotArea.Left); actualMaximumX = Math.Max(left, right); actualMinimumX = Math.Min(left, right); } if (!this.ClipByYAxis) { double bottom = YAxis.InverseTransform(PlotModel.PlotArea.Bottom); double top = YAxis.InverseTransform(PlotModel.PlotArea.Top); actualMaximumY = Math.Max(top, bottom); actualMinimumY = Math.Min(top, bottom); } // y=f(x) Func <double, double> fx = null; // x=f(y) Func <double, double> fy = null; switch (this.Type) { case LineAnnotationType.Horizontal: fx = x => this.Y; break; case LineAnnotationType.Vertical: fy = y => this.X; break; case LineAnnotationType.EquationY: fx = this.Equation; break; case LineAnnotationType.EquationX: fy = this.Equation; break; default: fx = x => (this.Slope * x) + this.Intercept; break; } var points = new List <DataPoint>(); bool isCurvedLine = !(this.XAxis is LinearAxis) || !(this.YAxis is LinearAxis) || this.Type == LineAnnotationType.EquationY; if (!isCurvedLine) { // we only need to calculate two points if it is a straight line if (fx != null) { points.Add(new DataPoint(actualMinimumX, fx(actualMinimumX))); points.Add(new DataPoint(actualMaximumX, fx(actualMaximumX))); } else if (fy != null) { points.Add(new DataPoint(fy(actualMinimumY), actualMinimumY)); points.Add(new DataPoint(fy(actualMaximumY), actualMaximumY)); } if (this.Type == LineAnnotationType.Horizontal || this.Type == LineAnnotationType.Vertical) { // use aliased line drawing for horizontal and vertical lines aliased = true; } } else { if (fx != null) { double x = actualMinimumX; // todo: the step size should be adaptive double dx = (actualMaximumX - actualMinimumX) / 100; while (true) { points.Add(new DataPoint(x, fx(x))); if (x > actualMaximumX) { break; } x += dx; } } else if (fy != null) { double y = actualMinimumY; // todo: the step size should be adaptive double dy = (actualMaximumY - actualMinimumY) / 100; while (true) { points.Add(new DataPoint(fy(y), y)); if (y > actualMaximumY) { break; } y += dy; } } } // transform to screen coordinates this.screenPoints = points.Select(p => this.Transform(p)).ToList(); // clip to the area defined by the axes var clippingRectangle = OxyRect.Create( this.ClipByXAxis ? this.XAxis.ScreenMin.X : PlotModel.PlotArea.Left, this.ClipByYAxis ? this.YAxis.ScreenMin.Y : PlotModel.PlotArea.Top, this.ClipByXAxis ? this.XAxis.ScreenMax.X : PlotModel.PlotArea.Right, this.ClipByYAxis ? this.YAxis.ScreenMax.Y : PlotModel.PlotArea.Bottom); const double MinimumSegmentLength = 4; IList <ScreenPoint> clippedPoints = null; rc.DrawClippedLine( this.screenPoints, clippingRectangle, MinimumSegmentLength * MinimumSegmentLength, this.GetSelectableColor(this.Color), this.StrokeThickness, this.LineStyle, this.LineJoin, aliased, pts => clippedPoints = pts); ScreenPoint position; double angle; double margin = this.TextMargin; if (this.TextHorizontalAlignment == HorizontalAlignment.Center) { margin = 0; } else { margin *= this.TextPosition < 0.5 ? 1 : -1; } if (clippedPoints != null && GetPointAtRelativeDistance(clippedPoints, this.TextPosition, margin, out position, out angle)) { if (angle < -90) { angle += 180; } if (angle > 90) { angle -= 180; } switch (this.TextOrientation) { case AnnotationTextOrientation.Horizontal: angle = 0; break; case AnnotationTextOrientation.Vertical: angle = -90; break; } // Apply 'padding' to the position var angleInRadians = angle / 180 * Math.PI; var f = 1; if (this.TextHorizontalAlignment == HorizontalAlignment.Right) { f = -1; } if (this.TextHorizontalAlignment == HorizontalAlignment.Center) { f = 0; } position.X += f * this.TextPadding * Math.Cos(angleInRadians); position.Y += f * this.TextPadding * Math.Sin(angleInRadians); var cs = new CohenSutherlandClipping(clippingRectangle); if (!string.IsNullOrEmpty(this.Text) && cs.IsInside(position)) { rc.DrawClippedText( clippingRectangle, position, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, angle, this.TextHorizontalAlignment, this.TextVerticalAlignment); } } }
public Point3DCollection CreatePositions( Point3D center, double radius, double startAngle, double endAngle, double thetadiv = 32, double thickness = 1.0, double depthOffset = 0.0, CohenSutherlandClipping clipping = null ) { var halfThickness = thickness * 0.5; var spoints = new Point3DCollection(); for (int i = 0; i <= thetadiv; i++) { double x = radius * Math.Sin(i * (endAngle - startAngle) / thetadiv + startAngle) + center.X; double y = radius * Math.Cos(i * (endAngle - startAngle) / thetadiv + startAngle) + center.Y; spoints.Add(new Point3D(x, y, center.Z)); } var segmentCount = spoints.Count - 1; var positions = new Point3DCollection(segmentCount * 4); for (int i = 0; i < segmentCount; i++) { // int startIndex = i * 2; var startPoint = spoints[i]; var endPoint = spoints[i + 1]; // Transform the start and end points to screen space var s0 = (Point4D)startPoint * this.visualToScreen; var s1 = (Point4D)endPoint * this.visualToScreen; if (clipping != null) { // Apply a clipping rectangle var x0 = s0.X / s0.W; var y0 = s0.Y / s0.W; var x1 = s1.X / s1.W; var y1 = s1.Y / s1.W; if (!clipping.ClipLine(ref x0, ref y0, ref x1, ref y1)) { continue; } s0.X = x0 * s0.W; s0.Y = y0 * s0.W; s1.X = x1 * s1.W; s1.Y = y1 * s1.W; } var lx = (s1.X / s1.W) - (s0.X / s0.W); var ly = (s1.Y / s1.W) - (s0.Y / s0.W); var l2 = (lx * lx) + (ly * ly); var p00 = s0; var p01 = s0; var p10 = s1; var p11 = s1; if (l2.Equals(0)) { // coinciding points (in world space or screen space) var dz = halfThickness; // TODO: make a square with the thickness as side length p00.X -= dz * p00.W; p00.Y -= dz * p00.W; p01.X -= dz * p01.W; p01.Y += dz * p01.W; p10.X += dz * p10.W; p10.Y -= dz * p10.W; p11.X += dz * p11.W; p11.Y += dz * p11.W; } else { var m = halfThickness / Math.Sqrt(l2); // the normal (dx,dy) var dx = -ly * m; var dy = lx * m; // segment start points p00.X += dx * p00.W; p00.Y += dy * p00.W; p01.X -= dx * p01.W; p01.Y -= dy * p01.W; // segment end points p10.X += dx * p10.W; p10.Y += dy * p10.W; p11.X -= dx * p11.W; p11.Y -= dy * p11.W; } if (!depthOffset.Equals(0)) { // Adjust the z-coordinate by the depth offset p00.Z -= depthOffset; p01.Z -= depthOffset; p10.Z -= depthOffset; p11.Z -= depthOffset; // Transform from screen space to world space p00 *= this.screenToVisual; p01 *= this.screenToVisual; p10 *= this.screenToVisual; p11 *= this.screenToVisual; positions.Add(new Point3D(p00.X / p00.W, p00.Y / p00.W, p00.Z / p00.W)); positions.Add(new Point3D(p01.X / p00.W, p01.Y / p01.W, p01.Z / p01.W)); positions.Add(new Point3D(p10.X / p00.W, p10.Y / p10.W, p10.Z / p10.W)); positions.Add(new Point3D(p11.X / p00.W, p11.Y / p11.W, p11.Z / p11.W)); } else { // Transform from screen space to world space p00 *= this.screenToVisual; p01 *= this.screenToVisual; p10 *= this.screenToVisual; p11 *= this.screenToVisual; positions.Add(new Point3D(p00.X, p00.Y, p00.Z)); positions.Add(new Point3D(p01.X, p01.Y, p01.Z)); positions.Add(new Point3D(p10.X, p10.Y, p10.Z)); positions.Add(new Point3D(p11.X, p11.Y, p11.Z)); } } positions.Freeze(); return(positions); // return null; }
/// <summary> /// Renders the annotation on the specified context. /// </summary> /// <param name="rc">The render context.</param> /// <param name="model">The model.</param> public override void Render(IRenderContext rc, PlotModel model) { base.Render(rc, model); this.CalculateActualMinimumsMaximums(); this.screenPoints = this.GetScreenPoints(); // clip to the area defined by the axes var clippingRectangle = OxyRect.Create( this.ClipByXAxis ? this.XAxis.ScreenMin.X : PlotModel.PlotArea.Left, this.ClipByYAxis ? this.YAxis.ScreenMin.Y : PlotModel.PlotArea.Top, this.ClipByXAxis ? this.XAxis.ScreenMax.X : PlotModel.PlotArea.Right, this.ClipByYAxis ? this.YAxis.ScreenMax.Y : PlotModel.PlotArea.Bottom); const double MinimumSegmentLength = 4; var clippedPoints = new List<ScreenPoint>(); var dashArray = this.LineStyle.GetDashArray(); rc.DrawClippedLine( clippingRectangle, this.screenPoints, MinimumSegmentLength * MinimumSegmentLength, this.GetSelectableColor(this.Color), this.StrokeThickness, dashArray, this.LineJoin, this.aliased, null, clippedPoints.AddRange); ScreenPoint position; double angle; double margin = this.TextMargin; if (this.TextHorizontalAlignment == HorizontalAlignment.Center) { margin = 0; } else { margin *= this.TextLinePosition < 0.5 ? 1 : -1; } if (GetPointAtRelativeDistance(clippedPoints, this.TextLinePosition, margin, out position, out angle)) { if (angle < -90) { angle += 180; } if (angle > 90) { angle -= 180; } switch (this.TextOrientation) { case AnnotationTextOrientation.Horizontal: angle = 0; break; case AnnotationTextOrientation.Vertical: angle = -90; break; } // Apply 'padding' to the position var angleInRadians = angle / 180 * Math.PI; var f = 1; if (this.TextHorizontalAlignment == HorizontalAlignment.Right) { f = -1; } if (this.TextHorizontalAlignment == HorizontalAlignment.Center) { f = 0; } position += new ScreenVector(f * this.TextPadding * Math.Cos(angleInRadians), f * this.TextPadding * Math.Sin(angleInRadians)); if (!string.IsNullOrEmpty(this.Text)) { var textPosition = this.GetActualTextPosition(() => position); if (this.TextPosition.IsDefined()) { angle = this.TextRotation; } if (this.ClipText) { var cs = new CohenSutherlandClipping(clippingRectangle); if (cs.IsInside(position)) { rc.DrawClippedText( clippingRectangle, textPosition, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, angle, this.TextHorizontalAlignment, this.TextVerticalAlignment); } } else { rc.DrawText( textPosition, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, angle, this.TextHorizontalAlignment, this.TextVerticalAlignment); } } } }
/// <summary> /// Renders the line 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); bool aliased = false; double actualMinimumX = Math.Max(this.MinimumX, this.XAxis.ActualMinimum); double actualMaximumX = Math.Min(this.MaximumX, this.XAxis.ActualMaximum); double actualMinimumY = Math.Max(this.MinimumY, this.YAxis.ActualMinimum); double actualMaximumY = Math.Min(this.MaximumY, this.YAxis.ActualMaximum); if (!this.ClipByXAxis) { double right = XAxis.InverseTransform(PlotModel.PlotArea.Right); double left = XAxis.InverseTransform(PlotModel.PlotArea.Left); actualMaximumX = Math.Max(left, right); actualMinimumX = Math.Min(left, right); } if (!this.ClipByYAxis) { double bottom = YAxis.InverseTransform(PlotModel.PlotArea.Bottom); double top = YAxis.InverseTransform(PlotModel.PlotArea.Top); actualMaximumY = Math.Max(top, bottom); actualMinimumY = Math.Min(top, bottom); } // y=f(x) Func<double, double> fx = null; // x=f(y) Func<double, double> fy = null; switch (this.Type) { case LineAnnotationType.Horizontal: fx = x => this.Y; break; case LineAnnotationType.Vertical: fy = y => this.X; break; case LineAnnotationType.EquationY: fx = this.Equation; break; case LineAnnotationType.EquationX: fy = this.Equation; break; default: fx = x => (this.Slope * x) + this.Intercept; break; } var points = new List<DataPoint>(); bool isCurvedLine = !(this.XAxis is LinearAxis) || !(this.YAxis is LinearAxis) || this.Type == LineAnnotationType.EquationY; if (!isCurvedLine) { // we only need to calculate two points if it is a straight line if (fx != null) { points.Add(new DataPoint(actualMinimumX, fx(actualMinimumX))); points.Add(new DataPoint(actualMaximumX, fx(actualMaximumX))); } else if (fy != null) { points.Add(new DataPoint(fy(actualMinimumY), actualMinimumY)); points.Add(new DataPoint(fy(actualMaximumY), actualMaximumY)); } if (this.Type == LineAnnotationType.Horizontal || this.Type == LineAnnotationType.Vertical) { // use aliased line drawing for horizontal and vertical lines aliased = true; } } else { if (fx != null) { double x = actualMinimumX; // todo: the step size should be adaptive double dx = (actualMaximumX - actualMinimumX) / 100; while (true) { points.Add(new DataPoint(x, fx(x))); if (x > actualMaximumX) { break; } x += dx; } } else if (fy != null) { double y = actualMinimumY; // todo: the step size should be adaptive double dy = (actualMaximumY - actualMinimumY) / 100; while (true) { points.Add(new DataPoint(fy(y), y)); if (y > actualMaximumY) { break; } y += dy; } } } // transform to screen coordinates this.screenPoints = points.Select(p => this.Transform(p)).ToList(); // clip to the area defined by the axes var clippingRectangle = OxyRect.Create( this.ClipByXAxis ? this.XAxis.ScreenMin.X : PlotModel.PlotArea.Left, this.ClipByYAxis ? this.YAxis.ScreenMin.Y : PlotModel.PlotArea.Top, this.ClipByXAxis ? this.XAxis.ScreenMax.X : PlotModel.PlotArea.Right, this.ClipByYAxis ? this.YAxis.ScreenMax.Y : PlotModel.PlotArea.Bottom); const double MinimumSegmentLength = 4; IList<ScreenPoint> clippedPoints = null; rc.DrawClippedLine( this.screenPoints, clippingRectangle, MinimumSegmentLength * MinimumSegmentLength, this.GetSelectableColor(this.Color), this.StrokeThickness, this.LineStyle, this.LineJoin, aliased, pts => clippedPoints = pts); ScreenPoint position; double angle; double margin = this.TextMargin; if (this.TextHorizontalAlignment == HorizontalAlignment.Center) { margin = 0; } else { margin *= this.TextPosition < 0.5 ? 1 : -1; } if (clippedPoints != null && GetPointAtRelativeDistance(clippedPoints, this.TextPosition, margin, out position, out angle)) { if (angle < -90) { angle += 180; } if (angle > 90) { angle -= 180; } switch (this.TextOrientation) { case AnnotationTextOrientation.Horizontal: angle = 0; break; case AnnotationTextOrientation.Vertical: angle = -90; break; } // Apply 'padding' to the position var angleInRadians = angle / 180 * Math.PI; var f = 1; if (this.TextHorizontalAlignment == HorizontalAlignment.Right) { f = -1; } if (this.TextHorizontalAlignment == HorizontalAlignment.Center) { f = 0; } position.X += f * this.TextPadding * Math.Cos(angleInRadians); position.Y += f * this.TextPadding * Math.Sin(angleInRadians); var cs = new CohenSutherlandClipping(clippingRectangle); if (!string.IsNullOrEmpty(this.Text) && cs.IsInside(position)) { rc.DrawClippedText( clippingRectangle, position, this.Text, this.ActualTextColor, this.ActualFont, this.ActualFontSize, this.ActualFontWeight, angle, this.TextHorizontalAlignment, this.TextVerticalAlignment); } } }