Re-imagining of the sketch from which this is forked. Tweaked adjustment parameters, changed rendering to lines instead of circles, added fine-tuned adjustment slider to AngleIncrementA.
Most recent revision:
- added breakpoints for responsive pen opacity based on the minimum radius slider, and a corresponding function.
- Added a slider to adjust the number of iterations before the sketch stops running.
Log in to post a comment.
// Forked from "Beadpackpathwander" by ProjectGrantwood // https://turtletoy.net/turtle/5f76422d98 let shrinkageAcceleration = 0; //min=0, max=50, step=1 let shrinkageAcceleration_FineAdjust = 0.0//min=0, max=1, step=0.001 let AngleIncrementA = 20 // min=-180, max=180, step=1 let AngleIncrementA_FineAdjust = 0 //min=0, max=1, step=0.01 let AngleIncrementB = -26 // min=-180, max=180, step=1 let AngleIncrementB_FineAdjust =0 //min=0, max=1, step=0.01 let minimumRadius = 0.2 // min=0.05, max=4, step=0.01 let initialRadius = 4 // min=1, max=34, step=1 let maxFailures = 0 //min=0, max=200, step=1 let MaxIterations = 20000 //min=1000, max=80000, step=1000 // the breakpoints are based on the value of the minimumRadius let pen_opacity_breakpoints = [0.05, 0.08, 0.12, 0.15, 0.2, 0.25] let pen_opacities = [0.375, 0.425, 0.5, 0.625, 0.75, 0.875] let opacity = findCurrentPenOpacityBreakpoint( minimumRadius, pen_opacity_breakpoints, pen_opacities ); Canvas.setpenopacity(opacity); // shrinkageAcceleration = (100 - (shrinkageAcceleration + shrinkageAcceleration_FineAdjust)) / 1000; initialRadius = minimumRadius > initialRadius ? minimumRadius : initialRadius; const angleIncrement1 = (AngleIncrementA + AngleIncrementA_FineAdjust) * Math.PI / 180; const angleIncrement2 = (AngleIncrementB + AngleIncrementB_FineAdjust) * Math.PI / 180 const t = new Turtle(); const circleArray = [createCircle(0, 0, initialRadius, -Math.PI * 2)]; let ratio = 0.9; let ratio2 = 0.999; const initialRatio = ratio; let currentCircle = circleArray[0]; let failures = 0; t.pd(); t.radians(); function walk(i){ if (i === 0){ // draw(circleArray[0], t, '10'); } else { for (let j = 0; j < 12; j++){ currentCircle = getAndCheck(currentCircle, circleArray); } } return i < MaxIterations; } 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 draw(c, turtle, flags = '01'){ turtle.jmp(c[0], c[1] - c[2]); if (flags[0] === '1'){ turtle.circle(c[2]) } if (flags[1] === '1') { turtle.jmp(c[0], c[1]); turtle.seth(c[3] - Math.PI) let travelDistance = c[2]; travelDistance = c[2] === minimumRadius ? c[2] + c[2] + minimumRadius : c[2] + c[2] / ratio + minimumRadius turtle.forward(travelDistance) } } function getNextCircle(c){ let radiusOld = c[2]; let radiusNew = radiusOld * ratio radiusNew = radiusNew < minimumRadius ? minimumRadius : radiusNew let headingNew = c[3] += angleIncrement1 //* [-1, 1][Math.floor(Math.random() * 2)]; c[3] = headingNew; let d = ((radiusOld + radiusNew) + minimumRadius); 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 = c2; break; } } if (!add){ c1[3] += angleIncrement2 failures++; if (failures > maxFailures){ failures = 0; c1[3] += angleIncrement2 //* [-1, 1][Math.floor(Math.random() * 2)]; ratio *= initialRatio + shrinkageAcceleration; 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 + shrinkageAcceleration; draw(c2, t); circleArray.push(c2); return c2; } } function findCurrentPenOpacityBreakpoint(min_radius, pen_opacity_breakpoints, pen_opacities) { let breakpoint = 0; for (let i = 0; i < pen_opacity_breakpoints.length; i++){ if (min_radius > pen_opacity_breakpoints[i]){ breakpoint++; } if (min_radius <= pen_opacity_breakpoints[breakpoint]){ break; } } return pen_opacities[breakpoint]; }