WisdomSoft - for your serial experiences.

2.7 曲線

滑らかな曲線を描画する方法を紹介します。

2.7.1 ベジェ曲線

点と点を繋ぐ直線以外に、始点と終点の間で線が曲がる曲線を描画することができます。曲線を描画するには Graphics クラスの DrawBezier() メソッドを使います。このメソッドは、ベジェ曲線を描画します。

ベジェ曲線とは、コンピュータで曲線を表現する代表的な手段で、始点と終点に加えて線の形状を決定する制御点を設定します。これを利用することで、滑らかな曲線を描画することができます。

Graphics クラス DrawBezier() メソッド
public void DrawBezier(Pen pen, Point pt1, Point pt2, Point pt3, Point pt4)

pen パラメータには線を引くペンオブジェクトを、pt1 パラメータには開始点、pt4 パラメータには終了点を設定します。曲線は必ず pt1 パラメータと pt4 パラメータを通過します。pt2 パラメータと pt3 パラメータは pt1 パラメータと pt4 パラメータの間の制御点を設定します。曲線は pt2 パラメータと pt3 パラメータの上を通過することはなく、曲線の形を決定するために使われます。

コード1
using System.Drawing;
using System.Windows.Forms;

public class Test : Form
{
	protected override void OnPaint(PaintEventArgs e) 
	{
		base.OnPaint(e);
		Pen pen = new Pen(Color.Black, 5);
		Point pt1 = new Point(0, 0);
		Point pt2 = new Point(100, 200);
		Point pt3 = new Point(200, 0);
		Point pt4 = new Point(300, 200);
		e.Graphics.DrawBezier(pen, pt1, pt2, pt3, pt4);

		pen.Width = 1;
		e.Graphics.DrawLine(pen, pt1, pt2);
		e.Graphics.DrawLine(pen, pt2, pt3);
		e.Graphics.DrawLine(pen, pt3, pt4);
	}
	static void Main() 
	{
		Application.Run(new Test());
	}
}
実行結果
コード1 実行結果

コード1は、DrawBezier() メソッドを使って4つの点からベジェ曲線を描画しています。また、それぞれの点の位置が確認しやすいように DrawLine() メソッドで各点を結んでいます。制御点の座標を変更すれば、ベジェ曲線が制御点を参考に曲線を描いていることを確認することができます。

2.7.2 カーディナル スプライン

ベジェ曲線は、制御点を通過しませんでしたが、カーディナル スプラインを使えば各点を滑らかに通過する曲線を描画うすることができます。大きな曲線を描画するときにカーディナル スプラインは適しています。

カーディナル スプラインを描画するには Graphics クラスの DrawCurve() メソッドを使います。

Graphics クラス DrawCurve() メソッド
public void DrawCurve(Pen pen, Point[] points)

pen パラメータには描画に使われるペンを、points パラメータには曲線を定義する4つ以上の要素を含む Point 構造体の配列を指定します。

コード2
using System.Drawing;
using System.Windows.Forms;

public class Test : Form
{
	protected override void OnPaint(PaintEventArgs e) 
	{
		base.OnPaint(e);
		Pen pen = new Pen(Color.Black, 5);
		Point[] pts = {
			new Point(0, 0), new Point(100, 150),
			new Point(200, 50), new Point(300, 200)
		};
		e.Graphics.DrawCurve(pen, pts);

		pen = new Pen(Color.Red, 1);
		for(int i = 0 ; (i + 1) < pts.Length ; i++)
			e.Graphics.DrawLine(pen, pts[i], pts[i + 1]);
	}
	static void Main() 
	{
		Application.Run(new Test());
	}
}
実行結果
コード2 実行結果

コード2は、曲線の通過点を定義する Point 構造体の配列 pts を作成し、これを DrawCurve() メソッドに渡して描画しています。ベジェ曲線とは異なりすべての点の座標を曲線が通過していることを確認することができます。

DrawCurve() メソッドはオーバーロードされていて、点と点の間の曲線をどのくらい曲げるかを設定するテンションと呼ばれる値を設定することができます。

Graphics クラス DrawCurve() メソッド
public void DrawCurve(Pen pen, Point[] points, float tension)

pen パラメータと points パラメータの意味は、これまでと同じです。tension パラメータにテンションを設定します。省略した場合、テンションは 0.5F が設定されます。テンションは 0.0F からの値で、 0 を指定した場合は点と点を最短距離で結ぶことを表し(すなわち直線)、1.0F であれば曲げの合計が最小になるように結ぶことを表します。値が 1 よりも大きくなると、曲線は圧縮され長いルートを通るようになります。

コード3
using System.Drawing;
using System.Windows.Forms;

public class Test : Form
{
	protected override void OnPaint(PaintEventArgs e) 
	{
		base.OnPaint(e);
		Pen pen = new Pen(Color.Black, 1);
		Point[] pts = {
			new Point(0, 0), new Point(100, 150),
			new Point(200, 50), new Point(300, 200)
		};
		e.Graphics.DrawCurve(pen, pts, 0F);

		pen.Color = Color.Blue;
		e.Graphics.DrawCurve(pen, pts, 0.5F);

		pen.Color = Color.Green;
		e.Graphics.DrawCurve(pen, pts, 1F);

		pen.Color = Color.Red;
		e.Graphics.DrawCurve(pen, pts, 2F);
	}
	static void Main() 
	{
		Application.Run(new Test());
	}
}
実行結果
コード3 実行結果

コード3は、曲線のテンションを変更しながら同一の Point 構造体の配列で描画しています。すべての線に使っている Point 構造体の配列は同じですが、テンションを変更することで線の曲がり方が変わっています。