練習がてら書いてみました。だいたい3時間。
マンデルブロ集合たん綺麗だよ'`ァ,、ァ(*´Д`*)'`ァ,、ァ
マンデルブロ集合は複素数を扱うので、複素数クラスを探したのですが、公式だと.Net Framework4からしかComplexクラスが入ってないので、しょうがないので自分で書きました。ぐぐっても複素数クラスをジェネリック?を使ったりして「如何に上手く作るか」説明してあるサイトはあったのですが、初心者向けの簡単なクラスは見つかりませんでした…(´・ω・`)
正直こういうところは動作が確実な、そして俺でも読める(重要)ライブラリを拝借するのが一番楽で確実と思うですよ?
コードの解説。
1) 色
Wikiには、マンデルブロ集合の周りも発散の速度で色分けしてあります。よって、発散まで(Infinityがtrue)のループ回数で判定してますが、結構シビアです。大抵は殆ど直ぐに発散します。集合の境界あたりは発散までの回数が急激に変わるみたいです。
2) delegate
マルチスレッドじゃないと重くてやってらんねーので、UIを弄るときはマルチスレッド特有の処理が必要です。ここらへん素人なので他のサイトをあたってくだしあ
3) ループ回数
今のところ10000回です。どっかのサイトに10000回って書いてあるのを昔見た気がする、それが全て。
4) 複素数クラス
長くなったので別の投稿にするかもですね。
Complexとある所は全て自分の複素数クラスです。
5) UI
WindowSize : width 480, height 480
Button1 : これを押すとDrawします。
Label1 : ループが何回目かを表示します。
えっと、参考にしてください。
ええと、C#について幾つか今日はじめて知ったことを。
(´ー`)oO(この言語進化するの早すぎだろ…)
1) checked, unchecked
これを書くとOverflowがごにょごにょ こちらのリンク先に詳しい説明がありました。
2) doubleはOverflow Exceptionを投げない
これも上のリンク先に(ry
3) Double.IsPositiveInfinity(), Double.IsNaN()
doubleがOverflowするとInfinityという値を取ります。ここらへんはMSDNのDoubleに詳しく書いてあります。で、それの判定はDouble.IsPositiveInfinity(double d)です。NaNについても同様。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; //Threadクラスで必要 namespace WindowsFormsApplication43 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Thread t = new Thread( delegate() { for (int x = 0; x < 480; x++) { //中央は(240, 240) double __x = x; double _x = (__x - 240.0d) / 240.0d; for (int y = 0; y < 480; y++) { double __y = y; double _y = (__y - 240.0d) / 240.0d; Complex v = new Complex(_x, _y); //発散しない if (IsDivergence(v) == -1) { if(this.IsHandleCreated) { this.Invoke( (MethodInvoker)delegate() { Graphics g = this.CreateGraphics(); g.FillRectangle(Brushes.Black, x, y, 1, 1); g.Flush(); g.Dispose(); label1.Text = x.ToString(); label1.Show(); }); } } //早い発散 else if (IsDivergence(v) > 0 && IsDivergence(v) < 40) { if (this.IsHandleCreated) { this.Invoke( (MethodInvoker)delegate() { Graphics g = this.CreateGraphics(); g.FillRectangle(Brushes.Aqua, x, y, 1, 1); g.Flush(); g.Dispose(); label1.Text = x.ToString(); label1.Show(); }); } } //中くらいの発散速度 else if (IsDivergence(v) >= 40 && IsDivergence(v) < 70) { if (this.IsHandleCreated) { this.Invoke( (MethodInvoker)delegate() { Graphics g = this.CreateGraphics(); g.FillRectangle(Brushes.Blue, x, y, 1, 1); g.Flush(); g.Dispose(); label1.Text = x.ToString(); label1.Show(); }); } } //遅い発散 else { if (this.IsHandleCreated) { this.Invoke( (MethodInvoker)delegate() { Graphics g = this.CreateGraphics(); g.FillRectangle(Brushes.RoyalBlue, x, y, 1, 1); g.Flush(); g.Dispose(); label1.Text = x.ToString(); label1.Show(); }); } } } } }); t.Start(); } private int IsDivergence(Complex initval) { //初期値 Complex z = new Complex(0.0d, 0.0d); //z0 = 0 for (int i = 0; i < 10000; i++) { z = z * z + initval; //catch (OverflowException ex) //{ //発散 // return true; //} if (Double.IsPositiveInfinity(z.re) || Double.IsPositiveInfinity(z.im)) { //発散 return i; } else if (Double.IsNaN(z.re) || Double.IsNaN(z.im)) { //発散 return i; } } //発散してない return -1; } } }