This didn't come out like it looked in my head, but it's sort of fun anyway.
Interesting variations:
- Mutated concentric circles (variation)
- Mutated concentric circles (variation)
- Mutated concentric circles (variation)
Log in to post a comment.
// LL 2021 // Inspired by https://twitter.com/generativehut/status/1393499529467600896 const iterations = 200; // min=1 max=1000 step=1 const inner_size = 10; // min=1 max=100 step=1 const point_count = 300; // min=10 max=1000 step=1 const loop_count = 20; // min=0 max=20 step=1 const grow_fract = -50; // min=-101 max=1000 step=1 const spread = 1; // min=0 max=100 step=1 const mult = 2; // min=1 max=20 step=.01 const use_max = 1; // min=0 max=1 step=1 (No,Yes) const seed = 0; // min=0 max=100 step=1 const style = 0; // min=0 max=1 step=1 (Lines (fast),Polygons (slow)) Canvas.setpenopacity(1); const turtle = new Turtle(); function walk(i) { if (i==0) { rng = new RNG(seed); polygons = new Polygons(); circle = new Circle(inner_size, point_count); circle_max = circle.dup(); } const a = i * Math.PI/2 / Math.max(1, iterations-1); const d = 0; //1; //if (i==1) circle.draw(a, d, circle_max); const more_to_draw = circle.mutate(); if (!more_to_draw) return false; circle_max.recordMax(circle); //sleep(100); return i + 1 < iterations; } class Circle { constructor(size, count, points=undefined) { this.size = size; this.count = count; if (points === undefined) { this.points = []; const astep = Math.PI * 2 / this.count; for (var i=0, a=0; i<this.count; i++, a+=astep) { const x = size * Math.cos(a); const y = size * Math.sin(a); this.points.push(x); // ,y); this.points.push(y); } } else { this.points = [...points]; } } dup() { return new Circle(this.size, this.count, this.points); } recordMax(circle) { for (var i=0; i<this.points.length && i<circle.points.length; i++) { this.points[i] = smax(this.points[i], circle.points[i]); } } draw(a, d, circle_max) { const points = []; for (var i=0; i<this.count && i<circle_max.count; i++) { var x = this.points[i*2+0]; var y = this.points[i*2+1]; if (use_max) { x = smax(x, circle_max.points[i*2+0]); y = smax(y, circle_max.points[i*2+1]); } points.push([x, y]); } drawPoints(points, a, d); } mutate() { var more_to_draw = loop_count < 1; const grow = 1 + grow_fract / 1000; for (var i = 0; i < this.points.length; i++) { this.points[i] *= grow; } for (var loop = 0; loop < loop_count; loop++) { const index = (this.count * rng.nextFloat()) | 0; this.points[index * 2 + 0] *= mult; this.points[index * 2 + 1] *= mult; const new_points = [...this.points]; for (var i = 0; i < this.count; i++) { const this_len = Math.hypot(this.points[i * 2], this.points[i * 2 + 1]); var total_len = 0; var len_count = 0; for (var j=-spread; j<=spread; j++, len_count++) { const ii = (i + this.points.length + j) % (this.count); total_len += Math.hypot(this.points[ii * 2], this.points[ii * 2 + 1]);; } const nlen = total_len / len_count; const factor = nlen / this_len; new_points[i*2+0] *= factor; new_points[i*2+1] *= factor; more_to_draw |= Math.abs(new_points[i*2]) < 100 && Math.abs(new_points[i*2+1]) < 100 && Math.abs(new_points[i*2]) > 1 && Math.abs(new_points[i*2+1]) > 1; } this.points = new_points; } return more_to_draw; } } function smax(v1, v2) { const v = Math.max(Math.abs(v1), Math.abs(v2)) * Math.sign(v1); return v; } function sleep(ms) { start=Date.now(); while (Date.now()-start<ms); } // Random with seed function RNG(t){return new class{constructor(t){this.m=2147483648,this.a=1103515245,this.c=12345,this.state=t||Math.floor(Math.random()*(this.m-1))}nextFloat(){return this.state=(this.a*this.state+this.c)%this.m,this.state/(this.m-1)}}(t)} function drawPoints(points, hatching_angle = 0, hatching_distance = 0) { if (style == 0) { turtle.jump(points[points.length-1]); points.forEach(p=>turtle.goto(p)); } else { const p1 = polygons.create(); p1.addPoints(...points); if (hatching_distance) p1.addHatching(hatching_angle, hatching_distance); p1.addOutline(); polygons.draw(turtle, p1, true); } } //////////////////////////////////////////////////////////////// // Polygon Clipping utility code - Created by Reinder Nijhoff 2019 // https://turtletoy.net/turtle/a5befa1f8d //////////////////////////////////////////////////////////////// function Polygons(){const t=[],s=class{constructor(){this.cp=[],this.dp=[],this.aabb=[]}addPoints(...t){let s=1e5,e=-1e5,h=1e5,i=-1e5;(this.cp=[...this.cp,...t]).forEach(t=>{s=Math.min(s,t[0]),e=Math.max(e,t[0]),h=Math.min(h,t[1]),i=Math.max(i,t[1])}),this.aabb=[(s+e)/2,(h+i)/2,(e-s)/2,(i-h)/2]}addSegments(...t){t.forEach(t=>this.dp.push(t))}addOutline(){for(let t=0,s=this.cp.length;t<s;t++)this.dp.push(this.cp[t],this.cp[(t+1)%s])}draw(t){for(let s=0,e=this.dp.length;s<e;s+=2)t.jump(this.dp[s]),t.goto(this.dp[s+1])}addHatching(t,e){const h=new s;h.cp.push([-1e5,-1e5],[1e5,-1e5],[1e5,1e5],[-1e5,1e5]);const i=Math.sin(t)*e,n=Math.cos(t)*e,a=200*Math.sin(t),p=200*Math.cos(t);for(let t=.5;t<150/e;t++)h.dp.push([i*t+p,n*t-a],[i*t-p,n*t+a]),h.dp.push([-i*t+p,-n*t-a],[-i*t-p,-n*t+a]);h.boolean(this,!1),this.dp=[...this.dp,...h.dp]}inside(t){let s=0;for(let e=0,h=this.cp.length;e<h;e++)this.segment_intersect(t,[.1,-1e3],this.cp[e],this.cp[(e+1)%h])&&s++;return 1&s}boolean(t,s=!0){if(Math.abs(this.aabb[0]-t.aabb[0])-(t.aabb[2]+this.aabb[2])>=0&&Math.abs(this.aabb[1]-t.aabb[1])-(t.aabb[3]+this.aabb[3])>=0)return this.dp.length>0;const e=[];for(let h=0,i=this.dp.length;h<i;h+=2){const i=this.dp[h],n=this.dp[h+1],a=[];for(let s=0,e=t.cp.length;s<e;s++){const h=this.segment_intersect(i,n,t.cp[s],t.cp[(s+1)%e]);!1!==h&&a.push(h)}if(0===a.length)s===!t.inside(i)&&e.push(i,n);else{a.push(i,n);const h=n[0]-i[0],p=n[1]-i[1];a.sort((t,s)=>(t[0]-i[0])*h+(t[1]-i[1])*p-(s[0]-i[0])*h-(s[1]-i[1])*p);for(let h=0;h<a.length-1;h++)(a[h][0]-a[h+1][0])**2+(a[h][1]-a[h+1][1])**2>=.001&&s===!t.inside([(a[h][0]+a[h+1][0])/2,(a[h][1]+a[h+1][1])/2])&&e.push(a[h],a[h+1])}}return(this.dp=e).length>0}segment_intersect(t,s,e,h){const i=(h[1]-e[1])*(s[0]-t[0])-(h[0]-e[0])*(s[1]-t[1]);if(0===i)return!1;const n=((h[0]-e[0])*(t[1]-e[1])-(h[1]-e[1])*(t[0]-e[0]))/i,a=((s[0]-t[0])*(t[1]-e[1])-(s[1]-t[1])*(t[0]-e[0]))/i;return n>=0&&n<=1&&a>=0&&a<=1&&[t[0]+n*(s[0]-t[0]),t[1]+n*(s[1]-t[1])]}};return{list:()=>t,create:()=>new s,draw:(s,e,h=!0)=>{for(let s=0;s<t.length&&e.boolean(t[s]);s++);e.draw(s),h&&t.push(e)}}}