Draw randomized grid, split cells into multiple rectangles and recurse.
#kdtree
Log in to post a comment.
const turtle = new Turtle(); const seed = 50; /// min=1, max=100, step=1 const baseShape = 0; // min=0, max=1, step=1 (Square, Hexagon) const grid = 7; // min=3, max=21, step=2 const maxDepth = 4; // min=1, max=10, step=1 const directionMode = 0; // min=0, max=1, step=1 (Random, Modulo) const splitMode = 0; // min=0, max=1, step=1 (Scattered, Ordered) const splitChance = 0.84; // min=0, max=1, step=0.01 const splitMin = 2; // min=1, max=8, step=1 const splitMax = 3; // min=1, max=8, step=1 const randomDistortion1 = .4; // min=0, max=1, step=0.01 const randomDistortion2 = .03; // min=0, max=0.25, step=0.001 const shapeScaleMode = 0//min=0, max=2, step=1 (Both, On Outer Shape, On Splitted Shapes) const shapeScale = 0.98; // min=0.75, max=1.25, step=0.001 const scale = 220 / grid; let mod = 0; function walk(i) { const x = (i % grid) - (grid/2|0); const y = (i/grid|0) - (grid/2|0); if (baseShape == 0) { const square = randomizePoints(createSquare(x, y), randomDistortion1); recurse(square, splitChance); } else if (baseShape == 1) { const hexagon = randomizePoints(createHexagon(x, y), randomDistortion1); const square1 = [hexagon[0],hexagon[1],hexagon[2],hexagon[3]]; const square2 = [hexagon[3],hexagon[4],hexagon[5],hexagon[0]]; recurse( square1, splitChance); recurse( square2, splitChance); } return i < grid * grid - 1; } function recurse(points, chance = 0.5, depth = 0) { const doRecurse = depth < maxDepth && chance > 0; const totalSplits = Math.round(lrp(splitMin,splitMax, rand())); const direction = directionMode == 0 ? rand() > 0.5 : mod++ % 3 == 0; const splittedShapeScale = (shapeScaleMode == 0 || shapeScaleMode == 2) ? shapeScale : 1.0; const shape = split(points, totalSplits, direction, splittedShapeScale); if (splitMode == 0) { if (doRecurse && rand() < chance) { shape.forEach(points => recurse(points, chance, depth + 1)); } else { if (shapeScaleMode <= 1) { shape.forEach((points,i,l) => l[i] = randomizePoints(points, randomDistortion2)); shape.forEach((points,i,l) => l[i] = scl4(points, shapeScale)); } shape.forEach(points => drawPoints(points.map(point => scl2(point, scale)), turtle)); } } else { shape.forEach(points => { if (doRecurse && rand() < chance) { recurse(points, chance, depth + 1); } else { if (shapeScaleMode <= 1) { shape.forEach((points,i,l) => l[i] = randomizePoints(points, randomDistortion2)); shape.forEach((points,i,l) => l[i] = scl4(points, shapeScale)); } drawPoints(points.map(point => scl2(point, scale)), turtle); } }); } } 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 => add2(center, p)); } function randomizePoints(points, scale = 1) { return points.map( point => add2(point, scl2( add2( [hash(dot2(point, [11, 13])), hash(dot2(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 split(points, total = 5, vertical = true, scale = 1.0) { const [tl,tr,br,bl] = points; const shapes = []; for(let i=0;i<total;i++) { const t1 = (i + (1 - scale)) / total; const t2 = (i + scale) / total; if (vertical) { shapes.push([ [lrp(tl[0], tr[0], t1), lrp(tl[1], tr[1], t1) ], [lrp(tl[0], tr[0], t2), lrp(tl[1], tr[1], t2) ], [lrp(bl[0], br[0], t2), lrp(bl[1], br[1], t2) ], [lrp(bl[0], br[0], t1), lrp(bl[1], br[1], t1) ], ]); } else { shapes.push([ [lrp(tl[0], bl[0], t1), lrp(tl[1], bl[1], t1) ], [lrp(tl[0], bl[0], t2), lrp(tl[1], bl[1], t2) ], [lrp(tr[0], br[0], t2), lrp(tr[1], br[1], t2) ], [lrp(tr[0], br[0], t1), lrp(tr[1], br[1], t1) ], ]); } } return shapes; } // vec2 functions function scl2(a,b) { return [a[0]*b, a[1]*b]; } function add2(a,b) { return [a[0]+b[0], a[1]+b[1]]; } function sub2(a,b) { return [a[0]-b[0], a[1]-b[1]]; } function dot2(a,b) { return a[0]*b[0] + a[1]*b[1]; } function len2(a) { return Math.sqrt(a[0]**2 + a[1]**2); } function nrm2(a) { return scl(a, 1/len(a)); } function lrp2(a,b,f) { return [a[0]*f+b[0]*(1-f), a[1]*f+b[1]*(1-f)]; } function lrp(a,b,f) { return a*f + b*(1-f); } function scl4(shape, scale=0.9) { const t1 = 1-scale; const t2 = scale; const [tl,tr,br,bl] = shape; return [ [lrp(tl[0], br[0], t1), lrp(tl[1], br[1], t1) ], [lrp(tr[0], bl[0], t1), lrp(tr[1], bl[1], t1) ], [lrp(br[0], tl[0], t1), lrp(br[1], tl[1], t1) ], [lrp(bl[0], tr[0], t1), lrp(bl[1], tr[1], t1) ], ]; } function add4(shape, val = 0) { const [tl,tr,br,bl] = shape; return [ add2(tl,[val,val]), add2(tr,[-val,val]), add2(br,[-val,-val]), add2(bl,[val,-val]) ]; } // pseudo random methods function hash(p) { p += seed; p = 1103515245 * (((p) >> 1) ^ (p)); p = 1103515245 * (p ^ (p>>3)); p = p ^ (p >> 16); return p / 1103515245 % 1; } let rseed = seed; function rand() { let r = 1103515245 * (((rseed) >> 1) ^ (rseed++)); r = 1103515245 * (r ^ (r>>3)); r = r ^ (r >> 16); return r / 1103515245 % 1; }