Jump to my Home Page Send me a message Check out stuff on GitHub Check out my photography on Instagram Check out my profile on LinkedIn Check out my profile on reddit Check me out on Facebook

Mitch Richling: Mandelbrot Wave

Author: Mitch Richling
Updated: 2024-10-31

Table of Contents

1. Introduction

Iterate \(f(x)=z^5+a\cdot z+c\) as one would \(f(z)=z^2+c\) to render a Mandelbrot Set. Vary the parameter \(a\) by moving it around the unit circle, and drop out an image for each \(a\).

2. Algorithm & Code

#include "ramCanvas.hpp"

typedef mjr::ramCanvas3c8b::colorType ct;
typedef ct::csIntType cit;

int main(void) {
  std::chrono::time_point<std::chrono::system_clock> startTime = std::chrono::system_clock::now();
  const int    NUMITR = 255;
  const int    NUMFRM = 24*16;      // Full circle animation
  //const int    NUMFRM = 24*4;     // Wave animation
  const int    IMXSIZ = 7680/2;
  const int    IMYSIZ = 7680/2;
  const int    MAXZSQ = 10;
  const double ANGMIN = 0.0;                 // Full circle animation
  const double ANGMAX = std::numbers::pi*2;  // Full circle animation
  // const double ANGMIN = 3.04341788317;    // Wave animation
  // const double ANGMAX = 3.23976742401;    // Wave animation

  for(int frame=0; frame<NUMFRM; frame++) {
    mjr::ramCanvas3c8b theRamCanvas(IMXSIZ, IMYSIZ, -1.5, 1.5, -1.5, 1.5);    // Full circle animation
    // mjr::ramCanvas3c8b theRamCanvas(IMXSIZ, IMYSIZ, -0.7, 0.1, -0.7, 0.1); // Wave animation
    theRamCanvas.clrCanvasToBlack();
    std::cout << "Frame: " << frame << " of " << NUMFRM << std::endl;
    double angle = frame*(ANGMAX-ANGMIN)/NUMFRM+ANGMIN;    
    std::complex<double> a(std::cos(angle), std::sin(angle));
#   pragma omp parallel for schedule(static,1)
    for(int y=0;y<theRamCanvas.getNumPixY();y++) {
      for(int x=0;x<theRamCanvas.getNumPixX();x++) {
        std::complex<double> c(theRamCanvas.int2realX(x), theRamCanvas.int2realY(y));
        std::complex<double> z(0.0, 0.0);
        int count = 0; 
        while((std::norm(z)<MAXZSQ) && (count<=NUMITR)) {
          z = std::pow(z, 5) +  a * z + c;
          count++;
        }
        if(count < NUMITR)
          theRamCanvas.drawPoint(x, y, ct::csCColdeFireRamp::c(static_cast<ct::csIntType>(count*20)));
      }
    }
    theRamCanvas.scaleDownMean(8);   // Another good choice: theRamCanvas.scaleDownMax(8); 
    theRamCanvas.writeTIFFfile("mandelbrot_wave_" + mjr::math::str::fmt_int(frame, 3, '0') + ".tiff");
  }
  std::chrono::duration<double> runTime = std::chrono::system_clock::now() - startTime;
  std::cout << "Total Runtime " << runTime.count() << " sec" << std::endl;
}

The above program will generate frames for a movie which may be rendered into a GIF:

mandelbrot_morph01_mean_50.gif

If we use the scaleDownMax option, then we get the following:

mandelbrot_morph01_max_50.gif

Lastly, if we use the "wave" code, we get the following:

mandelbrot_morph01_wavy_50.gif

3. References

Check out the fractals section of my reading list.

All the code used to generate everything on this page may be found on github.