Contour Lines of Mandelbrot

Mandelbrot using the Contour Lines utility from Reinder:
Metaball Contour Lines

Log in to post a comment.

// LL 2021

const turtle = new Turtle();

const detail_z = 8; // min=1, max=10, step=1
const detail_xy = 0.5; // min=0.01, max=1, step=0.01

const max_iterations = 25   // min = 1, max = 100, step = 1
const m_scale =  80         // min = 10, max = 1000, step = 0.01
const offset_x = 0.73        // min = -10, max = 10, step = 0.001
const offset_y = 0          // min = -10, max = 10, step = 0.001


function mandelbrot(x, y)
{
    var cr = x
    var ci = y
    var zr = 0
    var zi = 0
    var iterations = 0
    
    while (zr * zr + zi * zi < 4)
    {
        const new_zr = zr * zr - zi * zi + cr
        const new_zi = 2 * zr * zi + ci
        zr = new_zr
        zi = new_zi
        iterations += 1
        if (iterations >= max_iterations) break
    }
    
    return iterations
    
    //var l = Math.sqrt(zr * zr + zi * zi)
    //return iterations + 1. - Math.log(Math.log2(l))
    
    //return (iterations == max_iterations) ? max_iterations : 0
}

function zFunc(p)
{
    //return ((Math.sin(p[0]/10) + Math.cos(p[1]/10)) / 4 + 0.5) * (detail_z+1);
    
    const m_x = p[0] / m_scale - offset_x;
    const m_y = p[1] / m_scale - offset_y;

    const m = mandelbrot(m_x, m_y) / max_iterations;

    return m * (detail_z+1);
}

function walk(i) {
    const lines = ContourLines(i, (1/detail_xy)/(1+i), zFunc);
    lines.forEach(line => {
        turtle.jump(line[0]);
        turtle.goto(line[1]);
    });
    return i <= detail_z;
}

// Metaball Contour Lines. Created by Reinder Nijhoff 2020 - @reindernijhoff
// The MIT License
// https://turtletoy.net/turtle/104c4775c5
function ContourLines(z, step, zFunc) {
    const intersectSegmentZ = (z, v1, v2) => {
    	if (v1[2] === v2[2]) return false;
    	const t = (z - v1[2]) / (v2[2] - v1[2]);
    	if (t <= 0 || t > 1) return false;
    	return [v1[0]+(v2[0]-v1[0])*t, v1[1]+(v2[1]-v1[1])*t];
    }
    const intersectTriangleZ = (z, p1, p2, p3) => {
        const p = [];
    	const v1 = intersectSegmentZ(z, p1, p2);
    	const v2 = intersectSegmentZ(z, p2, p3);
    	const v3 = intersectSegmentZ(z, p3, p1);
    	if (v1 && v2) p.push([v1, v2]);
        if (v1 && v3) p.push([v1, v3]);
    	if (v2 && v3) p.push([v2, v3]);
		return p;
    }
	const result = [];
	for (let x = -100; x <= 100; x += step) {
    	for (let y = -100; y <= 100; y += step) {
			const corners = [[x, y], [x+step, y], [x+step, y+step], [x, y+step]];
			corners.forEach( c => c[2] = zFunc(c) );
			const c3 = [x+step/2, y+step/2, zFunc([x+step/2, y+step/2])];
			for (let i=0; i<4; i++) {
			    result.push(...intersectTriangleZ(z, corners[i], corners[(i+1) & 3], c3));
			}
		}
	}
	return result;
}