練習がてら書いてみました。だいたい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;
}
}
}