- 題名: DrawPathとFillPathの結果の違いについて教えて下さい
- 日時: 2009/01/28 14:04:40
- ID: 23878
- この記事の返信元:
- (なし)
- この記事への返信:
- [23879] Re[1]: DrawPathとFillPathの結果の違いについて教えて下さい2009/01/28 16:11:23
- ツリーを表示
魔界の仮面弁士さん、返信ありがとうございます。 ■No23879に返信(魔界の仮面弁士さんの記事) > 枠線のペン幅を 2 以上にする事はできませんか? > そうすれば、同じパスを使えるかも知れません。 > > ペンの太さが 1 の時、右下に 1 ドット大きく描画されてしまいますが、 > ペンの太さが 2 以上なら、指定した領域内に描画されるようなので。 ご提示頂いたコード・動作は確認致しました。 ペン幅については盲点でした… 四隅の円弧が、上下左右で対称で無い点については原因がわからないまま なのですが、1ピクセルの境界線については以下の方法で実現出来ましたので ソースを載せておきます。 四隅の円弧の問題については引き続き、ご存知の方がいらっしゃいましたら 宜しくお願い致します。 private static GraphicsPath CreateRoundRect(Rectangle rect, float w) { GraphicsPath gp = new GraphicsPath(); gp.StartFigure(); gp.AddArc(rect.Right - w, rect.Bottom - w, w, w, 0.0f, 90.0f); // 右下 gp.AddArc(rect.Left, rect.Bottom - w, w, w, 90.0f, 90.0f); // 左下 gp.AddArc(rect.Left, rect.Top, w, w, 180.0f, 90.0f); // 左上 gp.AddArc(rect.Right - w, rect.Top, w, w, 270.0f, 90.0f); // 右上 gp.CloseFigure(); return gp; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); float w = 45.0f; Rectangle rect = new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height); rect.Inflate(-1, -1); using (GraphicsPath gp = CreateRoundRect(rect, w)) using (SolidBrush brs = new SolidBrush(Color.Black)) { rect.Inflate(-1, -1); gp.AddPath(CreateRoundRect(rect, w), true); e.Graphics.FillPath(brs, gp); } }
# もし同じことをすでに試されていたら、スルーしてください > 四隅の円弧が、上下左右で対称で無い点については原因がわからないまま 円弧部分の点の座標は小数になります。 (推測ですが)画面に表示するとき小数→整数に変換されます。 切捨て、四捨五入、切上げのいずれを使っても、 画面上の円弧の形状は点対称になりません。 これが原因だと思います。 そこで、円弧の左上は小数を切上げ、右下は小数を切捨てて1ドットずつ円弧を描いてみました。 私のPCではうまく描けました。まことさんのPCでも試してみてください。 # コードがVBですがご了承下さいm(_ _)m Public Class GraphicsPathTestForm_ver3 Inherits Form ' 角丸四角形の画像を保持する変数 Dim m_image As Bitmap Protected Overrides Sub OnLoad(ByVal e As System.EventArgs) Me.Text = Me.GetType.Name Dim r As Rectangle = Me.ClientRectangle r.Inflate(-2, -2) Me.m_image = Me.CreateRoundBitmap(r, 30) MyBase.OnLoad(e) End Sub Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs) e.Graphics.DrawImage(Me.m_image, 2, 2) MyBase.OnPaint(e) End Sub ' 角丸四角形の画像を返す Private Function CreateRoundBitmap(ByVal rect As Rectangle, ByVal radius As Integer) As Bitmap Dim borderColor As Color = Color.Red Dim bgColor As Color = Color.Blue Dim bmp As New Bitmap(rect.Width, rect.Height) Using g As Graphics = Graphics.FromImage(bmp) ' bmpの色を初期化 g.Clear(SystemColors.Control) ' 直線 Using p As New Pen(borderColor) Dim x0 As Integer = radius Dim y0 As Integer = radius Dim x1 As Integer = rect.Width - 1 - radius Dim y1 As Integer = rect.Height - 1 - radius g.DrawLine(p, x0, 0, x1, 0) g.DrawLine(p, 0, y0, 0, y1) g.DrawLine(p, x0, rect.Height - 1, x1, rect.Height - 1) g.DrawLine(p, rect.Width - 1, y0, rect.Width - 1, y1) End Using End Using ' 右上円弧(小数点以下:x切り上げ、y切り捨て) Dim center As New Point(rect.Width - 1 - radius, radius) For i As Integer = 0 To 90 Dim x As Integer = CInt(Math.Ceiling(center.X + radius * Math.Cos(Me.GetRadian(i)))) Dim y As Integer = CInt(Math.Floor(center.Y - radius * Math.Sin(Me.GetRadian(i)))) bmp.SetPixel(x, y, borderColor) Next ' 左上円弧(小数点以下:x、y共切り捨て) center = New Point(radius, radius) For i As Integer = 90 To 180 Dim x As Integer = CInt(Math.Floor(center.X + radius * Math.Cos(Me.GetRadian(i)))) Dim y As Integer = CInt(Math.Floor(center.Y - radius * Math.Sin(Me.GetRadian(i)))) bmp.SetPixel(x, y, borderColor) Next ' 左下円弧(小数点以下:x切り捨て、y切り上げ) center = New Point(radius, rect.Height - 1 - radius) For i As Integer = 180 To 270 Dim x As Integer = CInt(Math.Floor(center.X + radius * Math.Cos(Me.GetRadian(i)))) Dim y As Integer = CInt(Math.Ceiling(center.Y - radius * Math.Sin(Me.GetRadian(i)))) bmp.SetPixel(x, y, borderColor) Next ' 右下円弧(小数点以下:x、y共切り上げ) center = New Point(rect.Width - 1 - radius, rect.Height - 1 - radius) For i As Integer = 270 To 360 Dim x As Integer = CInt(Math.Ceiling(center.X + radius * Math.Cos(Me.GetRadian(i)))) Dim y As Integer = CInt(Math.Ceiling(center.Y - radius * Math.Sin(Me.GetRadian(i)))) bmp.SetPixel(x, y, borderColor) Next ' 塗りつぶし For y As Integer = 0 To bmp.Height - 1 Dim flg As Flag = Flag.Outside For x As Integer = 0 To bmp.Width - 1 Dim c As Color = bmp.GetPixel(x, y) If Me.Color_Equals(c, borderColor) = True Then If flg = Flag.Outside Then ' 左側境界線に入った flg = Flag.FirstBorder ElseIf flg = Flag.Inside Then ' 右側境界線に入った Exit For End If ElseIf Me.Color_Equals(c, SystemColors.Control) = True Then If flg = Flag.FirstBorder Then If x >= bmp.Width \ 2 Then ' 上下境界線の場合は、ここに来る Exit For Else ' 領域内に入った flg = Flag.Inside End If End If If flg = Flag.Inside Then bmp.SetPixel(x, y, bgColor) End If End If Next Next Return bmp End Function ' Bitmap塗りつぶし用フラグ Private Enum Flag Outside = 0 FirstBorder Inside End Enum ' 以下、ヘルパーメソッド Private Function GetRadian(ByVal degree As Integer) As Double Return degree / 180 * Math.PI End Function Private Function Color_Equals(ByVal c1 As Color, ByVal c2 As Color) As Boolean Return c1.A = c2.A AndAlso c1.R = c2.R AndAlso _ c1.G = c2.G AndAlso c1.B = c2.B End Function End Class
分類:[.NET]