Skip to content

Commit

Permalink
- add more color schemes and fractal types
Browse files Browse the repository at this point in the history
  • Loading branch information
TobiasMue91 committed Sep 1, 2024
1 parent 2573f9e commit 1eb458a
Showing 1 changed file with 190 additions and 37 deletions.
227 changes: 190 additions & 37 deletions tools/fractal_viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,37 @@
<canvas id="fractalCanvas" class="w-full rounded-lg shadow-inner mb-4 cursor-move"></canvas>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div><label class="block text-gray-700 dark:text-gray-300 text-sm font-bold mb-2" for="fractalType">Fractal
Type:</label><select id="fractalType"
class="w-full p-2 border rounded dark:bg-gray-700 dark:text-white">
<option value="mandelbrot">Mandelbrot Set</option>
<option value="julia">Julia Set</option>
<option value="burningShip">Burning Ship</option>
<option value="mandelbox">Mandelbox</option>
</select></div>
Type:</label>
<select id="fractalType" class="w-full p-2 border rounded dark:bg-gray-700 dark:text-white">
<option value="mandelbrot">Mandelbrot Set</option>
<option value="julia">Julia Set</option>
<option value="burningShip">Burning Ship</option>
<option value="mandelbox">Mandelbox</option>
<option value="sierpinskiCarpet">Sierpinski Carpet</option>
<option value="lyapunov">Lyapunov Fractal</option>
<option value="phoenix">Phoenix Fractal</option>
<option value="mandelbox3DSlice">Mandelbox 3D Slice</option>
<option value="newtonFractal">Newton Fractal</option>
</select>
</div>
<div><label class="block text-gray-700 dark:text-gray-300 text-sm font-bold mb-2" for="maxIterations">Max
Iterations: <span id="iterationValue">100</span></label><input type="range" id="maxIterations" min="50"
max="1000" value="100" class="w-full">
</div>
<div><label class="block text-gray-700 dark:text-gray-300 text-sm font-bold mb-2" for="colorScheme">Color
Scheme:</label><select id="colorScheme"
class="w-full p-2 border rounded dark:bg-gray-700 dark:text-white">
Scheme:</label><select id="colorScheme" class="w-full p-2 border rounded dark:bg-gray-700 dark:text-white">
<option value="default">Default</option>
<option value="rainbow">Rainbow</option>
<option value="fire">Fire</option>
<option value="ocean">Ocean</option>
<option value="psychedelic">Psychedelic</option>
<option value="pastel">Pastel</option>
<option value="neon">Neon</option>
<option value="grayscale">Grayscale</option>
<option value="autumn">Autumn</option>
<option value="electric">Electric</option>
<option value="cosmic">Cosmic</option>
<option value="vintage">Vintage</option>
</select></div>
<div><label class="block text-gray-700 dark:text-gray-300 text-sm font-bold mb-2" for="juliaReal">Julia
Real:</label><input type="number" id="juliaReal" value="-0.7" step="0.1"
Expand Down Expand Up @@ -95,20 +107,51 @@
const type = fractalType.value;
const jr = parseFloat(juliaReal.value);
const ji = parseFloat(juliaImag.value);

for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
const zx = 1.5 * (x - width / 2) / (0.5 * zoomLevel * width) + centerX;
const zy = (y - height / 2) / (0.5 * zoomLevel * height) + centerY;
let i;
if (type === 'julia') i = julia(zx, zy, jr, ji, maxIter); else if (type === 'burningShip') i = burningShip(zx, zy, maxIter); else if (type === 'mandelbox') i = mandelbox(zx, zy, maxIter); else i = mandelbrot(zx, zy, maxIter);
const [r, g, b] = getColor(i, maxIter, scheme);

let value;
switch (type) {
case 'julia':
value = julia(zx, zy, jr, ji, maxIter);
break;
case 'burningShip':
value = burningShip(zx, zy, maxIter);
break;
case 'mandelbox':
value = mandelbox(zx, zy, maxIter);
break;
case 'sierpinskiCarpet':
value = sierpinskiCarpet(zx, zy, maxIter);
break;
case 'lyapunov':
value = lyapunov(zx, zy, maxIter);
break;
case 'phoenix':
value = phoenix(zx, zy, maxIter);
break;
case 'mandelbox3DSlice':
value = mandelbox3DSlice(zx, zy, maxIter);
break;
case 'newtonFractal':
value = newtonFractal(zx, zy, maxIter);
break;
default:
value = mandelbrot(zx, zy, maxIter);
}

const [r, g, b] = getColor(value, maxIter, scheme, type);
const pos = (y * width + x) * 4;
data[pos] = r;
data[pos + 1] = g;
data[pos + 2] = b;
data[pos + 3] = 255;
}
}

ctx.putImageData(imageData, 0, 0);
}

Expand Down Expand Up @@ -185,18 +228,140 @@
return c;
}

