Mitch Richling: Orbit Traps
Author: | Mitch Richling |
Updated: | 2024-10-31 |
Table of Contents
1. Introduction
The classic way to render a Mandelbrot Set is to use the \(L\) function. Here we are going to use something called an "orbit trap". THe idea is to do the same iterations we do when using the \(L\) function, but keep track of how close the orbit for each point gets to the "trap". For each point we use the minimimal distance between the trap and the orbit for that point for the color. Ususally brighter colors for closer orbits. Probably the most famous orbit trap is the X & Y axes. This idea popularized by Pickover, and the resulting renderings are called "Pickover Stalks".
2. Pickover Stalks
#include "ramCanvas.hpp" typedef mjr::ramCanvas3c8b::colorType ct; int main(void) { std::chrono::time_point<std::chrono::system_clock> startTime = std::chrono::system_clock::now(); const int IMGSIZ = 7680; const int MAXITR = 1024; const double MAXZSQ = 1008.0; mjr::ramCanvas3c8b theRamCanvas(IMGSIZ, IMGSIZ, -2.2, 0.8, -1.5, 1.5); # 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.int2real(x, y); std::complex<double> z(0.0, 0.0); double minX = theRamCanvas.getCanvasWidD(); double minY = theRamCanvas.getCanvasWidD(); int count = 0; while((std::norm(z)<MAXZSQ) && (count<=MAXITR)) { z=std::pow(z, 2) + c; if (std::abs(std::real(z)) < minX) minX = std::abs(std::real(z)); if (std::abs(std::imag(z)) < minY) minY = std::abs(std::imag(z)); count++; } if(count < MAXITR) theRamCanvas.drawPoint(x, y, ct::csCCfractalYB::c(static_cast<ct::csIntType>(std::log(1+std::min(minX, minY))*500))); } } theRamCanvas.writeTIFFfile("mandelbrot_pickover.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 image:
3. Mandelbrot Lemniscates
The Mandelbrot Set is ringed by the "Mandelbrot Curves" or "Mandelbrot Lemniscates" – an infinite family of continuous, closed curves that converge to the Mandelbrot Set. We can use these curves as orbit traps:
#include "ramCanvas.hpp" typedef mjr::ramCanvas3c8b::colorType ct; double lp(std::complex<double> z, int n) { std::complex<double> lpv(0.0, 0.0); for(int i=0; i<n; i++) lpv = std::pow(lpv, 2) + z; return std::abs(lpv) - 2; } int main(void) { std::chrono::time_point<std::chrono::system_clock> startTime = std::chrono::system_clock::now(); const int IMGSIZ = 7680; const int MAXITR = 1024; const double MAXZSQ = 4.0; const int NUMFRM = 10; # pragma omp parallel for schedule(static,1) for(int frame=1;frame<=NUMFRM;frame++) { # pragma omp critical std::cout << "Frame " << frame << " of " << NUMFRM << std::endl; mjr::ramCanvas3c8b theRamCanvas(IMGSIZ, IMGSIZ, -2.2, 0.8, -1.5, 1.5); for(int y=0;y<theRamCanvas.getNumPixY();y++) { for(int x=0;x<theRamCanvas.getNumPixX();x++) { std::complex<double> c = theRamCanvas.int2real(x, y); std::complex<double> z(0.0, 0.0); double minDval = theRamCanvas.getCanvasWidD(); double minDsgn = 0; int count = 0; while((std::norm(z)<MAXZSQ) && (count<=MAXITR)) { z=std::pow(z, 2) + c; double ld = lp(z, frame); if (std::abs(ld) < minDval) { minDval = std::abs(ld); minDsgn = (ld > 0 ? 1 : -1); } count++; } if(count < MAXITR) { ct::csIntType csIdx = static_cast<ct::csIntType>(std::log(1+minDval)*100); if (minDsgn > 0) theRamCanvas.drawPoint(x, y, ct::csCCfractalYB::c(csIdx)); else theRamCanvas.drawPoint(x, y, ct::csCCfractalYR::c(csIdx)); } } } theRamCanvas.writeTIFFfile("mandelbrot_ltrap_" + mjr::math::str::fmt_int(frame, 2, '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 all of the images in the gallery below.
These may be transformed into a movie: