Draw a fractal that is generated by applying rules to prime numbers in C#

(For information and discussion of this idea, see The prime-explosion Bergot graph at The Prime Puzzles & Problem Connection.)

The program draws the image by following these rules:

  1. Start at the point (0, 0) corresponding to the prime 2.
  2. Go to the next prime.
  3. If the prime is 5, ignore it. Otherwise the prime has one of these forms:
    1. 5n + 1: Move up 1 pixel
    2. 5n + 2: Move right 1 pixel
    3. 5n + 3: Move down 1 pixel
    4. 5n + 4: Move left 1 pixel
  4. Repeat at step 2 until bored.

Periodically the program makes a bitmap where the colors of the pixels indicate the number of times each point was visited. The image shown here was generated by plotting 4 million points.

The form's Load event handler creates a Hits array to record the number of times a pixel is visited.

private const int Wid = 800;
private const int Hgt = 800;
private const int XOff = 150;
private const int YOff = 200;
private int[,] Hits;
private Point CurrentPoint;
private long CurrentPrime;

// Initialize data structures.
private void Form1_Load(object sender, EventArgs e)
{
Hits = new int[Wid, Hgt];
CurrentPoint = new Point(0, 0);
CurrentPrime = 1;
}

When you select the File menu's Start item, the following code executes.

// Start or stop.
private bool Running = false;
private void mnuFileStart_Click(object sender, EventArgs e)
{
if (mnuFileStart.Text == "&Start")
{
// Start.
Running = true;
mnuFileStart.Text = "&Stop";

DrawFractal();

// Clean up after we finish running.
mnuFileStart.Enabled = true;
mnuFileStart.Text = "&Start";
}
else
{
// Stop.
Running = false;
mnuFileStart.Enabled = false;
}
}

If the menu item currently says Start, the program starts calculating. It sets Running to true so it knows it's running, changes the menu item's text to Stop, and calls the DrawFractal method. After that method returns, the code enables the menu item and resets its text to Start.

If the menu item currently doesn't say Start, then the program is currently drawing the fractal. In that case the code sets Running to false and disables the menu item.

The following code shows the DrawFractal method.

// Add points to the fractal.
private int NumPoints = 0;
private void DrawFractal()
{
const int points_per_loop = 10000;
while (Running)
{
// Generate a bunch of points.
for (int i = 0; i < points_per_loop; i++)
{
// Find the next prime.
CurrentPrime = FindNextPrime(CurrentPrime);

// See which kind of prime it is.
switch (CurrentPrime % 5)
{
case 1:
CurrentPoint.Y--;
break;
case 2:
CurrentPoint.X++;
break;
case 3:
CurrentPoint.Y++;
break;
case 4:
CurrentPoint.X--;
break;
}

// Record the hit.
int ix = CurrentPoint.X + XOff;
int iy = CurrentPoint.Y + YOff;
if (ix >= 0 && iy >= 0 && ix < Wid && iy < Hgt)
{
Hits[ix, iy]++;
}
}

// Build the image.
BuildImage();

// Display the point count.
NumPoints += points_per_loop;
lblNumPoints.Text = NumPoints.ToString();
lblPrime.Text = CurrentPrime.ToString();

// Process button clicks if there were any.
Application.DoEvents();
}
}

This code enters a loop that executes as long as Running is true. Inside that loop, the code executes another loop to plot a bunch of points.

The inner loop calls FindNextPrime to get the next prime number. It then uses a switch statement to decide which rule to use and updates the current point accordingly. It then updates the new point's Hits count.

After the inner loop finishes, the program calls BuildImage to display the fractal so far. It then updates a couple labels and calls Application.DoEvents to allow the program to process Windows events. That allows the Start/Stop menu item's event handler to execute if the user selected the item to stop running. That event handler sets Running to false so the outer loop stops.

The FindNextPrime method is straightforward.

// Find the next prime after this one.
private long FindNextPrime(long value)
{
// Cheat a little for speed.
//if (value == 1) return 2;
//if (value == 2) return 3;
for (long i = value + 2; ; i += 2)
{
if (IsPrime(i)) return i;
}
}

The BuildImage method is also straightforward. It creates a bitmap and uses the Hits array to set its pixel values. See the code for the details.

The only non-trivial part of this method is the fact that it uses the MapRainbowColor method to assign colors to the pixels based on their hit values. For a description of this method, see Map numeric values to colors in a rainbow in C#.

Finally, the File menu's Save command saves the current picture's image in a file. It calls the SaveBitmapUsingExtension method to save the file using an appropriate file form. For information on that method, see Write a method that saves images in an appropriate format depending on the file name's extension in C#.
// Save the file.
private void mnuFileSave_Click(object sender, EventArgs e)
{
if (sfdFractal.ShowDialog() == DialogResult.OK)
{
Bitmap bm = picFractal.Image as Bitmap;
SaveBitmapUsingExtension(bm, sfdFractal.FileName);
}
}

   

 

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.