function getColor(i, maxIter, scheme) {
if (i === maxIter) return [0, 0, 0];
const t = i / maxIter;
function sierpinskiCarpet(x, y, maxIter) {
let iter = 0;
while (iter < maxIter) {
if ((Math.floor(x * 3) % 3 == 1) && (Math.floor(y * 3) % 3 == 1)) {
return iter;
}
x *= 3;
y *= 3;
x -= Math.floor(x);
y -= Math.floor(y);
iter++;
}
return maxIter;
}

function lyapunov(x, y, maxIter) {
const a = 3.7 * x;
const b = 3.7 * y;
let x0 = 0.5;
let sum = 0;
for (let i = 0; i < maxIter; i++) {
const r = i % 2 === 0 ? a : b;
x0 = r * x0 * (1 - x0);
sum += Math.log(Math.abs(r * (1 - 2 * x0)));
}
return sum / maxIter;
}

function phoenix(x, y, maxIter) {
let x1 = x, y1 = y, x2 = 0, y2 = 0;
const p = -0.5, q = 0.0;
for (let i = 0; i < maxIter; i++) {
const xx = x1 * x1 - y1 * y1 + x + p * x2;
const yy = 2 * x1 * y1 + y + q * y2;
if (xx * xx + yy * yy > 4) return i;
x2 = x1;
y2 = y1;
x1 = xx;
y1 = yy;
}
return maxIter;
}

function mandelbox3DSlice(x, y, maxIter) {
const scale = 2;
let zx = x, zy = y, zz = 0;
let c = 0;
for (let i = 0; i < maxIter; i++) {
zx = clamp(zx, -1, 1) * 2 - zx;
zy = clamp(zy, -1, 1) * 2 - zy;
zz = clamp(zz, -1, 1) * 2 - zz;

const r = Math.sqrt(zx*zx + zy*zy + zz*zz);
if (r < 0.5) {
zx *= 4; zy *= 4; zz *= 4;
} else if (r < 1) {
zx /= r*r; zy /= r*r; zz /= r*r;
}

zx = zx * scale + x;
zy = zy * scale + y;
zz = zz * scale;

if (zx*zx + zy*zy + zz*zz > 4) return i;
c++;
}
return c;
}

function clamp(x, min, max) {
return Math.min(Math.max(x, min), max);
}

function newtonFractal(x, y, maxIter) {
let zx = x, zy = y;
for (let i = 0; i < maxIter; i++) {
const zx2 = zx * zx, zy2 = zy * zy;
const zx3 = zx2 * zx - 3 * zx * zy2;
const zy3 = 3 * zx2 * zy - zy2 * zy;
const mag = zx3 * zx3 + zy3 * zy3;
if (mag < 1e-6) return i;
const denom = 3 * (zx2 + zy2);
zx -= (zx3 + 1) / denom;
zy -= zy3 / denom;
}
return maxIter;
}

function getColor(value, maxIter, scheme, type) {
if (type === 'lyapunov') {
// Lyapunov fractal uses a different coloring scheme
const hue = (value + 5) / 10; // Adjust this range as needed
return hsvToRgb(hue, 1, 1);
}

if (value === maxIter) return [0, 0, 0];

const t = value / maxIter;
switch (scheme) {
case'rainbow':
case 'rainbow':
return hsvToRgb(t, 1, 1);
case'fire':
case 'fire':
return hsvToRgb(t / 3, 1, Math.min(1, t * 2));
case'ocean':
case 'ocean':
return hsvToRgb(0.6 + t / 3, 1, Math.min(1, t * 2));
case'psychedelic':
case 'psychedelic':
return hsvToRgb(Math.sin(t * Math.PI), 1, 1);
case 'pastel':
return hsvToRgb(t, 0.5, 1);
case 'neon':
return hsvToRgb(t, 1, t < 0.5 ? 0.5 + t : 1);
case 'grayscale':
const gray = Math.floor(t * 255);
return [gray, gray, gray];
case 'autumn':
return [
Math.floor(255 * t),
Math.floor(128 * Math.sin(Math.PI * t)),
Math.floor(64 * (1 - t))
];
case 'electric':
return hsvToRgb(0.6 + 0.4 * t, 1, t < 0.5 ? 2 * t : 1);
case 'cosmic':
return [
Math.floor(128 * (1 + Math.sin(2 * Math.PI * t))),
Math.floor(128 * (1 + Math.sin(2 * Math.PI * t + 2 * Math.PI / 3))),
Math.floor(128 * (1 + Math.sin(2 * Math.PI * t + 4 * Math.PI / 3)))
];
case 'vintage':
return [
Math.floor(255 * (0.5 + 0.5 * Math.sin(Math.PI * t))),
Math.floor(255 * (0.5 + 0.5 * Math.sin(Math.PI * t + Math.PI / 2))),
Math.floor(255 * (0.5 + 0.5 * Math.sin(Math.PI * t + Math.PI)))
];
default:
return hsvToRgb(t, 1, Math.sqrt(t));
}
Expand All @@ -210,24 +375,12 @@
const q = v * (1 - f * s);
const t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0:
r = v, g = t, b = p;
break;
case 1:
r = q, g = v, b = p;
break;
case 2:
r = p, g = v, b = t;
break;
case 3:
r = p, g = q, b = v;
break;
case 4:
r = t, g = p, b = v;
break;
case 5:
r = v, g = p, b = q;
break;
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
Expand Down

0 comments on commit 1eb458a

Please sign in to comment.