Hidden circle removal

Super slow for extra enjoyment.

Log in to post a comment.

Canvas.setpenopacity(1);

const precision = 300; /// min=3 max=1000 step=1
const concentric = 50; // min=1 max=100 step=1
const density = 0.25; // min=0.0.1 max=3 step=0.01
const radius = 90; // min=0 max=300 step=1
const epicenters = 25; // min=1 max=1000 step=1
const variation = 0.0; // min=0 max=0.5 step=0.01
const frequency = 4; // min=1 max=10 step=0.1

const turtle = new Turtle();

let circle_list;
let radius_t = radius;

let epicenter_list;

function walk(i, t) {
    if (i == 0) {
        circle_list = [];
        
        epicenter_list = [];
        while (epicenter_list.length < epicenters) {
            var x, y;
            if (radius < 0.1) {
                var retries = 100;
                var done = false;
                while (retries-- > 0 && !done) {
                    x = (Math.random() - 0.5) * 200;
                    y = (Math.random() - 0.5) * 200;
                    done = true;
                    epicenter_list.forEach(e => {
                        const distance = Math.hypot(x-e.x, y-e.y);
                        if (distance < 10) done = false;
                    });
                }
            } else {
                const i = epicenter_list.length;
                const r = radius_t * ((1-variation) + Math.sin(Math.PI * 2 * frequency / epicenters * i) * variation * 2);
                x = r * Math.cos(Math.PI/2 + Math.PI * 2 / epicenters * i);
                y = r * Math.sin(Math.PI/2 + Math.PI * 2 / epicenters * i);
            }
            epicenter_list.push({x:x, y:y, r:0.4});
        }

        radius_t = radius * (Math.cos(Math.PI * 2 * t) + 1) / 2;
    }

    const e = epicenter_list[i % epicenters];
    const c = new Circle(e.x, e.y, e.r);
    e.r += 1/density;

    c.clip(circle_list);
    if (c.lines.length > 10) {
        c.draw();
        circle_list.push(c);
    }

    return (i+1) < concentric * epicenters;
}

class Circle {
    constructor(x, y, r) {
        this.x = x; this.y = y; this.r = r;
        this.lines = [];
        const p = Math.max(3, Math.round(precision * this.r / 10));
        const step = Math.PI * 2 / p;
        for (var i=0; i<p; i++) {
            const a0 = step * i;
            const a1 = step * (i+1);
            const x0 = this.x + Math.cos(a0) * this.r;
            const y0 = this.y + Math.sin(a0) * this.r;
            const x1 = this.x + Math.cos(a1) * this.r;
            const y1 = this.y + Math.sin(a1) * this.r;
            this.lines.push({start:{x:x0, y:y0}, end:{x:x1, y:y1}});
        }
    }
    
    draw() {
        this.lines.forEach(l => {
            turtle.jump(l.start.x, l.start.y);
            turtle.goto(l.end.x, l.end.y);
        })
    }
    
    // This would benefit from some serious optimization
    // For starters: 3 calls to hypot need to go
    clip(list) {
        list.forEach(c => {
            if (this.x - c.x < c.r + this.r && this.y - c.y < c.r + this.r) {
                const distance = Math.hypot(this.x - c.x, this.y - c.y);
                if (distance < (c.r + this.r)) {
                    if (distance < (c.r - this.r)) {
                        this.lines = [];
                    }
                    const to_delete = [];
                    this.lines.forEach((l, i) => {
                        if ((Math.abs(l.start.x) > 150 || Math.abs(l.start.y) > 150) && (Math.abs(l.end.x) > 150 || Math.abs(l.end.y) > 150)) {
                            to_delete.unshift(i);
                        } else {
                            const d0 = Math.hypot(l.start.x - c.x, l.start.y - c.y);
                            const d1 = Math.hypot(l.end.x - c.x, l.end.y - c.y);
                            if (d0 < c.r || d1 < c.r) {
                                to_delete.unshift(i);
                            }
                        }
                    });
                    to_delete.forEach(i => {
                        this.lines.splice(i, 1);
                    });
                }
            }
        });
    }
}