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: Burning Ship Fractal

Author: Mitch Richling
Updated: 2022-12-10

horizon_50.png

Table of Contents

1. Introduction

The Burning Ship Fractal is a bit of a Mandelbrot'alike in that its generating function is a minor modification of the one used for the Mandelbrot Set:

\[\begin{eqnarray} f(z) & = & z^2+c & \,\,\,\,\,\,\mathrm{Mandelbrot} \\ f(z) & = & \left(\vert\Re(z)\vert + i\cdot\vert\Im(z)\vert\right)^2 +c & \,\,\,\,\,\,\mathrm{Burning\,\,Ship} \\ \end{eqnarray}\]

Granted, these two functions are not visually similar in the standard form written above; however, we can remedy that by rewriting the equations using explicit real and imaginary parts. We use \(x+yi\) instead of \(z\) for the following two equations:

\[\begin{eqnarray} f(z) & = & ( & \,x & + & \,y & i & )^2 & + & c & \,\,\,\,\,\,\mathrm{Mandelbrot} \\ f(z) & = & ( & \vert x\vert & + & \vert y\vert & i & )^2 & + & c & \,\,\,\,\,\,\mathrm{Burning\,\,Ship} \\ \end{eqnarray}\]

So the equations are identical except for the signs of the real and imaginary parts – i.e. at each step in the Burning Ship Fractal we make the parts positive.

2. Algorithms

We render the Burning Ship Fractal using the \(L\) function just like we did with the Mandelbrot Set. The general idea is to map an array of pixels making up the raster image to a rectangular region of the complex plane, and color each pixel of the image based upon a color scale for the computed value of the \(L\) function. Coding up this idea leads to the following C++ program:

#include "ramCanvas.hpp"

typedef mjr::color3c8b::csCC_tpl<mjr::color3c8b::cornerColorEnum::BLUE, 
                                 mjr::color3c8b::cornerColorEnum::RED, 
                                 mjr::color3c8b::cornerColorEnum::YELLOW, 
                                 mjr::color3c8b::cornerColorEnum::WHITE>  csCCbs;

int main(void) {
  std::chrono::time_point<std::chrono::system_clock> startTime = std::chrono::system_clock::now();
  const int NUMITR = 1024; 
  const int MAXMAG = 15; 
  const int IMGSIZ = 7680/4;
  //mjr::ramCanvas3c8b escRamCanvas(IMGSIZ, IMGSIZ, -1.5, 2.7, -1.25, 2.49);                 // Entire fractal
  //mjr::ramCanvas3c8b escRamCanvas(IMGSIZ, IMGSIZ, 1.6, 1.9, -0.089, 0.2);                  // The horizon zoom
  mjr::ramCanvas3c8b escRamCanvas(IMGSIZ, IMGSIZ, 1.715, 1.795, -0.022, 0.086);              // The classic zoom
  //mjr::ramCanvas3c8b escRamCanvas(IMGSIZ, IMGSIZ, 1.802, 1.80287, -0.002, 0.002);          // Columns to heaven
  //mjr::ramCanvas3c8b escRamCanvas(IMGSIZ, IMGSIZ, -0.3743, -0.3735, -0.0876, -0.0866);     // Deep zoom.  BATS!

  for(int y=0;y<escRamCanvas.getNumPixY();y++) {
    for(int x=0;x<escRamCanvas.getNumPixX();x++) {
      double cx = escRamCanvas.int2realX(x), cy = escRamCanvas.int2realY(y);
      double zx = 0.0, zy = 0.0;
      double t;
      int count = 0;
      while(((zx*zx+zy*zy)<MAXMAG) && (count<=NUMITR)) {
        count++;
        t  = zx*zx - zy*zy     - cx;
        zy = std::abs(2*zx*zy) - cy;
        zx = t;
      }
      if(count < NUMITR) 
        escRamCanvas.drawPoint(x, y, csCCbs::c(static_cast<mjr::ramCanvas3c8b::csIntType>(count*10)));
    }
  }
  // Escape Time Coloring
  escRamCanvas.writeTIFFfile("BurningShip.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 this picture:

BurningShip_03_50.png

4. 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.