/// <summary> /// DrawEllipse - /// Draw an ellipse with the provided Brush and/or Pen. /// If both the Brush and Pen are null this call is a no-op. /// </summary> /// <param name="brush"> /// The Brush with which to fill the ellipse. /// This is optional, and can be null, in which case no fill is performed. /// </param> /// <param name="pen"> /// The Pen with which to stroke the ellipse. /// This is optional, and can be null, in which case no stroke is performed. /// </param> /// <param name="center"> /// The center of the ellipse to fill and/or stroke. /// </param> /// <param name="radiusX"> /// The radius in the X dimension of the ellipse. /// The absolute value of the radius provided will be used. /// </param> /// <param name="radiusY"> /// The radius in the Y dimension of the ellipse. /// The absolute value of the radius provided will be used. /// </param> public override void DrawEllipse( Brush brush, Pen pen, Point center, Double radiusX, Double radiusY) { if ((brush != null) || Pen.ContributesToBounds(pen)) { // _bounds is always in "world" space // So, we need to transform the geometry to world to bound it Rect geometryBounds = EllipseGeometry.GetBoundsHelper( pen, _transform, // world transform center, radiusX, radiusY, Matrix.Identity, // geometry transform Geometry.StandardFlatteningTolerance, ToleranceType.Absolute ); AddTransformedBounds(ref geometryBounds); } }
internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Rect rect, double radiusX, double radiusY, Matrix geometryMatrix, double tolerance, ToleranceType type) { Rect boundingRect; if (rect.IsEmpty) { boundingRect = Rect.Empty; } else if ((pen == null || pen.DoesNotContainGaps) && geometryMatrix.IsIdentity && worldMatrix.IsIdentity) { double strokeThickness = 0.0; boundingRect = rect; if (Pen.ContributesToBounds(pen)) { strokeThickness = Math.Abs(pen.Thickness); boundingRect.X -= 0.5 * strokeThickness; boundingRect.Y -= 0.5 * strokeThickness; boundingRect.Width += strokeThickness; boundingRect.Height += strokeThickness; } } else { unsafe { uint pointCount, segmentCount; GetCounts(rect, radiusX, radiusY, out pointCount, out segmentCount); // We've checked that rect isn't empty above Invariant.Assert(pointCount != 0); Point *pPoints = stackalloc Point[(int)pointCount]; RectangleGeometry.GetPointList(pPoints, pointCount, rect, radiusX, radiusY); fixed(byte *pTypes = RectangleGeometry.GetTypeList(rect, radiusX, radiusY)) { boundingRect = Geometry.GetBoundsHelper( pen, &worldMatrix, pPoints, pTypes, pointCount, segmentCount, &geometryMatrix, tolerance, type, false); // skip hollows - meaningless here, this is never a hollow } } } return(boundingRect); }
/// <summary> /// DrawGeometry - /// Draw a Geometry with the provided Brush and/or Pen. /// If both the Brush and Pen are null this call is a no-op. /// </summary> /// <param name="brush"> /// The Brush with which to fill the Geometry. /// This is optional, and can be null, in which case no fill is performed. /// </param> /// <param name="pen"> /// The Pen with which to stroke the Geometry. /// This is optional, and can be null, in which case no stroke is performed. /// </param> /// <param name="geometry"> The Geometry to fill and/or stroke. </param> public override void DrawGeometry( Brush brush, Pen pen, Geometry geometry) { if ((geometry != null) && ((brush != null) || Pen.ContributesToBounds(pen))) { // _bounds is always in "world" space // So, we need to transform the geometry to world to bound it Rect geometryBounds = geometry.GetBoundsInternal(pen, _transform); AddTransformedBounds(ref geometryBounds); } }
internal static Rect GetBoundsHelper(Pen pen, Matrix worldMatrix, Point center, double radiusX, double radiusY, Matrix geometryMatrix, double tolerance, ToleranceType type) { Rect rect; Debug.Assert(worldMatrix != null); Debug.Assert(geometryMatrix != null); if ((pen == null || pen.DoesNotContainGaps) && worldMatrix.IsIdentity && geometryMatrix.IsIdentity) { double strokeThickness = 0.0; if (Pen.ContributesToBounds(pen)) { strokeThickness = Math.Abs(pen.Thickness); } rect = new Rect( center.X - Math.Abs(radiusX) - 0.5 * strokeThickness, center.Y - Math.Abs(radiusY) - 0.5 * strokeThickness, 2.0 * Math.Abs(radiusX) + strokeThickness, 2.0 * Math.Abs(radiusY) + strokeThickness); } else { unsafe { Point *pPoints = stackalloc Point[(int)c_pointCount]; EllipseGeometry.GetPointList(pPoints, c_pointCount, center, radiusX, radiusY); fixed(byte *pTypes = EllipseGeometry.s_roundedPathTypes) { rect = Geometry.GetBoundsHelper( pen, &worldMatrix, pPoints, pTypes, c_pointCount, c_segmentCount, &geometryMatrix, tolerance, type, false); // skip hollows - meaningless here, this is never a hollow } } } return(rect); }
/// <summary> /// DrawLine - /// Draws a line with the specified pen. /// Note that this API does not accept a Brush, as there is no area to fill. /// </summary> /// <param name="pen"> The Pen with which to stroke the line. </param> /// <param name="point0"> The start Point for the line. </param> /// <param name="point1"> The end Point for the line. </param> public override void DrawLine( Pen pen, Point point0, Point point1) { if (Pen.ContributesToBounds(pen)) { // _bounds is always in "world" space // So, we need to transform the geometry to world to bound it Rect geometryBounds = LineGeometry.GetBoundsHelper( pen, _transform, // world transform point0, point1, Matrix.Identity, // geometry transform Geometry.StandardFlatteningTolerance, ToleranceType.Absolute ); AddTransformedBounds(ref geometryBounds); } }
/// <summary> /// DrawRectangle - /// Draw a rectangle with the provided Brush and/or Pen. /// If both the Brush and Pen are null this call is a no-op. /// </summary> /// <param name="brush"> /// The Brush with which to fill the rectangle. /// This is optional, and can be null, in which case no fill is performed. /// </param> /// <param name="pen"> /// The Pen with which to stroke the rectangle. /// This is optional, and can be null, in which case no stroke is performed. /// </param> /// <param name="rectangle"> The Rect to fill and/or stroke. </param> public override void DrawRectangle( Brush brush, Pen pen, Rect rectangle) { if ((brush != null) || Pen.ContributesToBounds(pen)) { // _bounds is always in "world" space // So, we need to transform the geometry to world to bound it Rect geometryBounds = RectangleGeometry.GetBoundsHelper( pen, _transform, // world transform rectangle, 0.0, 0.0, Matrix.Identity, // geometry transform Geometry.StandardFlatteningTolerance, ToleranceType.Absolute ); AddTransformedBounds(ref geometryBounds); } }
internal unsafe static Rect GetBoundsHelper( Pen pen, Matrix *pWorldMatrix, Point *pPoints, byte *pTypes, uint pointCount, uint segmentCount, Matrix *pGeometryMatrix, double tolerance, ToleranceType type, bool fSkipHollows) { MIL_PEN_DATA penData; double[] dashArray = null; // If the pen contributes to the bounds, populate the CMD struct bool fPenContributesToBounds = Pen.ContributesToBounds(pen); if (fPenContributesToBounds) { pen.GetBasicPenData(&penData, out dashArray); } MilMatrix3x2D geometryMatrix; if (pGeometryMatrix != null) { geometryMatrix = CompositionResourceManager.MatrixToMilMatrix3x2D(ref (*pGeometryMatrix)); } Debug.Assert(pWorldMatrix != null); MilMatrix3x2D worldMatrix = CompositionResourceManager.MatrixToMilMatrix3x2D(ref (*pWorldMatrix)); Rect bounds; fixed(double *pDashArray = dashArray) { int hr = MilCoreApi.MilUtility_PolygonBounds( &worldMatrix, (fPenContributesToBounds) ? &penData : null, (dashArray == null) ? null : pDashArray, pPoints, pTypes, pointCount, segmentCount, (pGeometryMatrix == null) ? null : &geometryMatrix, tolerance, type == ToleranceType.Relative, fSkipHollows, &bounds ); if (hr == (int)MILErrors.WGXERR_BADNUMBER) { // When we encounter NaNs in the renderer, we absorb the error and draw // nothing. To be consistent, we report that the geometry has empty bounds. bounds = Rect.Empty; } else { HRESULT.Check(hr); } } return(bounds); }