Aromatic ring

Sampling 2D distance field with union via smooth min (logsumexp)

Log in to post a comment.

const R = 45;
const r1 = 11;
const r2 = 4.5;

const max_d = r1;
const step = 0.2;

const alpha = 0.2;

Canvas.setpenopacity(-0.2);

const t = new Turtle();

function minus(v1, v2) {
    return [v1[0] - v2[0], v1[1] - v2[1]];
}

function length(v) {
    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
}

function df_circ(v, c, r) {
    return length(minus(v, c)) - r;
}

function smooth_max(a, b, alpha) {
    return Math.log(Math.exp(alpha * a) + Math.exp(alpha * b)) / alpha;
}

function smooth_min(a, b, alpha) {
    return -smooth_max(-a, -b, alpha)
}

const circles = [];

const N = 6;
for (let i = 0; i < N; i++) {
    let phi = Math.PI / 6 + 2 * Math.PI / N * i;
    
    let c1 = [[R * Math.cos(phi), R * Math.sin(phi)], r1];
    let c2 = [[(R + r1 + 6 * r2) * Math.cos(phi), (R + r1 + 6 * r2) * Math.sin(phi)], r2];
    
    circles.push(c1);
    circles.push(c2);
}

let x = -100;
let y = -100;

function walk(frame) {
    let p = [x, y];
    
    let d = 400;
    for (let c of circles) {
        let dc = df_circ(p, c[0], c[1]);
        
        d = smooth_min(d, dc, alpha);
    }
    
    if (Math.abs(d) < max_d) {
        let s = step * (1 - d / max_d);
        
        t.seth(360 * Math.random());

        for (let i = 0; i < 4; i++) {
            t.jump(x, y);
            t.forward(s);
            t.right(90);
        }
    }
    
    x += step;
    if (x > 100) {
        x = -100;
        y += step;
    }
    
    return y <= 100;
}