Beadpackpathwander

Packing circles for a good wander.

Log in to post a comment.

Canvas.setpenopacity(1);
let shrinkageAcceleration = 100 //min=50, max=100, step=1
shrinkageAcceleration = 150 - shrinkageAcceleration
let AngleIncrementA = -240; // min=-360, max=360, step=1
const angleIncrement1 = AngleIncrementA * Math.PI / 180;
const maxFailures = 0
let AngleIncrementB = -180 // min=-360, max=360, step=1
const angleIncrement2 = AngleIncrementB * Math.PI / 180
let minimumRadius = 0.75 // min=0.5, max=10, step=0.05
let initialRadius = 3.0 // min=1, max=10, step=0.1
initialRadius = minimumRadius > initialRadius ? minimumRadius : initialRadius;
const circleArray = [createCircle(-5, -5, initialRadius, Math.PI * 16)];
let ratio = 0.999;
const initialRatio = ratio;
let currentCircle = circleArray[0]; 
let failures = 0;
const t = new Turtle();
t.pd();
t.radians();

function walk(i){
    if (i === 0){
        drawCircle(circleArray[0], t);
    } else {
       currentCircle = getAndCheck(currentCircle, circleArray);
    }
    return i < 100000;
}

function createCircle(x, y, rad, heading){
    return [x, y, rad, heading];
}

function checkCircles(c1, c2){
    const xd = (c2[0] - c1[0]) ** 2;
    const yd = (c2[1] - c1[1]) ** 2;
    const dsq = xd + yd;
    return dsq >= (c1[2] + c2[2]) ** 2;
}

function drawCircle(c, turtle){
    turtle.jmp(c[0], c[1] - c[2]);
// turtle.seth(c[3])
    turtle.circle(c[2])
        
}

function getNextCircle(c){
    let radiusOld = c[2];
    let radiusNew = radiusOld * ratio;
    radiusNew = radiusNew < minimumRadius ? minimumRadius : radiusNew
    let headingNew = c[3] += angleIncrement1 //* [-1, 0, 1][Math.floor(Math.random() * 3)];
    c[3] = headingNew;
    let d = ((radiusOld + radiusNew) * 2 + minimumRadius) / 2;
    let xOld = c[0];
    let yOld = c[1];
    let xNew = xOld + d * Math.cos(headingNew);
    let yNew = yOld + d * Math.sin(headingNew);
    return createCircle(xNew, yNew, radiusNew, headingNew);
}

function checkBounds(c){
    let add = 1;
    add *= c[0] < 100 - c[2];
    add *= c[0] > -100 + c[2];
    add *= c[1] < 100 - c[2];
    add *= c[1] > -100 + c[2];
    return add;
}

function getAndCheck(c1, circleArray){
    let c2 = getNextCircle(currentCircle);
    let add = 1;
    add *= checkBounds(c2);
    let newC;
    for (let c of circleArray){
        if (!add){
            break;
        }
        add *= checkCircles(c, c2);
        if (!add){
            newC = c;
            break;
        }
    }
    if (!add){
        // c1[3] += angleIncrement2
        failures++;
        if (failures > maxFailures){
            failures = 0;
             c1[3] += angleIncrement2;
             ratio *= 0.975 + shrinkageAcceleration / 4000;
             radius = initialRadius;
            let index = circleArray.indexOf(c1) - 1;
            index = index < 0 ? circleArray.length - 1 : index;
            // return circleArray[index];
             return circleArray[Math.floor(Math.random() * circleArray.length)]
            
        }
        return currentCircle;
    } else {
        ratio = initialRatio;
        drawCircle(c2, t);
        circleArray.push(c2);
        return c2;
    }
        }