C#で3次のベジェ曲線(cubic-bezier)を描画するコードを紹介します。
C#で3次のベジェ曲線を描画する場合は、GraphicsオブジェクトのDrawBezier()
メソッドを利用すると簡単に描画できます。
下図のフォームを作成します。テキストボックスを4つ、ボタンを1つ、パネルコントロールを一つ配置します。
以下のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SimpleDrawCubicBezier
{
public partial class FormDrawCubicBezier : Form
{
Point point1;
Point point2;
Point point3;
Point point4;
Pen bPen;
Brush backBrush;
public FormDrawCubicBezier()
{
InitializeComponent();
bPen = new Pen(Color.Blue, 2);
backBrush = new SolidBrush(Color.White);
}
private void button1_Click(object sender, EventArgs e)
{
int cp1x = Convert.ToInt32(textBox1.Text);
int cp1y = Convert.ToInt32(textBox2.Text);
int cp2x = Convert.ToInt32(textBox3.Text);
int cp2y = Convert.ToInt32(textBox4.Text);
point1 = new Point(0, 320);
point2 = new Point(cp1x,cp1y);
point3 = new Point(cp2x,cp2y);
point4 = new Point(320, 0);
panel1.Refresh();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(backBrush, new Rectangle(0, 0, 320, 320));
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.DrawBezier(bPen, point1, point2, point3, point4);
}
}
}
[button1]をクリックすると以下のコードを実行します。
テキストボックスに入力されている2つの制御点の座標値を変数に代入し、曲線の始点と終点を合わせた4つのPoint型の値を作成します。
int cp1x = Convert.ToInt32(textBox1.Text);
int cp1y = Convert.ToInt32(textBox2.Text);
int cp2x = Convert.ToInt32(textBox3.Text);
int cp2y = Convert.ToInt32(textBox4.Text);
point1 = new Point(0, 320);
point2 = new Point(cp1x,cp1y);
point3 = new Point(cp2x,cp2y);
point4 = new Point(320, 0);
値の設定後、パネルを更新します。
panel1.Refresh();
パネルのPaintメソッドで曲線を描画します。描画のコードは次のコードです。
背景部分を白色で塗りつぶします。
e.Graphics.FillRectangle(backBrush, new Rectangle(0, 0, 320, 320));
SmoothingMode でアンチエイリアスを有効にします。DrawBezier() メソッドでベジェ曲線を描画します。
第一引数にびょぐあで利用するペンオブジェクトを与えます。第2引数にベジェ曲線の始点の座標、第3引数に1つ目のコントロールポイントの座標、
第4引数に2つ目のコントロールポイントの座標、第5引数にベジェ曲線の終点の座標を与えます。
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.DrawBezier(bPen, point1, point2, point3, point4);
プロジェクトを実行します。下図のウィンドウが表示されます。
[Draw]をクリックします。ベジェ曲線がパネルに描画されます。
上部のテキストボックスのコントロールポイントの座標値を変更して[Draw]ボタンをクリックすると、曲線の形状が変わることが確認できます。
3次ベジェ曲線を描画できました。
先ほどのプログラムでベジェ曲線は描画できましたが、コントロールポイントの位置や、ベジェ曲線の値が枠をはみ出した場合でも描画できるよう周囲にマージンを追加します。
また、コントロールポイントの値を枠の幅、高さで正規化します。
下図のフォームを作成します。テキストボックスを4つ、ボタンを1つ、パネルコントロールを一つ配置します。
以下のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace SimpleDrawCubicBezier
{
public partial class FormDrawCubicBezierEx : Form
{
Point point1;
Point point2;
Point point3;
Point point4;
Pen bPen;
Pen fPen;
Pen cPen;
Brush backBrush;
Brush controlpointBrush;
int offsetX, offsetY;
int areaWidth, areaHeight;
int controlpointRaduis;
public FormDrawCubicBezierEx()
{
InitializeComponent();
offsetX = 64;
offsetY = 64;
areaWidth = 320;
areaHeight = 320;
controlpointRaduis = 8;
bPen = new Pen(Color.Blue, 2);
fPen = new Pen(Color.Black, 1);
cPen = new Pen(Color.FromArgb(105,161,255), 1);
backBrush = new SolidBrush(Color.White);
controlpointBrush= new SolidBrush(Color.FromArgb(105, 161, 255));
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(backBrush, new Rectangle(0, 0, panel1.Width, panel1.Height));
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.DrawRectangle(fPen, new Rectangle(offsetX, offsetY, areaWidth, areaHeight));
e.Graphics.DrawLine(cPen, point1, point2);
e.Graphics.DrawLine(cPen, point4, point3);
e.Graphics.FillEllipse(controlpointBrush, new Rectangle(point2.X - controlpointRaduis, point2.Y - controlpointRaduis, controlpointRaduis*2, controlpointRaduis * 2));
e.Graphics.FillEllipse(controlpointBrush, new Rectangle(point3.X - controlpointRaduis, point3.Y - controlpointRaduis, controlpointRaduis * 2, controlpointRaduis * 2));
e.Graphics.DrawBezier(bPen, point1, point2, point3, point4);
}
private void button1_Click(object sender, EventArgs e)
{
double cp1x = Convert.ToDouble(textBox1.Text);
double cp1y = Convert.ToDouble(textBox2.Text);
double cp2x = Convert.ToDouble(textBox3.Text);
double cp2y = Convert.ToDouble(textBox4.Text);
point1 = new Point(offsetX, offsetY + areaHeight);
point2 = new Point(offsetX + (int)(areaWidth * cp1x), offsetY + (int)(areaHeight * cp1y));
point3 = new Point(offsetX + (int)(areaWidth * cp2x), offsetY + (int)(areaHeight * cp2y));
point4 = new Point(offsetX + areaWidth, offsetY);
panel1.Refresh();
}
}
}
基本の処理は先のコードと同様です。コントロールポイントを描画する処理や、正規化した値を座標に変換するための掛け算などを追加しています。
上記のプロジェクトを実行します。下図のウィンドウが表示されます。
[Draw]ボタンをクリックします。下図の画面が表示されます。ベジェ曲線とコントロールポイントがパネル上に表示されます。
コントロールポイントの値を変更してベジェ曲線が枠をはみ出る場合でも描画できます。