Dyson Hatching

Dyson hatching (dysonlogos.blog/), based on a blog-post by Oleg Dolya (patreon.com/posts/hatching-in-1pdg-31716880).

A complete Dungeon Generator is next ;-)

#hatching #possion-disc

Log in to post a comment.

// Dyson  Hatching. Created by Reinder Nijhoff 2019 - @reindernijhoff
// The MIT License
//
// https://turtletoy.net/turtle/0422c2a17f
//

const hatchRadius = 2; // min=1, max=5, step=.1
const hatchLength = 2.5; // min=1, max=5, step=.1
const hatchWidth = 1.6; // min=1, max=5, step=.1
const hatchLines = 3; // min=2, max=5, step=1
const maxGrowIterations = 15000;

const turtle = new Turtle();
const disc = new PoissonDisc([[0,0]], hatchRadius);

function walk(i) {
    const points = disc.addPoints(1, 32, 0, 1);
    hatch(turtle, points[points.length-1], hatchLines, hatchLength, hatchWidth);
    return i < maxGrowIterations;
}

function hatch(t, p, n, l, w) {
    if (Math.abs(p[0]) > 75 || Math.abs(p[1]) > 75) return;
    
    const a = Math.random() * 2 * Math.PI;
    const c = Math.cos(a), s = Math.sin(a);
    
    for (let i=0; i<n; i++) {
        const o = scl([s,-c], (i/(n-1)-.5) * w);
        t.jump(add(o,add(p, scl([c,s], l*.5))));
        t.goto(add(o,add(p, scl([-c,-s], l*.5))));
    }
}

function add(a, b) { return [a[0]+b[0], a[1]+b[1]]; }
function scl(a, b) { return [a[0]*b, a[1]*b]; }

////////////////////////////////////////////////////////////////
// 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);
}