Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
521 views
in Technique[技术] by (71.8m points)

c# - Oddly drawn GraphicsPath with Graphics.FillPath

I have written some code which creates a rounded rectangle GraphicsPath, based on a custom structure, BorderRadius (which allows me to define the top left, top right, bottom left and bottom right radius of the rectangle), and the initial Rectangle itself:

public static GraphicsPath CreateRoundRectanglePath(BorderRadius radius, Rectangle rectangle)
{
    GraphicsPath result = new GraphicsPath();

    if (radius.TopLeft > 0)
    {
        result.AddArc(rectangle.X, rectangle.Y, radius.TopLeft, radius.TopLeft, 180, 90);
    }
    else
    {
        result.AddLine(new System.Drawing.Point(rectangle.X, rectangle.Y), new System.Drawing.Point(rectangle.X, rectangle.Y));
    }
    if (radius.TopRight > 0)
    {
        result.AddArc(rectangle.X + rectangle.Width - radius.TopRight, rectangle.Y, radius.TopRight, radius.TopRight, 270, 90);
    }
    else
    {
        result.AddLine(new System.Drawing.Point(rectangle.X + rectangle.Width, rectangle.Y), new System.Drawing.Point(rectangle.X + rectangle.Width, rectangle.Y));
    }
    if (radius.BottomRight > 0)
    {
        result.AddArc(rectangle.X + rectangle.Width - radius.BottomRight, rectangle.Y + rectangle.Height - radius.BottomRight, radius.BottomRight, radius.BottomRight, 0, 90);
    }
    else
    {
        result.AddLine(new System.Drawing.Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height), new System.Drawing.Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height));
    }
    if (radius.BottomLeft > 0)
    {
        result.AddArc(rectangle.X, rectangle.Y + rectangle.Height - radius.BottomLeft, radius.BottomLeft, radius.BottomLeft, 90, 90);
    }
    else
    {
        result.AddLine(new System.Drawing.Point(rectangle.X, rectangle.Y + rectangle.Height), new System.Drawing.Point(rectangle.X, rectangle.Y + rectangle.Height));
    }

    return result;
}

Now if I use this along with FillPath and DrawPath, I notice some odd results:

GraphicsPath path = CreateRoundRectanglePath(new BorderRadius(8), new Rectangle(10, 10, 100, 100));
e.Graphics.DrawPath(new Pen(Color.Black, 1), path);
e.Graphics.FillPath(new SolidBrush(Color.Black), path);

I've zoomed into each resulting Rectangle (right hand side) so you can see clearly, the problem:

rectangles

What I would like to know is: Why are all of the arcs on the drawn rectangle equal, and all of the arcs on the filled rectangle, odd?

Better still, can it be fixed, so that the filled rectangle draws correctly?

EDIT: Is it possible to fill the inside of a GraphicsPath without using FillPath?

EDIT: As per comments....here is an example of the BorderRadius struct

public struct BorderRadius
{
    public Int32 TopLeft { get; set; }
    public Int32 TopRight { get; set; }
    public Int32 BottomLeft { get; set; }
    public Int32 BottomRight { get; set; }

    public BorderRadius(int all) : this()
    {
        this.TopLeft = this.TopRight = this.BottomLeft = this.BottomRight = all;
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I experienced the same problem and found a solution. Might be too late for you @seriesOne but it can be useful to other people if they have this problem. Basically when using the fill methods (and also when setting the rounded rectangle as the clipping path with Graphics.SetClip) we have to move by one pixel the right and bottom lines. So I came up with a method that accepts a parameter to fix the rectangle is using the fill or not. Here it is:

private static GraphicsPath CreateRoundedRectangle(Rectangle b, int r, bool fill = false)
{
    var path = new GraphicsPath();
    var r2 = (int)r / 2;
    var fix = fill ? 1 : 0;

    b.Location = new Point(b.X - 1, b.Y - 1);
    if (!fill)
        b.Size = new Size(b.Width - 1, b.Height - 1);

    path.AddArc(b.Left, b.Top, r, r, 180, 90);
    path.AddLine(b.Left + r2, b.Top, b.Right - r2 - fix, b.Top);

    path.AddArc(b.Right - r - fix, b.Top, r, r, 270, 90);
    path.AddLine(b.Right, b.Top + r2, b.Right, b.Bottom - r2);

    path.AddArc(b.Right - r - fix, b.Bottom - r - fix, r, r, 0, 90);
    path.AddLine(b.Right - r2, b.Bottom, b.Left + r2, b.Bottom);

    path.AddArc(b.Left, b.Bottom - r - fix, r, r, 90, 90);
    path.AddLine(b.Left, b.Bottom - r2, b.Left, b.Top + r2);

    return path;
}

So this is how you use it:

g.DrawPath(new Pen(Color.Red), CreateRoundedRectangle(rect, 24, false));
g.FillPath(new SolidBrush(Color.Red), CreateRoundedRectangle(rect, 24, true));

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...