Shape to Circle ⭕

Draw from grid of squares / hexagon shapes to a circle.

Use sliders to create some variation, or use these preset:
Shape to Circle ⭕ (variation)

Shape to Circle ⭕ (variation)

Log in to post a comment.

const shape = 0; // min=0, max=1, step=1
const turtle = new Turtle();


const grid = 11; // min=3, max=50, step=2
const shapeScale = 1; // min=0, max=2, step=0.001
const segments = 9; // min=2, max=30, step=1
const radiusBase = 0.5; // min=0, max=3, step=0.01
const radiusRange = 0.25; // min=0, max=3, step=0.01
const offsetRange = 0.25; // min=0, max=3, step=0.01

// The walk function will be called until it returns false.
function walk(i) {
	const size = 175;
    const x = (i % grid) - (grid/2|0);
    const y = (i/grid|0) - (grid/2|0);

	const segmentedShape = [];
	let   midPoint = [0, 0];
	const shapes = shape > .5 ? createHexagon(x, y,shapeScale) : createSquare(x,y,shapeScale);
	shapes.forEach((p1, idx, pts) => {
	    midPoint = add(midPoint, scl(p1, 1/shapes.length));
		const p2 = pts[(idx + 1) % pts.length];
		for (let s = 0; s < segments; s++) {
			segmentedShape.push(lrp(p1, p2, s / segments));
		}
	});
	const radius = radiusBase + (-radiusRange / 2 + radiusRange * Math.random());
	const circleCenter = add(scl(sub([Math.random(), Math.random()], [0.5, 0.5]), offsetRange), midPoint);
	

	segmentedShape.forEach((point, idx) => {
	    const scale = size/grid;
		turtle.jump(scl(point, scale));
		const vec = nrm(sub(point, circleCenter));
		turtle.goto(scl(add(circleCenter, scl(vec, radius * 0.5)), scale));
	});

	return i < grid * grid - 1;
}

// shape generators 
function createSquare(x,y,scale=1) {
    return [[x-.5*scale,y+.5*scale], [x-.5*scale,y-.5*scale], [x+.5*scale,y-.5*scale], [x+.5*scale,y+.5*scale]];
}

function createHexagon(x,y, scale=1) {
    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, scl(p,scale)));
}

// vec2 functions
function vec2(a)    { return [a,a]; }
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)]; }
function angle(a,b) { return Math.atan2(b[1]-a[1], b[0]-a[0]) }