The Mandelbrot and Julia set is calculated by iterating the equation
zn+1 = zn2 + c
where i = √-1 and x and y are the horizontal and vertical position of the location within the fractal whose color you wish to calculate.
The calculation is repeated until |zn| > 2, and colors are assigned to each location depending on the number of iterations required until this condition is met.
A maximum number of iterations needs to be specified, because in some parts of the fractal, the iteration sequence above will never end. This is true in the 'lake' area in the center of the fractal.
The starting conditions are
Z0 = 0
and
c = x + iy
The starting conditions are
Z0 = x + iy
and
c = x0 + iy0
x0 and y0 are two numerical constants which define a two-dimensional set of different Julia sets.
left: -3.834738617201
right: 3.834738617201
top: -2.000000000000
botton: 2.000000000000
Julia Set
Mandelbrot Set
From Simple to Complex
The mandelbrot Fractal Explained
mandelbrot online viewer
optimize mandelbrot set
Plotting algorithms for the Mandelbrot set
2018-2019-JonckheereLSde
mandelbrot_compute
high_level_design
Mandelbrot set web optimizing
Mandelbrot set performance
increase performance creating mandelbrot set in python
optimising rendering the mandelbrot set
Fract-ol
Fabien fractol
Fractals are typically not self-similar
p5.js julia set
Mandelbrot Locations
z2 = (x + iy)(x + iy) = x2 + xyi + xyi - y2 = x2 - y2 + 2xyi
while iter < max_iter
x = x<sup>2</sup> - y<sup>2</sup>
y = 2xyi
if x<sup>2</sup> + y<sup>2</sup> > 2
break
color = iter/max_iter
Mandelbrot JavaScript implementation with p5.js:
var minval = -0.5;
var maxval = 0.5;
var minSlider;
var maxSlider;
function setup() {
createCanvas(400, 400);
pixelDensity(1);
minSlider = createSlider(-2.5, 0, -2.5, 0.01);
maxSlider = createSlider(0, 2.5, 2.5, 0.01);
}
function draw()
{
var max_iter = 50;
loadPixels();
for (var x = 0; x < width; x++)
{
for (var y = 0; y < height; y++)
{
var a = map(x, 0, width, minSlider.value(), maxSlider.value());
var b = map(y, 0, height, minSlider.value(), maxSlider.value());
var ca = a;
var cb = b;
var n = 0;
while (n < max_iter)
{
var aa = a*a - b*b;
var bb = 2 * a * b;
a = aa + ca;
b = bb + cb;
if (abs(a + b) > 16)
{
break;
}
n++;
}
var bright = map(n, 0, max_iter, 0, 1);
bright = map(sqrt(bright), 0, 1, 0, 255);
if (n == max_iter)
{
bright = 0;
}
var pix = (x + y * width) * 4;
pixels[pix + 0] = bright;
pixels[pix + 1] = bright;
pixels[pix + 2] = bright;
pixels[pix + 3] = 255;
}
}
updatePixels();
}
for the julia set just modify the lines from
...
a = aa + ca;
b = bb + cb;
...
to
...
a = aa -0.70176;
b = bb -0.3842;
...
Julia set from mouse position mapped to x[-2, 2] y[-2, 2]:
var minval = -0.5;
var maxval = 0.5;
var minSlider;
var maxSlider;
function setup() {
createCanvas(400, 400);
pixelDensity(1);
minSlider = createSlider(-2, 0, -2, 0.01);
maxSlider = createSlider(0, 2, 2, 0.01);
}
function draw()
{
var max_iter = 50;
loadPixels();
for (var x = 0; x < width; x++)
{
for (var y = 0; y < height; y++)
{
var a = map(x, 0, width, minSlider.value(), maxSlider.value());
var b = map(y, 0, height, minSlider.value(), maxSlider.value());
var ca = map(mouseX, 0, width, -2, 2);
var cb = map(mouseY, 0, height, -2, 2);
var n = 0;
while (n < max_iter)
{
var aa = a*a;
var bb = b*b;
if (aa + bb > 4)
{
break;
}
var twoab = 2.0 * a * b;
a = aa - bb + ca;
b = twoab + cb;
n++;
}
var bright = map(n, 0, max_iter, 0, 1);
bright = map(sqrt(bright), 0, 1, 0, 255);
if (n == max_iter)
{
bright = 0;
}
var pix = (x + y * width) * 4;
pixels[pix + 0] = bright;
pixels[pix + 1] = bright;
pixels[pix + 2] = bright;
pixels[pix + 3] = 255;
}
}
updatePixels();
}
implementation with zoom and movement on plane
function setup()
{
createCanvas(640, 360);
noStroke();
colorMode(HSB);
drawBrot();
}
let cenX = 0;
let cenY = 0;
let mscale = 1;
let maxiter = 1000;
function draw()
{
let redraw = false;
if (keyIsDown(LEFT_ARROW))
{
cenX -= 0.5 * 1/mscale;
redraw = true;
}
if (keyIsDown(RIGHT_ARROW))
{
cenX += 0.5 * 1/mscale;
redraw = true;
}
if (keyIsDown(UP_ARROW))
{
cenY -= 0.5 * 1/mscale;
redraw = true;
}
if (keyIsDown(DOWN_ARROW))
{
cenY += 0.5 * 1/mscale;
redraw = true;
}
if (keyIsDown(107) || keyIsDown(187))
{
mscale += mscale*0.5;
redraw = true;
}
if (keyIsDown(109) || keyIsDown(189))
{
mscale -= mscale*0.5;
redraw = true;
}
if (redraw)
{
drawBrot();
}
}
function drawBrot()
{
for (let x = 0; x < width; x++)
{
for (let y = 0; y < height; y++)
{
let c = pixelToPoint(x, y);
let result = calculatePoint(c);
if (result.isIn)
{
set(x, y, color(0));
}
else if (result.i > 1)
{
set(x, y, color(
150 + 200 - pow(result.i/maxiter, 0.5) * 200 % 255, 80, 100
));
}
else
set(x, y, color(50));
}
}
updatePixels();
}
function pixelToPoint(x, y)
{
let p = createVector(
(x - width/2) * (2/width) * (16/(9*mscale)) + cenX,
(y - height/2) * (2/height) * (1/mscale) + cenY
);
return p;
}
function calculatePoint(c)
{
let z0 = createVector(0, 0);
let i = 0;
let bounds = 2;
let isIn = true;
while (i < maxiter && isIn)
{
z0 = createVector(
z0.x*z0.x - z0.y*z0.y + c.x,
2*z0.x*z0.y + c.y
);
i++;
if (z0.mag() > bounds)
isIn = false;
}
return {
'i': i,
'isIn': isIn
};
}