DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

角を丸めて四角や折れ線を描く

注意:画像の表示方法が分からないという方は、まず「コントロールやフォームに画像を表示する」をご覧ください。また、四角を描く方法については「長方形、多角形、楕円、円弧、扇形を描く」、折れ線を描く方法については「折れ線を描く」をご覧ください。

PenクラスのLineJoinプロパティにより、四角の角や、折れ線を引いたときの折れた部分を丸くしたり、面取りをしたりすることができます。LineJoinプロパティにBevelを設定すると角の面取りを、Roundを設定すると丸めを行います。MiterClippedやMiterを設定した時は、鋭角な角だけ面取りやクリッピングをします。LineJoinプロパティのデフォルトはMiterです。

以下にLineJoinプロパティを色々変えて四角を描画する例を示します。

VB.NET
コードを隠すコードを選択
'Imports System.Drawing

'描画先とするImageオブジェクトを作成する
Dim canvas As New Bitmap(PictureBox1.Width, PictureBox1.Height)
'ImageオブジェクトのGraphicsオブジェクトを作成する
Dim g As Graphics = Graphics.FromImage(canvas)

'Penの作成
Dim blackPen As New Pen(Color.Black, 10)

'LineJoinをBevelに変更して四角を描く(角の面取りが行われる)
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Bevel
g.DrawRectangle(blackPen, New Rectangle(70, 10, 40, 40))

'LineJoinをMiterに変更して四角を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Miter
g.DrawRectangle(blackPen, New Rectangle(130, 10, 40, 40))

'LineJoinをMiterClippedに変更して四角を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.MiterClipped
g.DrawRectangle(blackPen, New Rectangle(190, 10, 40, 40))

'LineJoinをRoundに変更して四角を描く(角が丸められる)
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round
g.DrawRectangle(blackPen, New Rectangle(250, 10, 40, 40))

'リソースを解放する
blackPen.Dispose()
g.Dispose()

'PictureBox1に表示する
PictureBox1.Image = canvas
C#
コードを隠すコードを選択
//using System.Drawing;

//描画先とするImageオブジェクトを作成する
Bitmap canvas = new Bitmap(PictureBox1.Width, PictureBox1.Height);
//ImageオブジェクトのGraphicsオブジェクトを作成する
Graphics g = Graphics.FromImage(canvas);

//Penの作成
Pen blackPen = new Pen(Color.Black, 10);

//LineJoinをBevelに変更して四角を描く(角の面取りが行われる)
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Bevel;
g.DrawRectangle(blackPen, new Rectangle(70, 10, 40, 40));

//LineJoinをMiterに変更して四角を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Miter;
g.DrawRectangle(blackPen, new Rectangle(130, 10, 40, 40));

//LineJoinをMiterClippedに変更して四角を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.MiterClipped;
g.DrawRectangle(blackPen, new Rectangle(190, 10, 40, 40));

//LineJoinをRoundに変更して四角を描く(角が丸められる)
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;
g.DrawRectangle(blackPen, new Rectangle(250, 10, 40, 40));

//リソースを解放する
blackPen.Dispose();
g.Dispose();

//PictureBox1に表示する
PictureBox1.Image = canvas;

結果は、次のようになります。

LineJoinプロパティ

このように長方形(直角に接合した直線)の場合は、デフォルトでは、Bevelの面取りと、Roundの丸めだけが行われます。

面取りが行われる条件を変更する

MiterとMiterClippedの場合は、デフォルトでは、かなり鋭角にしないと面取りが行われません。例えば以下の例では平行四辺形を描画していますが、ここまで鋭角にしてやっとMiterClippedで面取りが行われるようになります。

MiterClipped

VB.NET
コードを隠すコードを選択
'Imports System.Drawing

'描画先とするImageオブジェクトを作成する
Dim canvas As New Bitmap(PictureBox1.Width, PictureBox1.Height)
'ImageオブジェクトのGraphicsオブジェクトを作成する
Dim g As Graphics = Graphics.FromImage(canvas)

'Penの作成
Dim blackPen As New Pen(Color.Black, 10)

'平行四辺形の角の座標を設定
Dim ps As Point() = {New Point(0, 0), _
                     New Point(50, 0), _
                     New Point(100, 10), _
                     New Point(50, 10)}

'座標系を変更
g.TranslateTransform(60, 20)

'LineJoinをBevelに変更して平行四辺形を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Bevel
g.DrawPolygon(blackPen, ps)

'座標系を変更して、下に平行移動
g.TranslateTransform(0, 30)

'LineJoinをMiterに変更して平行四辺形を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Miter
g.DrawPolygon(blackPen, ps)

'座標系を変更して、下に平行移動
g.TranslateTransform(0, 30)

'LineJoinをMiterClippedに変更して平行四辺形を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.MiterClipped
g.DrawPolygon(blackPen, ps)

'座標系を変更して、下に平行移動
g.TranslateTransform(0, 30)

'LineJoinをRoundに変更して平行四辺形を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round
g.DrawPolygon(blackPen, ps)

'リソースを解放する
blackPen.Dispose()
g.Dispose()

'PictureBox1に表示する
PictureBox1.Image = canvas
C#
コードを隠すコードを選択
//using System.Drawing;

//描画先とするImageオブジェクトを作成する
Bitmap canvas = new Bitmap(PictureBox1.Width, PictureBox1.Height);
//ImageオブジェクトのGraphicsオブジェクトを作成する
Graphics g = Graphics.FromImage(canvas);

//Penの作成
Pen blackPen = new Pen(Color.Black, 10);

//平行四辺形の角の座標を設定
Point[] ps = {new Point(0, 0),
     new Point(50, 0),
     new Point(100, 10),
     new Point(50, 10)};

//座標系を変更
g.TranslateTransform(60, 20);

//LineJoinをBevelに変更して平行四辺形を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Bevel;
g.DrawPolygon(blackPen, ps);

//座標系を変更して、下に平行移動
g.TranslateTransform(0, 30);

//LineJoinをMiterに変更して平行四辺形を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Miter;
g.DrawPolygon(blackPen, ps);

//座標系を変更して、下に平行移動
g.TranslateTransform(0, 30);

//LineJoinをMiterClippedに変更して平行四辺形を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.MiterClipped;
g.DrawPolygon(blackPen, ps);

//座標系を変更して、下に平行移動
g.TranslateTransform(0, 30);

//LineJoinをRoundに変更して平行四辺形を描く
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;
g.DrawPolygon(blackPen, ps);

//リソースを解放する
blackPen.Dispose();
g.Dispose();

//PictureBox1に表示する
PictureBox1.Image = canvas;

MiterとMiterClippedで面取りが行われるかどうかは、Pen.MiterLimitプロパティの値で決まります。MiterLimitプロパティはマイター制限(マイター限界比率)を表しており、2つの直線の接合部がマイター制限を超えると、制限内に収まるようにクリッピングや斜めの角が作成されます。

MSDNによると、マイター制限とは「マイター長とストローク幅の最大許容割合のこと」だそうです。JavaScriptの記事ですが、マイター限界比率の分かりやすい説明が「miterLimit プロパティ- HTML5.JP」にあります。

つまるところ、MiterLimitプロパティの値を小さくすれば、それほどとがっていない角でも面取りが行われるようになります。デフォルトは10です。

一番初めの四角を描画する例の場合、MiterLimitプロパティを1にすれば、MiterとMiterClippedでも面取りが行われるようになります。この時、下の図のようになります。MiterとMiterClippedは全く同じに見えます。

MiterLimitプロパティを小さくして面取りをした四角

VB.NET
コードを隠すコードを選択
'Penの作成
Dim blackPen As New Pen(Color.Black, 10)
'マイター限度を小さくする
blackPen.MiterLimit = 1F

'以下省略
C#
コードを隠すコードを選択
//Penの作成
Pen blackPen = new Pen(Color.Black, 10);
//マイター限度を小さくする
blackPen.MiterLimit = 1f;

//以下省略

線の両端を丸める

直線の両端を丸めるには、PenのStartCapプロパティEndCapプロパティをLineCap.Roundにします。端をくの字に(とがったように)するには、LineCap.Triangleにします。これらについて詳しくは、「矢印を描く」で説明しています。

接合部と、始点と終点を丸めた折れ線を描画する例を以下に示します。

始点と終点を丸めた折れ線

VB.NET
コードを隠すコードを選択
'Imports System.Drawing

'描画先とするImageオブジェクトを作成する
Dim canvas As New Bitmap(PictureBox1.Width, PictureBox1.Height)
'ImageオブジェクトのGraphicsオブジェクトを作成する
Dim g As Graphics = Graphics.FromImage(canvas)

'Penの作成
Dim blackPen As New Pen(Color.Black, 10)
'接合部分を丸める
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round
'始点と終点を丸める
blackPen.StartCap = System.Drawing.Drawing2D.LineCap.Round
blackPen.EndCap = System.Drawing.Drawing2D.LineCap.Round

'折れ線の座標を設定
Dim ps As Point() = {New Point(10, 60), New Point(35, 10), New Point(60, 60)}

'折れ線を描く
g.DrawLines(blackPen, ps)

'リソースを解放する
blackPen.Dispose()
g.Dispose()

'PictureBox1に表示する
PictureBox1.Image = canvas
C#
コードを隠すコードを選択
//using System.Drawing;

//描画先とするImageオブジェクトを作成する
Bitmap canvas = new Bitmap(PictureBox1.Width, PictureBox1.Height);
//ImageオブジェクトのGraphicsオブジェクトを作成する
Graphics g = Graphics.FromImage(canvas);

//Penの作成
Pen blackPen = new Pen(Color.Black, 10);
//接合部分を丸める
blackPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;
//始点と終点を丸める
blackPen.StartCap = System.Drawing.Drawing2D.LineCap.Round;
blackPen.EndCap = System.Drawing.Drawing2D.LineCap.Round;

//折れ線の座標を設定
Point[] ps = {new Point(10, 60),
     new Point(35, 10),
     new Point(60, 60)};

//折れ線を描く
g.DrawLines(blackPen, ps);

//リソースを解放する
blackPen.Dispose();
g.Dispose();

//PictureBox1に表示する
PictureBox1.Image = canvas;
  • 履歴:
  • 2010/2/28 リンクの間違いを修正。
  • 2012/8/3 表示する方法を、PictureBox.Imageプロパティを使った方法に変更。MiterとMiterClippedの違いを示す例を追加。
  • 2014/6/12 Pen.MiterLimitプロパティの説明と、「線の両端を丸める」を追加。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。