Draw a Buddhabrot fractal in C#

The Mandelbrot set iterates the function Z = Z2 + C in complex numbers for various values of C. It can be shown that, if the magnitude of Z ever grows beyond 2, then the function eventually heads towards infinity.

To draw a Mandelbrot set, you iterate the function and see how many iterations it takes for the function to reach magnitude 2. You then color the point C based on how many iterations it took. For example, if you use N colors and it took M iterations, then you could give the point color number M mod N.

To draw the Buddhabrot, you iterate Z = Z2 + C for values as usual, except you pick the values C randomly. If the function's magnitude exceeds 2 at some point, you go back and iterate the function again. This time you increment a count for each value Z that you come to before the magnitude exceeds 2. When you're done, you set a pixel's brightness to be 255 times its hit count divided by the largest hit count of any pixel.

To get the color map version, you set each point in the sequence based on the color of the initial value C. In this example, the program makes the points red if the distance from C to the origin is less than 1, green if the distance from C to the origin is less than Sqrt(2), and blue otherwise.

// Draw the Buddhabrot until stopped or
// we plot the desired number of points.
private void DrawBrot()
{
// Get parameters.
int wid = int.Parse(txtWidth.Text);
int hgt = int.Parse(txtHeight.Text);
int cut_r = int.Parse(txtRedCutoff.Text);
int cut_g = int.Parse(txtGreenCutoff.Text);
int cut_b = int.Parse(txtBlueCutoff.Text);
int stop_after = int.Parse(txtStopAfter.Text);
int draw_every = int.Parse(txtDrawEvery.Text);

if ((wid <= 0) || (hgt <= 0))
{
MessageBox.Show("Invalid parameter", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}

// Make hit count arrays.
int[,] hit_r = new int[wid, hgt];
int[,] hit_g = new int[wid, hgt];
int[,] hit_b = new int[wid, hgt];

// Make the bitmap.
m_Bitmap = new Bitmap(wid, hgt);
picCanvas.Image = m_Bitmap;
this.ClientSize = new Size(
picCanvas.Left + picCanvas.Width + 8,
System.Math.Max(
btnDraw.Top + btnDraw.Height,
picCanvas.Top + picCanvas.Height) + 8);
mnuFileSave.Enabled = true;

// Start drawing.
DateTime start_time = DateTime.Now;
DateTime stop_time;
TimeSpan elapsed;
m_Drawing = true;

// Build the hit counts.
double dx = (Wxmax - Wxmin) / hgt;
double dy = (Wymax - Wymin) / wid;
int max_r = 0, max_g = 0, max_b = 0, hits = 0, total_hits = 0;

while (total_hits < stop_after)
{
double cx = Wxmin + m_Rand.NextDouble() * (Wxmax - Wxmin);
double cy = Wymin + m_Rand.NextDouble() * (Wymax - Wymin);
double dd = cx * cx + cy * cy;
if (dd < 1)
{
DrawPoint(cx, cy, wid, hgt, dx, dy, ref max_r, hit_r, cut_r, ref hits);
}
else if (dd < 2)
{
DrawPoint(cx, cy, wid, hgt, dx, dy, ref max_g, hit_g, cut_g, ref hits);
}
else
{
DrawPoint(cx, cy, wid, hgt, dx, dy, ref max_b, hit_b, cut_b, ref hits);
}

if (hits >= draw_every)
{
total_hits += hits;
hits = 0;
DisplayBrot(wid, hgt, max_r, max_g, max_b, hit_r, hit_g, hit_b);

stop_time = DateTime.Now;
elapsed = stop_time.Subtract(start_time);
this.Text = elapsed.TotalSeconds.ToString("0.00") +
" sec, " + total_hits.ToString() + " hits";

Application.DoEvents();
if (!m_Drawing) break;
}
}
}

// Plot one point.
private void DrawPoint(double cx, double cy , int wid, int hgt, double dx , double dy , ref int max_hits, int[,] hits, int cutoff, ref int num_hits)
{
const double ESCAPING = 4;

// Pick C.
////Dim cx As Double = Wxmin + m_Rand.NextDouble() * (Wxmax - Wxmin)
////Dim cy As Double = Wymin + m_Rand.NextDouble() * (Wymax - Wymin)

// Zet Z0.
double x, xx, y, yy;
x = cx;
y = cy;
xx = x * x;
yy = y * y;

// Iterate.
for (int i = 1; i <= cutoff; i++)
{
y = 2 * x * y + cy;
x = xx - yy + cx;
xx = x * x;
yy = y * y;
if (xx + yy >= ESCAPING) break;
}

// See if we escaped.
if (xx + yy >= ESCAPING)
{
// Plot.
x = cx;
y = cy;
xx = x * x;
yy = y * y;

// Iterate.
for (int i = 1; i <= cutoff; i++)
{
int ix = (int)Math.Round((x - Wxmin) / dx);
int iy = (int)Math.Round((y - Wymin) / dy);
if ((ix >= 0) && (ix < hgt) && (iy >= 0) && (iy < wid))
{
hits[iy, ix] += 1;
if (max_hits < hits[iy, ix]) max_hits = hits[iy, ix];
}
else
{
break;
}

y = 2 * x * y + cy;
x = xx - yy + cx;
xx = x * x;
yy = y * y;
if (xx + yy >= ESCAPING) break;
}

num_hits += 1;
}
}

// Draw the current image.
private void DisplayBrot(int wid, int hgt, int max_r, int max_g, int max_b, int[,] hit_r, int[,] hit_g, int[,] hit_b)
{
Graphics gr = Graphics.FromImage(m_Bitmap);
gr.Clear(Color.Black);

double scale_r = 255 * 2.5 / max_r;
double scale_g = 255 * 2.5 / max_g;
double scale_b = 255 * 2.5 / max_b;

for (int y = 0; y < hgt; y++)
{
for (int x = 0; x < wid; x++)
{
int r = (int)Math.Round(hit_r[x, y] * scale_r);
if (r > 255) r = 255;
int g = (int)Math.Round(hit_g[x, y] * scale_g);
if (g > 255) g = 255;
int b = (int)Math.Round(hit_b[x, y] * scale_b);
if (b > 255) b = 255;

m_Bitmap.SetPixel(x, y, Color.FromArgb(255, r, g, b));
}
}

picCanvas.Refresh();
}

   

 

What did you think of this article?




Trackbacks
  • No trackbacks exist for this post.
Comments
  • No comments exist for this post.
Leave a comment

Submitted comments are subject to moderation before being displayed.

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.