Draw a fractal generated by prime numbers in C#

fractal generated by prime numbers

This example shows how to draw a fractal generated by prime numbers. (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 from 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. (Then I got bored.)

The program uses the following variables to keep track of what it’s doing.

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

The Wid and Hgt constants give the size of the bitmap the program draws. The values XOff and YOff are used to offset drawing so the origin isn’t in the image’s upper left corner. (You can see that some of the points have X or Y coordinates less than 0.)

The Hits array records the number of times each point on the image is hit. CurrentPoint and CurrentPrime record the current location in the image and the current prime.

When you select the File menu’s Start command, 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’s text currently reads Start, the program starts calculating. It sets Running to true so it knows it’s running. It also 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 points 10,000 at a time. (Updating the display too often slows the program down a lot.)

The inner loop calls FindNextPrime to get the next prime number. It then uses a switch statement to decide which rule to use and it 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 updates a couple of 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 shown in the following code is relatively 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;
    }
}

By commenting out the two lines of code, I cheat a bit on the rules. The first commented line lets the program start at the prime number 2. The second line moves from the prime 2 to the prime 3. By commenting out those two lines, I make the program skip the prime 2 (because the program initially starts with value set to 1.) It’s a small change to the result and avoids two if tests for every call to FindNextPrime. (For instance, the picture shown above required 5 million calls to this method.)

The following 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.

// Build and display the image.
private void BuildImage()
{
    Bitmap bm = new Bitmap(Wid, Hgt);
    using (Graphics gr = Graphics.FromImage(bm))
    {
        // Clear.
        gr.Clear(Color.Black);

        // Find the largest hit value.
        var max_query =
            from int count in Hits
            select count;
        float max = (float)max_query.Max();

        // Plot the hits.
        for (int x = 0; x < Wid; x++)
            for (int y = 0; y < Hgt; y++)
                if (Hits[x, y] > 0)
                    bm.SetPixel(x, y,
                        MapRainbowColor(Hits[x, y], 1, max));

        // Draw the axes.
        gr.DrawLine(Pens.Blue, XOff, 0, XOff, Hgt);
        gr.DrawLine(Pens.Blue, 0, YOff, Wid, YOff);
    }

    // Display the result.
    picFractal.Image = bm;
}

This method makes a bitmap of the required size and an associated Graphics object. After clearing the bitmap, it uses a LINQ query to get the largest value in the Hits array max. It then loops through the entries in the Hits array and gives each pixel a value that maps its Hits count into the range 1 to max. (For information on the MapRainbowColor method, see Map numeric values to colors in a rainbow in C#.)

After setting the pixels’ colors, the method draws the X and Y axes and displays the result.

The program’s File menu also includes a Save As command that saves the image into a file. Download the example to see how it works.


Download Example   Follow me on Twitter   RSS feed




This entry was posted in algorithms, fractals, graphics, mathematics. Bookmark the permalink.

One Response to Draw a fractal generated by prime numbers in C#

  1. Pingback: Draw a fractal curve generated by prime numbers in C# -

Leave a Reply

Your email address will not be published. Required fields are marked *