Deformed circles on a noise field.
Log in to post a comment.
// You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(0.5); const size = 80; //min = 10, max = 100, step = 5 const perlinSize = 2; //min = 1, max = 50, step = 1 const circles = 80; //min = 1, max = 250, step = 1 const resolution = 0.25; //min = 0.01, max = 1, step = 0.01 const amplitude = 18; //min = 0, max = 25, step = 0.5 // Global code will be evaluated once. const turtle = new Turtle(); class Perlin{ constructor(size, gridSize){ this.size = size; this.gridSize = gridSize; this.grid = []; // this.mean = 0; // For each grid intersection, compute a random unit vector for(let i = 0; i <= gridSize; i++){ let table = []; for(let j = 0; j <= gridSize; j++){ let angle = Math.random() * 2 * Math.PI; let x = Math.cos(angle); let y = Math.sin(angle); table.push([x, y]); // console.log([x, y]); } this.grid.push(table); } // console.log(this.grid); } get(x, y){ x = x / 2 + this.size / 2; y = y / 2 + this.size / 2; if(x < 0) x = 0; if(x >= this.size) x = this.size - 0.01; if(y < 0) y = 0; if(y >= this.size) y = this.size - 0.01; // console.log(x, y); let posx = x * this.gridSize / this.size; let posy = y * this.gridSize / this.size; // console.log(posx, posy); let x1 = Math.floor(posx); let x2 = x1 + 1; let y1 = Math.floor(posy); let y2 = y1 + 1; let scal = []; scal.push() scal.push(this.scalar(posx, posy, x1, y1)); scal.push(this.scalar(posx, posy, x2, y1)); scal.push(this.scalar(posx, posy, x1, y2)); scal.push(this.scalar(posx, posy, x2, y2)); // console.log(scal); // interpolate : linear interpolation for a start let int1 = this.interpolate(posx - x1, scal[0], scal[1]); let int2 = this.interpolate(posx - x1, scal[2], scal[3]); // console.log(int1, int2); // this.mean += this.interpolate(posy - y1, int1, int2); return this.interpolate(posy - y1, int1, int2); } scalar(x, y, vx, vy){ x -= vx; y -= vy; // console.log(x, y); return x * this.grid[vx][vy][0] + y * this.grid[vx][vy][1]; } smooth(v){ if(v < 0) v = 0; if(v > 1) v = 1; return v**2 * (3 - 2*v); } interpolate(x, a, b){ return a + (b - a) * this.smooth(x) } } // Class that handle tracing of circles, and their behavior regarding attractors. class Circle{ constructor(diameter = 25){ this.size = diameter; this.centerX = 0; this.centerY = 0; this.angle = 0; this.turtle = new Turtle(); this.turtle.jump(0, size); } walk(){ let radAngle = this.angle * Math.PI / 180; this.x = Math.cos(radAngle) * this.size; this.y = Math.sin(radAngle) * this.size; // console.log(this.x, this.y); let deviation = perlin.get(this.x, this.y); // console.log(deviation); this.x += Math.cos(deviation * Math.PI) * amplitude; this.y += Math.sin(deviation * Math.PI) * amplitude; // console.log(this.x, this.y); if(this.angle == 0) this.turtle.jump(this.x, this.y); else this.turtle.goto(this.x, this.y); this.angle += resolution; if(this.angle > 360) return false; return true; } } //generate the circles. const circleList = []; for (let i = 0; i < circles; i++){ circleList.push(new Circle((size / circles) * (i + 1))); } let perlin = new Perlin(size, perlinSize); // The walk function will be called until it returns false. function walk(i) { let goOn = true; for(let circle of circleList){ goOn = circle.walk(); } // if(!goOn) console.log(perlin.mean); return goOn; }