/// <summary> /// Gets the path representing this element. /// </summary> public override VectorPath GetPath(SVGElement context, RenderContext renderer) { Css.RenderableData rd = context.RenderData; // Don't build the path if there's no radius: float radius = Radius.GetDecimal(rd, ViewportAxis.None); if (radius <= 0) { return(null); } if (_Path == null) { // Don't need to consider stroke width. _Path = new VectorPath(); float centerX = CenterX.GetDecimal(rd, ViewportAxis.X); float centerY = CenterX.GetDecimal(rd, ViewportAxis.Y); // Get the C values: float cX = BezierC * radius; float cY = cX; // Offset to match the center: cX += centerX; cY += centerY; float radiusX = centerX + radius; float radiusY = centerY + radius; float nRadiusX = centerX - radius; float nRadiusY = centerY - radius; _Path.MoveTo(centerX, radiusY); // First quadrant (top right, going clockwise): _Path.CurveTo(cX, radiusY, radiusX, cY, radiusX, centerY); // Bottom right: _Path.CurveTo(radiusX, -cY, cX, nRadiusY, centerX, nRadiusY); // Bottom left: _Path.CurveTo(-cX, nRadiusY, nRadiusX, -cY, nRadiusX, centerY); // Top left: _Path.CurveTo(nRadiusX, cY, -cX, radiusY, centerX, radiusY); // Mark as closed: _Path.LatestPathNode.IsClose = true; } return(_Path); }
public void curveTo(float c1x, float c1y, float c2x, float c2y, float x, float y) { Path.CurveTo(c1x, c1y, c2x, c2y, x, y); }
/// <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); }
/// <summary>Adds the given parsed command into the given path.</summary> public static void AddCommand(VectorPath path, char command, float[] param, int currentLimit) { if (command == '\0') { return; } // Get the lc command: char lower = char.ToLower(command); // A lowercase char is relative // (and its lowercase if the lower one matches the original): bool isRelative = (command == lower); // Current point: float curX = 0f; float curY = 0f; float c1x = 0f; float c1y = 0f; if (path.LatestPathNode != null) { // Get current point: curX = path.LatestPathNode.X; curY = path.LatestPathNode.Y; } switch (lower) { case 'a': // Eliptical arc if (isRelative) { param[5] += curX; param[6] += curY; } path.EllipseArc(param[0], param[1], param[2], param[5], param[6], (param[3] == 1f), (param[4] == 1f)); break; case 'c': // Curve to if (isRelative) { param[0] += curX; param[1] += curY; param[2] += curX; param[3] += curY; param[4] += curX; param[5] += curY; } path.CurveTo(param[0], param[1], param[2], param[3], param[4], param[5]); break; case 'h': // Horizontal line to if (isRelative) { param[0] += curX; } path.LineTo(param[0], curY); break; case 'l': // Line to if (isRelative) { param[0] += curX; param[1] += curY; } path.LineTo(param[0], param[1]); break; case 'm': // Move to if (isRelative) { param[0] += curX; param[1] += curY; } path.MoveTo(param[0], param[1]); break; case 'q': // Quadratic bezier to if (isRelative) { param[0] += curX; param[1] += curY; param[2] += curX; param[3] += curY; } path.QuadraticCurveTo(param[0], param[1], param[2], param[3]); break; case 's': // Smooth curve to Reflect(path, out c1x, out c1y); if (isRelative) { param[0] += curX; param[1] += curY; param[2] += curX; param[3] += curY; } path.CurveTo(c1x, c1y, param[0], param[1], param[2], param[3]); break; case 't': // Smooth quadratic bezier to Reflect(path, out c1x, out c1y); if (isRelative) { param[0] += curX; param[1] += curY; } path.QuadraticCurveTo(c1x, c1y, param[0], param[1]); break; case 'v': // Vertical line to if (isRelative) { param[0] += curY; } path.LineTo(curX, param[0]); break; case 'z': // Close path path.ClosePath(); break; } }