グラフィックス

円の座標点の値をrubyで検証

C#で作成した円を描くロジックの数値を具体的に確認してみたかったので、rubyで似たようなロジックを作成して出力してみました。

paintcircle.rb
---------------------- O ----------------
x = 0
y = 0
r = 100

ix=r*1.0
iy=0.0
E=1.0/r

print "E=",E,"\n"
i=0
begin
    ix -= E * iy
    iy += E * ix
    i+=1
#    print "i=",i," ix=",ix," iy=",iy,"\n"
    puts sprintf "i=%3d ix=%11.6f iy=%11.6f <ix-r>=%11.6f\n",i,ix,iy,ix-r
    #break if i == 5
end while (ix - r).abs > 0.5 || iy.abs > 0.5
---------------------- O ----------------

結果(抜粋)は下記の通りとなりました。
E=0.01
i=  1 ix= 100.000000 iy=   1.000000 <ix-r>=   0.000000
i=  2 ix=  99.990000 iy=   1.999900 <ix-r>=  -0.010000
i=  3 ix=  99.970001 iy=   2.999600 <ix-r>=  -0.029999
    *
         *
i=155 ix=   2.578735 iy=  99.979640 <ix-r>= -97.421265
i=156 ix=   1.578939 iy=  99.995429 <ix-r>= -98.421061
i=157 ix=   0.578985 iy= 100.001219 <ix-r>= -99.421015
i=158 ix=  -0.421028 iy=  99.997009 <ix-r>=-100.421028
i=159 ix=  -1.420998 iy=  99.982799 <ix-r>=-101.420998
i=160 ix=  -2.420826 iy=  99.958590 <ix-r>=-102.420826
    *
         *
i=312 ix= -99.965928 iy=   2.157825 <ix-r>=-199.965928
i=313 ix= -99.987506 iy=   1.157950 <ix-r>=-199.987506
i=314 ix= -99.999085 iy=   0.157959 <ix-r>=-199.999085
i=315 ix=-100.000665 iy=  -0.842048 <ix-r>=-200.000665
i=316 ix= -99.992245 iy=  -1.841970 <ix-r>=-199.992245
i=317 ix= -99.973825 iy=  -2.841708 <ix-r>=-199.973825
i=318 ix= -99.945408 iy=  -3.841163 <ix-r>=-199.945408
    *
         *
i=469 ix=  -2.736638 iy= -99.976231 <ix-r>=-102.736638
i=470 ix=  -1.736876 iy= -99.993600 <ix-r>=-101.736876
i=471 ix=  -0.736940 iy=-100.000969 <ix-r>=-100.736940
i=472 ix=   0.263070 iy= -99.998339 <ix-r>= -99.736930
i=473 ix=   1.263053 iy= -99.985708 <ix-r>= -98.736947
i=474 ix=   2.262910 iy= -99.963079 <ix-r>= -97.737090
    *
         *
i=625 ix=  99.928451 iy=  -3.315360 <ix-r>=  -0.071549
i=626 ix=  99.961605 iy=  -2.315744 <ix-r>=  -0.038395
i=627 ix=  99.984762 iy=  -1.315897 <ix-r>=  -0.015238
i=628 ix=  99.997921 iy=  -0.315917 <ix-r>=  -0.002079

| | コメント (0) | トラックバック (0)

C# 点で円を描く

きれいな円が描ける様になりました。ソースは下記のように記述しています。

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
  Bitmap Bmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
  int x, y, r;

  x = 0; y = 0; r = 150;
  this.circle(ref Bmap, x, y, r, Color.Yellow);
  x = 50; y = 50; r = 100;
  this.circle(ref Bmap, x, y, r, Color.Red);
  x = -50; y = -50; r = 100;
  this.circle(ref Bmap, x, y, r, Color.Blue);
  x = -50; y = 50; r = 100;
  this.circle(ref Bmap, x, y, r, Color.Green);
  x = 50; y = -50; r = 100;
  this.circle(ref Bmap, x, y, r, Color.Brown);

  pictureBox1.Image = Bmap;
}

private void circle(ref Bitmap bm, int x, int y, int r, Color c)
{
  double ix, iy, E;

  ix = r; iy = 0; E = 1.0 / r;

  do
  {
    ix = ix - E * iy;
    iy = E * ix + iy;
    this.pset(ref bm, (int)ix+x, (int)iy+y, c);
  } while (Math.Abs(ix - r) > .5 || Math.Abs(iy) > .5);
}

sinθ
cosθ のθを0に限りなく近づくくらい小さい値を設定して、
sinθ≒ε cosθ≒1 になるとすれば、
x{n+1}=x{n}・cosθ-y{n}・sinθ
y{n+1}=x{n}・sinθ+y{n}・cosθ は、下記のように表せます
      ↓
x{n+1}=x{n}-ε・y{n}
y{n+1}=ε・x{n}+y{n}  …nは移動前の点、n+1は移動後の点
ただこれでは、y方向に大きく動きすぎるため、補正をかけて、すこし小さくすることにします。
Cscircle y{n+1}=ε・x{n+1}+y{n}

また、εの値は、円周2πr(ドット)を埋めるために必要な角度、
2π(ラジアン=360°)÷2πr(円周)で、1/rを使用すると良いようです。

ということで、めでたく円がきれいに描ける様になりました。よかった。よかった。

| | コメント (0) | トラックバック (0)

c# 円の座標ってむずかしい?

  円を考えると自分の数学の力では手に負えなくなってきているようです。
下記のソースで1度づつ描画すると、点が間引かれて点線になってしまった。
始点と終点で線を引くようにすれば、とりあえず円として繋がりそうだけど、大丈夫かな?
円周2πrの1点1点を描く角度を探した方がいいのでしょうか?

private void circle(ref Bitmap bm, int x, int y, int r, Color c)
{
    for (int i=0;i<=360;i++)
  {
    double a = (2 * Math.PI * i / 360);
    int ix = (int)(r * Math.Cos(a) + x);
    int iy = (int)(r * Math.Sin(a) + y);
    this.pset(ref bm, ix, iy, c);
  }
}

Cscircle01 ソースは、x,yを中心とした半径rの円を描くメソッド。として作ったつもり(ちょっと失敗)
でも、これを2倍の720分の1づつ点を描くようにすると、きれいな円として描ける様になるかもしれないです。


Cscircle00ということで、実験結果が左図。
ソースは以下のように修正しました

for (int i=0;i<=720;i++)

double a = (Math.PI * i / 360);

| | コメント (0) | トラックバック (0)

C# 円を考えると

円の方程式は 「x*x+y*y=r*r」なので、
 x=±√(r・r-y・y)
 y=±√(r・r-x・x)

でも、これをそのまま使うと、上と下の方でyの密度が高くなって、逆に真中付近ではyが拡散してしまうので、別の計算方法を考える必要がありそう。と、いうことで、

△ABCで、Aの角度をθ、Bの角度を90°とする直角三角形を見ると、
sinθ=(BC)÷(CA)、cosθ=(AB)÷(CA)
             ↓
sinθ=y÷r、cosθ=x÷r ⇒ y=r・sinθ、x=r・cosθ
このθをπで表し、360°=2π。
これを細かく分割して、その時のxとyの値を上記の換算式で計算し、点を算出する。
それぞれの点を始点と終点として線を書けば、円に類似した多角形が描画できることになります。
80分割すれば、きれいな円として描けるようです。

| | コメント (0) | トラックバック (0)

C# 点を打つことで線を引く

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);
    }
  }

Csline左図は実行結果。(クリックで大きくできます)
少しだけ、解説。
Math.Signは負で-1、ゼロは0、
正は+1となってしまって、ゼロの時に不都合があるので、ゼロも正の値を返すように、0.1を足して、符号を見るようにしました。
それから、コンピュータの画像では、左上が(0,0)で、yは下に行く方が+方向に増えていくので一般的な(学問的な)座標軸に直すために、画像の中心を原点に補正し、さらに、y方向は上が+、下が-になるように変換させています。点を打つpsetのメソッドでそこら辺をまとめて処理してます。

| | コメント (0) | トラックバック (0)

C# DrawLineで線を描く

やった!やっと、線が出力されました。
とりあえず、できた。って感じ。

Form1.cs
  private void pictureBox1_Paint(object sender, PaintEventArgs e)
  {
    Graphics g = e.Graphics;
    Pen bluePen = new Pen(Color.Blue, 3);
    Point pstart = new Point(0,0);
    Point pend = new Point(639,399);
    g.DrawLine(bluePen,pstart,pend);
  }

まずは、1歩づつ先に進めそうなのでここで数学のお勉強。
確か、学校で直線の方程式は「y=ax+b」って習ったような。。。
ここで、話を簡単にするために、始点(原点:0,0)~終点(1,1)の線は
  y=x   ---> aは1、bはゼロ  
    更に aは(yの増加量(1)÷xの増加量(1))

一般式に直せば、
 y=(yの増加量÷xの増加量)×(x-xの始点)+yの始点
   ↓
 y = (y2-y1) ÷ (x2-x1) × (x - x1) + y1
これが、始点(x1,y1)~終点(x2,y2)の直線を描く方程式として定義できそう。
xをx1→x2まで順に動かしてyを求めれば、開始~終了までの2点を描く線が引けるのかな?たぶん。

| | コメント (0) | トラックバック (0)

C# paintイベント

pictureboxオブジェクトを選んでもプロパティのところしか出てこなかったのでイベントってどこで設定するのかな~って思ってたら、イベントに切り替えるボタンがあった。ここでpictureboxのpaintインベトを選んでソースを記述する場所にとりあえず、線を出すDrawLineを書いてみたら。。。。。

え、一瞬線が引かれたけど、すぐ消えたよ!!なんで?もうちょっとでスタートラインに立てそう。

でもその前に、イベントの処理を確認するためにボタンの貼り付けをしたフォームを用意してテキストボックスに文字を出力するだけのものを作ってみてよかったかも。それによってイベント処理の記述が少し理解できたので。

C#の勉強とともに数学も勉強していかないと3D処理はできないのかもしれないので。直線から復習してみることにしようかな。
次回はy=ax+bを考えてみることにしよ。

| | コメント (0) | トラックバック (0)

C#で最初のプロジェクト

graphicsのインスタンスをpictureboxに生成して、penとpointも作ってdrawlineするだけのものを作ろうとしたけど、pictureboxの変数が見れません。とエラーになってしまった。

応用的なものをいきなり作るんじゃなくて、地道に基礎から始めてみないと駄目かも。
まだまだ修行が必要そう。

でも、C#ってなんかよさそうな予感が。Microsoftの製品で初めて好きになれそうなものかもしれない。
ちょっと本気で取り組んでみたいと改めて思いました

| | コメント (0) | トラックバック (0)

C#のインストール

http://www.microsoft.com/japan/msdn/vstudio/express/
↑ここからC#のインストールを行う。入れてみないことには何も始まらないので、何はともあれC#のインストール。何も考えなくても素直にインストールが終了。インストールするとsilverlightのruntimeというのが入っていた。runtimeということは。。。このままでは開発には使用できないってことでしょうか?

C#だけの機能でもグラフィックスを作っていけるのかな?まずはC#のお勉強から手をつけてみることにしよう。

下記のサイトが検索できたので、このあたりの”読書”からじっくりと取り組むことにします。
C# によるプログラミング入門
連載  改訂版 C#入門
私がJavaからC#に乗り換えた10の理由
C#入門
C#を攻略しよう!
宇宙仮面のC#プログラミング
C# Tips

サイト作成者の皆様、お世話になります。

| | コメント (0) | トラックバック (0)

C#とsilverlightでグラフィックス?

C#ってどんな言語なんだろう?勉強するの難しいのでしょうか?あちらこちらのサイトを読んでいるとC#とsilverlightの組み合わせでやるとグラフィックスの勉強を進められそうな気がしたんだけど、これってとてつもなく難しい組み合わせなの?

とりあえず、C#に関してはvisual studio 2008 express editionっていうのをインストールすれば始められそうだけど、silverlightは使えない!?どう取り組んでいけばいいのだろう?

いきなりつまづいてしまいそうな感じだけど、めげずに。とにかくゆっくり進めてみます。
何分、各方面に初心者なので。

| | コメント (0) | トラックバック (0)

何から始めていいのやら

数学苦手でプログラミングのセンスがなくてどこまで理解していけるか分かりませんが、気持ちとしてはグラフィックス、しかも3D、できれば動きのあるものを作っていけるようになりたいな~っていう願望を持ってこのブログを始めてみたいと思います。
さて、何から。っていうのが正直なところ。プログラミング言語もどうしたらいいのか。勉強ってどっから手をつけていいのやら。できればWEBで、ブラウザでみれるものにしたいとは考えているのですけど。
なにかいい方法はないですかね。普通とっかかりってどんなところから始めているのでしょうか?
まずは、情報収集にいろいろなサイトを見てみることから始めるのがいいのかも。

还有我最近没有经常写中文文章。
我今年还是也得学外语。
边看韩剧边学韩语,对我来说最好!是因为我老婆爱看韩剧。看韩剧的机会特别多。
努力吧。

I'd like to watch American TV dramas, too. They're usually very exciting.
Too much violence sometimes, though. Too bad.

| | コメント (0) | トラックバック (0)