3

カスタム構造(長方形の左上、右上、左下、右下の半径を定義できますGraphicsPath) に基づいて角丸長方形を作成するコードと、初期自体を作成しました。BorderRadiusRectangle

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;
}

これを FillPath および DrawPath と一緒に使用すると、奇妙な結果が得られることに気付きます。

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);

Rectangle結果の各結果(右側)を拡大したので、問題がはっきりとわかります。

長方形

私が知りたいのは、描画された長方形のすべての円弧が等しく、塗りつぶされた長方形のすべての円弧が奇数であるのはなぜですか?

さらに良いことに、塗りつぶされた長方形が正しく描画されるように修正できますか?

編集: FillPath を使用せずに GraphicsPath の内部を埋めることは可能ですか?

編集:コメントによると....ここに BorderRadius 構造体の例があります

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;
    }
}
4

4 に答える 4

3

私は同じ問題を経験し、解決策を見つけました。@seriesOne には遅すぎるかもしれませんが、他の人がこの問題を抱えている場合に役立つ可能性があります。基本的に、塗りつぶしメソッドを使用する場合 (および Graphics.SetClip で角丸長方形をクリッピング パスとして設定する場合)、右と下の線を 1 ピクセルずつ移動する必要があります。そこで、四角形が塗りつぶしを使用しているかどうかを修正するパラメーターを受け入れるメソッドを思いつきました。ここにあります:

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;
}

だから、これはあなたがそれを使用する方法です:

g.DrawPath(new Pen(Color.Red), CreateRoundedRectangle(rect, 24, false));
g.FillPath(new SolidBrush(Color.Red), CreateRoundedRectangle(rect, 24, true));
于 2014-02-17T13:25:13.747 に答える
1

動作の本当の理由は、FillRectangle と DrawRectangle の Pixel 動作で説明されています。

これは、デフォルトのピクセルの丸めと、整数座標を持つ FillRectangle/FillPath がピクセルの中央に描画されて丸められるという事実に関係しています (Graphics.PixelOffsetMode に従って)。

一方、DrawRectangle/DrawPath は、ピクセル境界で完全に丸められる 1px ペンで描画します。

使用状況に応じて、FillRectangle/FillPath の四角形を .5px だけ膨張/収縮させることで解決できます。

于 2017-12-06T13:06:04.003 に答える
1

各弧の終わりから次の弧の始まりまで明示的に行を追加することをお勧めします。

Flatten メソッドを使用して、パス内のすべての曲線を線で近似することもできます。それはあいまいさを取り除くはずです。

FillPath から得られる結果は、Path 上のポイントが正しく解釈されず、基本的に 3 次ベジェ スプラインではなく 2 次になるという問題に似ています。

GetPathData 関数を使用してパス上のポイントを調べることができます: http://msdn.microsoft.com/en-us/library/ms535534%28v=vs.85%29.aspx

ベジエ曲線 (GDI+ が円弧を近似するために使用する曲線) は、4 つの点で表されます。1 つ目はエンドポイントで、任意のタイプにすることができます。2 番目と 3 番目はコントロール ポイントであり、PathPointBezier 型を持ちます。最後はもう一方のエンドポイントであり、タイプ PathPointBezier を持ちます。つまり、GDI+ が PathPointBezier を認識すると、パスの現在の位置と 3 つのベジェ ポイントを使用して曲線を描画します。ベジェ曲線はつなぎ合わせることができますが、ベジェ ポイントの数は常に 3 で割り切れる必要があります。

あなたがやっていることは少し奇妙です.それらを結合するための明示的な線なしで、さまざまな場所に曲線を描いています. 次のようなパターンが作成されると思います。

PathPointStart - end point of first arc
PathPointBezier - control point of first arc
PathPointBezier - control point of first arc
PathPointBezier - end point of first arc
PathPointLine - end point of second arc
PathPointBezier - control point of second arc
PathPointBezier - control point of second arc
PathPointBezier - end point of second arc
PathPointLine - end point of third arc
PathPointBezier - control point of third arc
PathPointBezier - control point of third arc
PathPointBezier - end point of third arc

それは合理的に見えます。GDI+ は、各曲線の最後の端点から次の曲線の最初の端点まで線を引く必要があります。DrawPath は明らかにこれを行いますが、FillPath はポイントを異なる方法で解釈していると思います。一部のエンド ポイントはコントロール ポイントとして扱われ、その逆も同様です。

于 2013-10-04T04:44:56.883 に答える