/// <summary> /// Gets the <see cref="GraphicsPath"/> for this element. /// </summary> public override GraphicsPath Path(ISvgRenderer renderer) { if (_path == null || IsPathDirty) { // If the corners aren't to be rounded just create a rectangle if (CornerRadiusX.Value == 0.0f && CornerRadiusY.Value == 0.0f) { var rectangle = new RectangleF(Location.ToDeviceValue(renderer, this), SvgUnit.GetDeviceSize(this.Width, this.Height, renderer, this)); _path = new GraphicsPath(); _path.StartFigure(); _path.AddRectangle(rectangle); _path.CloseFigure(); } else { _path = new GraphicsPath(); var arcBounds = new RectangleF(); var lineStart = new PointF(); var lineEnd = new PointF(); var width = Width.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this); var height = Height.ToDeviceValue(renderer, UnitRenderingType.Vertical, this); var rx = Math.Min(CornerRadiusX.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) * 2, width); var ry = Math.Min(CornerRadiusY.ToDeviceValue(renderer, UnitRenderingType.Vertical, this) * 2, height); var location = Location.ToDeviceValue(renderer, this); // Start _path.StartFigure(); // Add first arc arcBounds.Location = location; arcBounds.Width = rx; arcBounds.Height = ry; _path.AddArc(arcBounds, 180, 90); // Add first line lineStart.X = Math.Min(location.X + rx, location.X + width * 0.5f); lineStart.Y = location.Y; lineEnd.X = Math.Max(location.X + width - rx, location.X + width * 0.5f); lineEnd.Y = lineStart.Y; _path.AddLine(lineStart, lineEnd); // Add second arc arcBounds.Location = new PointF(location.X + width - rx, location.Y); _path.AddArc(arcBounds, 270, 90); // Add second line lineStart.X = location.X + width; lineStart.Y = Math.Min(location.Y + ry, location.Y + height * 0.5f); lineEnd.X = lineStart.X; lineEnd.Y = Math.Max(location.Y + height - ry, location.Y + height * 0.5f); _path.AddLine(lineStart, lineEnd); // Add third arc arcBounds.Location = new PointF(location.X + width - rx, location.Y + height - ry); _path.AddArc(arcBounds, 0, 90); // Add third line lineStart.X = Math.Max(location.X + width - rx, location.X + width * 0.5f); lineStart.Y = location.Y + height; lineEnd.X = Math.Min(location.X + rx, location.X + width * 0.5f); lineEnd.Y = lineStart.Y; _path.AddLine(lineStart, lineEnd); // Add third arc arcBounds.Location = new PointF(location.X, location.Y + height - ry); _path.AddArc(arcBounds, 90, 90); // Add fourth line lineStart.X = location.X; lineStart.Y = Math.Max(location.Y + height - ry, location.Y + height * 0.5f); lineEnd.X = lineStart.X; lineEnd.Y = Math.Min(location.Y + ry, location.Y + height * 0.5f); _path.AddLine(lineStart, lineEnd); // Close _path.CloseFigure(); } IsPathDirty = false; } return(_path); }
/// <summary> /// Gets the <see cref="GraphicsPath"/> for this element. /// </summary> public override GraphicsPath Path(ISvgRenderer renderer) { if (_path == null || IsPathDirty) { var halfStrokeWidth = base.StrokeWidth / 2; // If it is to render, don't need to consider stroke if (renderer != null) { halfStrokeWidth = 0; this.IsPathDirty = false; } // If the corners aren't to be rounded just create a rectangle if (CornerRadiusX.Value == 0.0f && CornerRadiusY.Value == 0.0f) { var loc_y = Location.Y.ToDeviceValue(renderer, UnitRenderingType.Vertical, this); var loc_x = Location.X.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this); // Starting location which take consideration of stroke width SvgPoint strokedLocation = new SvgPoint(loc_x - halfStrokeWidth, loc_y - halfStrokeWidth); var width = this.Width.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) + halfStrokeWidth * 2; var height = this.Height.ToDeviceValue(renderer, UnitRenderingType.Vertical, this) + halfStrokeWidth * 2; var rectangle = new RectangleF(strokedLocation.ToDeviceValue(renderer, this), new SizeF(width, height)); _path = new GraphicsPath(); _path.StartFigure(); _path.AddRectangle(rectangle); _path.CloseFigure(); } else { _path = new GraphicsPath(); var arcBounds = new RectangleF(); var lineStart = new PointF(); var lineEnd = new PointF(); var width = Width.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this); var height = Height.ToDeviceValue(renderer, UnitRenderingType.Vertical, this); var rx = Math.Min(CornerRadiusX.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) * 2, width); var ry = Math.Min(CornerRadiusY.ToDeviceValue(renderer, UnitRenderingType.Vertical, this) * 2, height); var location = Location.ToDeviceValue(renderer, this); // Start _path.StartFigure(); // Add first arc arcBounds.Location = location; arcBounds.Width = rx; arcBounds.Height = ry; _path.AddArc(arcBounds, 180, 90); // Add first line lineStart.X = Math.Min(location.X + rx, location.X + width * 0.5f); lineStart.Y = location.Y; lineEnd.X = Math.Max(location.X + width - rx, location.X + width * 0.5f); lineEnd.Y = lineStart.Y; _path.AddLine(lineStart, lineEnd); // Add second arc arcBounds.Location = new PointF(location.X + width - rx, location.Y); _path.AddArc(arcBounds, 270, 90); // Add second line lineStart.X = location.X + width; lineStart.Y = Math.Min(location.Y + ry, location.Y + height * 0.5f); lineEnd.X = lineStart.X; lineEnd.Y = Math.Max(location.Y + height - ry, location.Y + height * 0.5f); _path.AddLine(lineStart, lineEnd); // Add third arc arcBounds.Location = new PointF(location.X + width - rx, location.Y + height - ry); _path.AddArc(arcBounds, 0, 90); // Add third line lineStart.X = Math.Max(location.X + width - rx, location.X + width * 0.5f); lineStart.Y = location.Y + height; lineEnd.X = Math.Min(location.X + rx, location.X + width * 0.5f); lineEnd.Y = lineStart.Y; _path.AddLine(lineStart, lineEnd); // Add third arc arcBounds.Location = new PointF(location.X, location.Y + height - ry); _path.AddArc(arcBounds, 90, 90); // Add fourth line lineStart.X = location.X; lineStart.Y = Math.Max(location.Y + height - ry, location.Y + height * 0.5f); lineEnd.X = lineStart.X; lineEnd.Y = Math.Min(location.Y + ry, location.Y + height * 0.5f); _path.AddLine(lineStart, lineEnd); // Close _path.CloseFigure(); } } return(_path); }
/// <summary> /// Gets the path representing this element. /// </summary> public override VectorPath GetPath(SVGElement context, RenderContext renderer) { Css.RenderableData rd = context.RenderData; // Get w/h: float width = Width.GetDecimal(rd, ViewportAxis.X); float height = Height.GetDecimal(rd, ViewportAxis.Y); if (width <= 0f && height > 0f) { return(null); } if (_Path == null) { _Path = new VectorPath(); // Get corner radius: float rx = CornerRadiusX.GetDecimal(rd, ViewportAxis.X); float ry = CornerRadiusY.GetDecimal(rd, ViewportAxis.Y); // Get x/y: float x = X.GetDecimal(rd, ViewportAxis.X); float y = Y.GetDecimal(rd, ViewportAxis.Y); // Note: This goes clockwise (like the other standard shapes). // If the corners aren't to be rounded just create a rectangle if (rx == 0f && ry == 0f) { // Ordinary rectangle. _Path.MoveTo(x, y); _Path.LineTo(x, y + height); _Path.LineTo(x + width, y + height); _Path.LineTo(x + width, y); _Path.ClosePath(); } else { // Clip the corner radius: rx = (float)Math.Min(rx * 2, width); ry = (float)Math.Min(ry * 2, height); // Get the C values (used to shape the 4 corners arcs - see CircleProvider for some clarity): float cx = (CircleProvider.BezierC * rx); float cy = (CircleProvider.BezierC * ry); float limit = x + width * 0.5f; // The start/ end of arcs from the left along x. float leftArcX = Math.Min(x + rx, limit); // The start/ end of arcs from the right along x. float rightArcX = Math.Max(x + width - rx, limit); limit = y + height * 0.5f; // The start/ end of arcs from the bottom along y. float bottomArcY = Math.Min(y + ry, limit); // The start/ end of arcs from the top along y. float topArcY = Math.Max(y + height - ry, limit); // Start from bottom left: _Path.MoveTo( leftArcX, y ); // First arc (bottom left): _Path.CurveTo( leftArcX - cx, y, x, bottomArcY - cy, x, bottomArcY ); // Up the left edge: _Path.LineTo(x, topArcY); // Top left arc: _Path.CurveTo( x, topArcY + cy, leftArcX - cx, y + height, leftArcX, y + height ); // Along the top edge: _Path.LineTo(rightArcX, y); // Top right arc: _Path.CurveTo( rightArcX + cx, y, x + width, topArcY + cy, x + width, topArcY ); // Down the right edge: _Path.LineTo(x + width, bottomArcY); // Bottom right arc: _Path.CurveTo( x + width, bottomArcY - cy, rightArcX + cx, y, rightArcX, y ); // Line along the bottom! _Path.ClosePath(); } } return(_Path); }