x方向に始点(x1)~終点(x2)まで移動(符号方向に1づつ)させるときにyの値がどうなるかをかんがえてみることにしました。
移動の回数はx2-x1の絶対値で長さを求めて、移動方向に関しては、x2がx1以上の場合は+1、x1がx2より大きい場合は-1とする。つまり、x2-x1が負の場合、-1。正(ゼロを含めて)の場合は+1とする。
ここで、画面上の座標は整数となるため、x方向に1進むときのyの値も整数になるように小数点第一位を四捨五入するようにしてみる。
整数部をy、少数部をeであらわすことにして、
n番目のynの値は、y=y{n}+e{n}
ここで、y{1}はかならず整数で始まるのでe{1}=0・・・(1)
e{n}=e{n-1}+⊿y÷⊿x・・・(2)
(四捨五入するのひ判定を簡単にして)
e{n}-0.5≧0のとき、y{n}=y{n-1}+1,
e{n}はe{n}-1を代入。
e{n}-0.5<0のとき、y{n}=y{n-1}
e{n}-0.5は単に判定用に使っているので計算を簡単にする都合上2⊿xを掛けて、
E{n}=2⊿x(e{n}-0.5)として、上記の(1)(2)に当てはめると、
E{1}=2⊿x(e{1}-0.5)=2⊿x(0-0.5)=-⊿x
E{n}=2⊿x(e{n-1}+⊿y÷⊿x-0.5)
=2⊿xe{n-1}+2⊿y-⊿x
=(2⊿xe{n-1}-⊿x)+2⊿y=E{n-1}+2⊿y
(⇒E{n}=2⊿x(e{n}-0.5)としたので、
E{n-1}=2⊿x(e{n-1}-0.5)=2⊿xe{n-1}-⊿x
・・・n番目が前者なのでn-1番目は後者。
よって、前半の括弧をE{n-1}に置換え可能。)
上記を整理してみると、
x{n}=x{1}+n,y=y{1}+⊿y÷⊿x・nのときに、
E{1}=-⊿x,E{n}=E{n-1}+2⊿yとすると、
E{n}≧0のとき、y{n}=y{n-1}+1,
E{n}はE{n}-2⊿xを代入。・・・(3)
E{n}<0のとき、y{n}=y{n-1}
【(3)Eはeの2⊿xとしたので、-1は-2⊿xと置き換える】
これまでのことはすべて、xを動かすことを考えていたが、
⊿y÷⊿x>1の場合、
xを1動かすとyが1以上動いてしまい、線がつながらなくなるので、その場合は、yを動かし、xを求めるようにする。以下がそのソース。
form1.csの内容。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Bitmap Bmap = new Bitmap(pictureBox1.Width,
pictureBox1.Height);
int x1,x2;
int y1,y2;
x1 = -100; x2 = 100; y1 = -100; y2 = 100;
this.line(ref Bmap, x1, y1, x2, y2, Color.Blue);
x1 = -100; x2 = 100; y1 = 100; y2 = -100;
this.line(ref Bmap, x1, y1, x2, y2, Color.Red);
x1 = 50; x2 = 50; y1 = 0; y2 = 0;
this.line(ref Bmap, x1, y1, x2, y2, Color.Black);
x1 = -50; x2 = 50; y1 = -100; y2 = 100;
this.line(ref Bmap, x1, y1, x2, y2, Color.Cyan);
x1 = -100; x2 = 100; y1 = -50; y2 = 50;
this.line(ref Bmap, x1, y1, x2, y2, Color.Magenta);
pictureBox1.Image = Bmap;
}
private void line(ref Bitmap bm, int x1, int y1, int x2, int y2,
Color c)
{
int dx, lenx, sx;
int dy, leny, sy;
int i, ix, iy, E;
dx = x2 - x1; dy = y2 - y1;
lenx = Math.Abs(dx); leny = Math.Abs(dy);
sx = Math.Sign(dx + 0.1); sy = Math.Sign(dy + 0.1);
ix = x1; iy = y1;
if (leny > lenx)
{
E = -leny;
for (i=0; i <= leny; i++)
{
this.pset(ref bm, ix, iy, c);
iy += sy;
E += 2 * lenx;
if (E >= 0)
{
ix += sx;
E -= 2 * leny;
}
}
}
else
{
E = -lenx;
for (i=0; i <= lenx; i++)
{
this.pset(ref bm, ix, iy, c);
ix += sx;
E += 2 * leny;
if (E >= 0)
{
iy += sy;
E -= 2 * lenx;
}
}
}
}
private void pset(ref Bitmap bm,int x,int y,Color c)
{
int x0 = 320; int y0 = 200;
int xx = x0 + x;
int yy = y0 - y;
bm.SetPixel(xx, yy, c);
}
}
左図は実行結果。(クリックで大きくできます)
少しだけ、解説。
Math.Signは負で-1、ゼロは0、
正は+1となってしまって、ゼロの時に不都合があるので、ゼロも正の値を返すように、0.1を足して、符号を見るようにしました。
それから、コンピュータの画像では、左上が(0,0)で、yは下に行く方が+方向に増えていくので一般的な(学問的な)座標軸に直すために、画像の中心を原点に補正し、さらに、y方向は上が+、下が-になるように変換させています。点を打つpsetのメソッドでそこら辺をまとめて処理してます。
最近のコメント