Gilbert tessellation
en.wikipedia.org/wiki/gilbert_tessellation
#tessellation
Log in to post a comment.
// Gilbert tessellation. Created by Reinder Nijhoff 2023 - @reindernijhoff // // https://turtletoy.net/turtle/4823100ba2 // const poissonRadius = 10; // min=5, max=50, step=1 const angle = 0; // min=0, max=3, step=1 (Free, ∟, ∠, ⬡) const lines = []; const disc = PoissonDisc([[0,0]], poissonRadius); const points = disc.addPoints((300/poissonRadius) **2, 50, 0, 1); class lineSegment { constructor(center, delta, index) { this.index = index; this.center =[...center]; this.delta = [...delta]; this.end = add(center, scale(delta, 0.1)); this.turtle = new Turtle(center); this.done = false; } grow(dt, lines) { if (this.done) return; let end = add(this.end, scale(this.delta, dt)); let done = Math.abs(end[0]) > 100 || Math.abs(end[1]) > 100; lines.forEach( (line, index) => { if (index === this.index) return; const intersection = segment_intersect(this.end, end, line.start.end, line.end.end); if (intersection) { done = true; end = intersection; } }); this.done = done; this.turtle.goto(end); this.end = end; } } class line { constructor(center, delta, index) { this.start = new lineSegment(center, scale(delta, 1), index); this.end = new lineSegment(center, scale(delta, -1), index); } grow(dt, lines) { this.start.grow(dt, lines); this.end.grow(dt, lines); } } points.forEach( (point, i) => { const r = angle == 0 ? Math.random() : angle == 1 ? (Math.random() * 4 | 0) / 4 : angle == 2 ? (Math.random() * 8 | 0) / 8 : (Math.random() * 6 | 0) / 6; const a = r * Math.PI * 2; lines.push(new line(point, [Math.sin(a), Math.cos(a)], i)); }); function walk(i) { lines.forEach(line => line.grow(1, lines)); return lines.find(a => !a.start.done || !a.end.done); } //////////////////////////////////////////////////////////////// // Poisson-Disc utility code. Created by Reinder Nijhoff 2019 // https://turtletoy.net/turtle/b5510898dc //////////////////////////////////////////////////////////////// function PoissonDisc(startPoints, radius) { class PoissonDiscGrid { constructor(sp, radius) { this.cellSize = 1/Math.sqrt(2)/radius; this.radius2 = radius*radius; this.cells = []; sp.forEach( p => this.insert(p) ); } insert(p) { const x = p[0]*this.cellSize|0, y=p[1]*this.cellSize|0; for (let xi = x-1; xi<=x+1; xi++) { for (let yi = y-1; yi<=y+1; yi++) { const ps = this.cell(xi,yi); for (let i=0; i<ps.length; i++) { if ((ps[i][0]-p[0])**2 + (ps[i][1]-p[1])**2 < this.radius2) { return false; } } } } this.cell(x, y).push(p); return true; } cell(x,y) { const c = this.cells; return (c[x]?c[x]:c[x]=[])[y]?c[x][y]:c[x][y]=[]; } } class PoissonDisc { constructor(sp, radius) { this.result = [...sp]; this.active = [...sp]; this.grid = new PoissonDiscGrid(sp, radius); } addPoints(count, maxTries=16, loosePacking=0, randomGrowOrder=0) { mainLoop: while (this.active.length > 0 && count > 0) { const index = (Math.random() * this.active.length * randomGrowOrder) | 0; const point = this.active[index]; for (let i=0; i < maxTries; i++) { const a = Math.random() * 2 * Math.PI; const d = (Math.random()*loosePacking + 1) * radius; const p = [point[0] + Math.cos(a)*d, point[1] + Math.sin(a)*d, point]; if (this.grid.insert(p)) { this.result.push(p); this.active.push(p); count--; continue mainLoop; } } this.active.splice(index, 1); } return this.result; } } return new PoissonDisc(startPoints, radius); } //////////////////////////////////////////////////////////////// // 2D math functions //////////////////////////////////////////////////////////////// function scale(a,b) { return [a[0]*b,a[1]*b]; } function add(a,b) { return [a[0]+b[0],a[1]+b[1]]; } function segment_intersect(l1p1, l1p2, l2p1, l2p2) { const d = (l2p2[1] - l2p1[1]) * (l1p2[0] - l1p1[0]) - (l2p2[0] - l2p1[0]) * (l1p2[1] - l1p1[1]); if (d === 0) return false; const n_a = (l2p2[0] - l2p1[0]) * (l1p1[1] - l2p1[1]) - (l2p2[1] - l2p1[1]) * (l1p1[0] - l2p1[0]); const n_b = (l1p2[0] - l1p1[0]) * (l1p1[1] - l2p1[1]) - (l1p2[1] - l1p1[1]) * (l1p1[0] - l2p1[0]); const ua = n_a / d; const ub = n_b / d; if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) { return [l1p1[0] + ua * (l1p2[0] - l1p1[0]), l1p1[1] + ua * (l1p2[1] - l1p1[1])]; } return false; }