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;
}
}