Grid with way too many sliders.
Log in to post a comment.
// Grid variations. Created by Reinder Nijhoff 2020 // @reindernijhoff // // https://turtletoy.net/turtle/abbc1557a1 // Canvas.setpenopacity(.5); const turtle = new Slowpoke(); const seed = 1; // min=1, max=100, step=1 const baseShape = 1; // min=0, max=1, step=1 (Box, Hexagon) const twistLength = .1; // min=0.01, max=2, step=0.01 const twistFactor = .07; // min=0, max=1, step=0.01 const splitAngle = .3; // min=0, max=1, step=0.01 const splitChange = .1; // min=0, max=1, step=0.01 const randomDistortion = .4; // min=0, max=1, step=0.01 const clipToBox = 0; // min=0, max=1, step=1 (No, Yes) const grid = 5; // min=3, max=21, step=2 function walk(i) { const scale = 220 / grid; const x = (i % grid) - (grid/2|0); const y = (i/grid|0) - (grid/2|0); // create base shape let points = baseShape ? createHexagon(x, y) : createSquare(x, y); // give vertices random offset points = randomizePoints(points, randomDistortion); // optional: clip points to box if (clipToBox) { for (let j=-1; j<=1; j+=2) { points = clipPoints(points, [j,0], grid/3); points = clipPoints(points, [0,j], grid/3); } } // shatter shape into shapes const shapes = shatterPoints(points); // for each shape: repeatedly draw and 'twist' shapes.forEach( points => { let maxLen, steps = 0; do { drawPoints(points.map(point => scl(point, scale)), turtle); points = twistPoints(points, twistFactor); maxLen = 0, steps++; points.forEach((p, i) => { maxLen = Math.max(maxLen, len(sub(p, points[(i+1)%points.length]))); }); } while (maxLen > twistLength && steps < 100); }); return i < grid * grid - 1; } // shape generators function createSquare(x,y) { return [[x-.5,y+.5], [x-.5,y-.5], [x+.5,y-.5], [x+.5,y+.5]]; } function createHexagon(x,y) { const h = .75, w = 3/8 * (h/(Math.sqrt(3)/4)), center = [x*2*w + (y%2)*w, y*3/2*h]; return [[0,-h],[-w,-h/2],[-w,h/2],[0,h],[w,h/2],[w,-h/2]].map(p => add(center, p)); } // vec2 functions function scl(a,b) { return [a[0]*b, a[1]*b]; } function add(a,b) { return [a[0]+b[0], a[1]+b[1]]; } function sub(a,b) { return [a[0]-b[0], a[1]-b[1]]; } function dot(a,b) { return a[0]*b[0] + a[1]*b[1]; } function len(a) { return Math.sqrt(a[0]**2 + a[1]**2); } function nrm(a) { return scl(a, 1/len(a)); } function lrp(a,b,f) { return [a[0]*f+b[0]*(1-f), a[1]*f+b[1]*(1-f)]; } // shape functions function randomizePoints(points, scale = 1) { return points.map( point => add(point, scl( add( [hash(dot(point, [11, 13])), hash(dot(point, [17, 19]))], [-.5,-.5]), scale))); } function drawPoints(points, turtle) { if (points.length > 0) turtle.jump(points[points.length-1]); points.forEach(point => turtle.goto(point)); } function twistPoints(points, twist) { return points.map( (p0, i) => lrp(p0, points[(i+1) % points.length], twist) ); } function shatterPoints(points) { if (points.length <= 3) return [points]; // calculate angle at each vertex and sort them const l = points.length, angles = points.map( (p, i) => { return [dot( nrm( sub(points[(i+1)%l],p)), nrm( sub( points[(i+l-1)%l],p))), i]; }).sort((a,b) => a[0]-b[0]); // split at vertex with largest angle or just randomly if (angles[0][0] < splitAngle-1 || rand() < splitChange) { const i = angles[0][1], d = 3 + rand()*(l-4)|0, p2 = [...points, ...points]; return [...shatterPoints([...p2].splice(i, d)), ...shatterPoints([...p2].splice(i+d-1, l-d+2))]; } else { return [points]; } } function clipPoints(points, planeNormal, planeDist) { const newPoints = []; points.forEach( (p, i) => { const p1 = points[(i+1) % points.length], d0 = dot(p, planeNormal) + planeDist, d1 = dot(p1, planeNormal) + planeDist; if (d0 >= 0) newPoints.push(p); if (d0 * d1 < 0) newPoints.push(lrp(p, p1, Math.abs(d1)/(Math.abs(d0)+Math.abs(d1)))); }); return newPoints; } // pseudo random methods function hash(p) { p = 1103515245 * (((p+=seed) >> 1) ^ (p)); p = 1103515245 * (p ^ (p>>3)); p = p ^ (p >> 16); const mod = 1 << 20; return (p % mod) / mod; } let rseed = seed; function rand() { let r = 1103515245 * (((rseed+=12345) >> 1) ^ (rseed)); r = 1103515245 * (r ^ (r >> 3)); r = r ^ (r >> 16); const mod = 1 << 20; return (r % mod) / mod; } //////////////////////////////////////////////////////////////// // Slowpoke utility code. Created by Reinder Nijhoff 2019 // https://turtletoy.net/turtle/cfe9091ad8 //////////////////////////////////////////////////////////////// function Slowpoke(x, y) { const linesDrawn = {}; class Slowpoke extends Turtle { goto(x, y) { const p = Array.isArray(x) ? [...x] : [x, y]; if (this.isdown()) { const o = [this.x(), this.y()]; const h1 = o[0].toFixed(2)+'_'+p[0].toFixed(2)+o[1].toFixed(2)+'_'+p[1].toFixed(2); const h2 = p[0].toFixed(2)+'_'+o[0].toFixed(2)+p[1].toFixed(2)+'_'+o[1].toFixed(2); if (linesDrawn[h1] || linesDrawn[h2]) { super.up(); super.goto(p); super.down(); return; } linesDrawn[h1] = linesDrawn[h2] = true; } super.goto(p); } } return new Slowpoke(x,y); }