C#で(PictureBoxに)マンデルブロ集合を描く

PictureBoxを使うとOnPaintイベントハンドラをoverrideしなくても描画できるみたいだった。Formのコンストラクタの中で描画したらRefresh()メソッドを呼ばなくてもImageが表示されていた(Formを作成した後にImageを更新した場合にはRefreshが必要だった)。ついでに今回は自作の複素数クラスではなくNumericsのComplexを使ったのでコンパイルにはNumerics.dllを参照する必要がある。

csc  /reference:System.Numerics.dll  ファイル名

実数部はプロパティRealで、虚数部はImaginaryで取得できる。発散の判断をするために原点からの距離を知りたいのでComplex.Abs()を使用した。理論的なことは知らないが絶対値が一度2を超えてしまうと収束しないらしいので。
※#タグが使えるようになったというのでC#のタグをつけまくろうかしらん。#C#

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;
using System.Drawing.Imaging;
using System.Numerics;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        Image image;
        int width = 800;
        int height = 500;
        public Complex Pixel2Complex(int i, int j, Complex c, double unit)
        {
            double a, b;
            a = c.Real + unit * i;
            b = c.Imaginary - unit * j;
            return new Complex(a, b);
        }
        void DrawFractal()
        {
            Complex leftUpPosition = new Complex(-2.35, 1.25);
            double pixelUnit = 0.005;
            int iteration = 200;
            Complex[] z = new Complex[iteration + 1];
            Complex zc;
            Brush[] palet =
            {
            new SolidBrush(Color.Black),                   // 0
            new SolidBrush(Color.Blue),                    // 1
            new SolidBrush(Color.FromArgb(140, 255, 255)), // 2
            new SolidBrush(Color.FromArgb(255, 170, 170)), // 3
            new SolidBrush(Color.Red),                     // 4
            new SolidBrush(Color.Purple),                  // 5
            new SolidBrush(Color.Yellow),                  // 6
            new SolidBrush(Color.YellowGreen),             // 7
            new SolidBrush(Color.FromArgb(255, 0, 170)),   // 8
            new SolidBrush(Color.SeaGreen),                // 9
            new SolidBrush(Color.FromArgb(255, 200, 0)),   // 10
            new SolidBrush(Color.Silver),                  // 11
            new SolidBrush(Color.FromArgb(255, 160, 0)),   // 12
            new SolidBrush(Color.SpringGreen),             // 13
            new SolidBrush(Color.FromArgb(255, 200, 255)), // 14
            new SolidBrush(Color.FromArgb(0, 170, 170)),   // 15
            new SolidBrush(Color.FromArgb(0, 250, 0)),     // 16
            new SolidBrush(Color.FromArgb(0, 200, 0)),     // 17
            new SolidBrush(Color.FromArgb(0, 150, 0)),     // 18
            new SolidBrush(Color.FromArgb(0, 100, 0)),     // 19
            new SolidBrush(Color.FromArgb(0, 50, 0)),      // 20
            new SolidBrush(Color.White)                    // 21
            };

            int MaxCycle = palet.Length - 1;

            Graphics g = Graphics.FromImage(image);
            int imax = image.Width;
            int jmax = image.Height;
            double n_progress = imax / 100.0;
            double s;
            int i;
            int j;
            int k;
            for (i = 0; i < imax; i++)
            {
                for (j = 0; j < jmax; j++)
                {
                    z[0] = Pixel2Complex(i, j, leftUpPosition, pixelUnit);
                    zc = z[0];

                    for (k = 0; k < iteration; k++)
                    {
                        z[k + 1] = z[k] * z[k] + zc;

                        s = Complex.Abs(z[k]);
                        if (s > 2.0)
                        {
                            g.FillRectangle(palet[0], i, j, 1, 1);
                            break;
                        }
                    }
                    if (k == iteration)
                    {
                        int n;
                        for (n = 1; n < MaxCycle; n++)
                        {
                            s = Complex.Abs(z[iteration] - z[iteration - n]);
                            if (s < pixelUnit)
                            {
                                g.FillRectangle(palet[n], i, j, 1, 1);
                                break;
                            }
                        }
                        if (n == MaxCycle)
                        {
                            g.FillRectangle(palet[MaxCycle], i, j, 1, 1);
                        }
                    }
                }
            }
        }
        public Form1()
        {
            InitializeComponent();
            image = new Bitmap(width, height);
            this.pictureBox1.Image = image;
            DrawFractal();
        }
    }
}