Based on codepen.io/ge1doot/pen/vymqvp
Log in to post a comment.
// Forked from "our new land" by ge1doot // https://turtletoy.net/turtle/b2fdeed2d8 const mirrors = 8; //min=2 max=30 step=1 // You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(0.5); // Global code will be evaluated once. const turtle = new Kaleidoscope(0, 0, mirrors); //const turtle = new Turtle(); turtle.penup(); class Noise { // http://mrl.nyu.edu/~perlin/noise/ constructor(setup) { this.p = new Uint8Array(512); this.octaves = setup.octaves || 1; const p = new Uint8Array(256); for (let i = 0; i < 256; i++) p[i] = i; for (let i = 255; i > 0; i--) { const n = Math.floor((i + 1) * Math.random()); const q = p[i]; p[i] = p[n]; p[n] = q; } for (let i = 0; i < 512; i++) { this.p[i] = p[i & 255]; } } lerp(t, a, b) { return a + t * (b - a); } grad2d(i, x, y) { const v = (i & 1) === 0 ? x : y; return (i & 2) === 0 ? -v : v; } noise2d(x2d, y2d) { const X = Math.floor(x2d) & 255; const Y = Math.floor(y2d) & 255; const x = x2d - Math.floor(x2d); const y = y2d - Math.floor(y2d); const fx = (3 - 2 * x) * x * x; const fy = (3 - 2 * y) * y * y; const p0 = this.p[X] + Y; const p1 = this.p[X + 1] + Y; return this.lerp( fy, this.lerp( fx, this.grad2d(this.p[p0], x, y), this.grad2d(this.p[p1], x - 1, y) ), this.lerp( fx, this.grad2d(this.p[p0 + 1], x, y - 1), this.grad2d(this.p[p1 + 1], x - 1, y - 1) ) ); } noise(x, y) { let e = 1, k = 1, s = 0; for (let i = 0; i < this.octaves; ++i) { e *= 0.5; s += e * (1 + this.noise2d(k * x, k * y)) / 2; k *= 2; } return s; } } const perlin = new Noise({ octaves: 2 }); let y = 100; const line = Array.from({ length: 200 }, () => 100); // The walk function will be called until it returns false. function walk(i) { y -= 0.3; turtle.goto(-100, y); turtle.down(); let v = false; for (let x = -100; x < 100; x++) { let z = y + 0.25 * ( (2048 * perlin.noise(x * 0.02, 6 + y * 0.04)) & (16 + 32 + 0 + 128 + 256) ); if (z > -100) v = true; if (z > line[x]) z = line[x] - 0.01; line[x] = z; turtle.goto(x, z); } turtle.up(); return v; } function Kaleidoscope(x, y, mirrors = 4) { function rot2(a) { return [Math.cos(a), -Math.sin(a), Math.sin(a), Math.cos(a)]; } function trans2(m, a) { return [m[0]*a[0]+m[2]*a[1], m[1]*a[0]+m[3]*a[1]]; } function segment_intersect2(a,b,d,c) { const e=(c[1]-d[1])*(b[0]-a[0])-(c[0]-d[0])*(b[1]-a[1]); if(0==e)return false; c=((c[0]-d[0])*(a[1]-d[1])-(c[1]-d[1])*(a[0]-d[0]))/e; d=((b[0]-a[0])*(a[1]-d[1])-(b[1]-a[1])*(a[0]-d[0]))/e; return 0<=c&&1>=c&&0<=d&&1>=d?[a[0]+c*(b[0]-a[0]),a[1]+c*(b[1]-a[1])]:false; } function pointInTriangle(pt, ...v) { const signFn = (p1, p2, p3) => (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]); const signs = v.map((v, i, arr) => signFn(pt, v, arr[(i+1)%arr.length])); return !(signs.reduce((p, c) => p || c < 0, false) && signs.reduce((p, c) => p || c > 0, false)); } class Kaleidoscope extends Turtle { constructor(x, y, n = 4) { super(x, y); this.boundaries = [[0,0], [0, 1000], trans2(rot2(2*Math.PI/(n*2)), [0,1000])]; const rotations = Array.from({length: n}).map((v, i) => { return (pt) => trans2(rot2(i * 2 * Math.PI / n), pt); }); const mirrors = rotations.map(r => (pt) => trans2([-1, 0, 0, 1], r(pt))); this.transforms = [...rotations, ...mirrors]; this.cur = this.pos(); this.curIn = this.inSegment(this.cur); this.turtle = new Turtle(x, y); } inSegment(pt) { return pointInTriangle(pt, ...this.boundaries); } goto(x, y) { const target = Array.isArray(x)? x: [x, y]; const isDown = this.isdown(); const targetIn = this.turtle === undefined? false: this.inSegment(target); if (isDown) { (() => { const bOne = segment_intersect2(this.cur, target, this.boundaries[0], this.boundaries[1]); const bTwo = segment_intersect2(this.cur, target, this.boundaries[0], this.boundaries[2]); debugger; let from = this.cur; let to = target; if(!this.curIn && !targetIn) { if(bOne === false && bTwo === false) return; from = bOne; to = bTwo; } else if(!this.curIn) { from = bOne === false? bTwo: bOne; } else if(!targetIn) { to = bOne === false? bTwo: bOne; } this.transforms.forEach(t => { this.turtle.jump(t(from)); this.turtle.goto(t(to)); }); })(); } this.cur = target; this.curIn = targetIn this.up(); super.goto(x, y); if(isDown) this.down(); } } return new Kaleidoscope(x, y, mirrors) }