Flowers­čî╝

Generating some flowers

Collect as nft here hic.link/150958

Interesting variant:
- Flowers­čî╝ (variation)

Log in to post a comment.

const turtle = new Turtle();

const grid = 2; // min=1, max=7, step=1
const size = 7/8 * 200 / grid;
const flowerSize = 14 // min=5, max=50, step=1

let totalHatch = 100; // min=0, max=300, step=1
const innerSize = 0.9; // min=0, max=1, step=0.01

let totalLeaves = 7; // min=5, max=20, step=2
const leafSize = 3.2; // min=1, max=5, step=0.01
const leafDetail = 12; // min=5, max=75, step=1
const innerLeafLines = 1; // min=0.00, max=1, step=0.25

const getX = x => (grid%2==1) ? x - (grid*0.5|0) - 0.5 : x - (grid*0.5);
const getY = y => (grid%2==1) ? y - (grid*0.5|0) - 0.5 : y - (grid*0.5);

function walk(i) {
    const x = getX(i % grid);
    const y = getY(i / grid | 0);
    flower([x * size + size*0.5, y*size + size*0.5], flowerSize);
    return i < grid*grid-1;
}

function flower(pos, size) {
    // add circles 
    circle(pos,size);
    if (innerSize != 1) circle(pos,size * innerSize);
    
    const startAngle = Math.random() * Math.PI*2;
    
    // hatch lines in between rings of cirlce
    let hatchOverlap = 0.075;
    for(let i=0;i<totalHatch;i++) {
        const angle = startAngle + (i+0) / totalHatch * Math.PI*2;
        const a = add2(pos, fromAngle(angle, size * (innerSize - hatchOverlap)));
        const b = add2(pos, fromAngle(angle, size * (1 + hatchOverlap)));
        a[0] += (-0.5 * Math.random()) * size * 0.1;
        a[1] += (-0.5 * Math.random()) * size * 0.1;
        b[0] += (-0.5 * Math.random()) * size * 0.1;
        b[1] += (-0.5 * Math.random()) * size * 0.1;
        turtle.jump(a);
        turtle.goto(b);
    }
    
    // Dots in flower. based on "Voronoi Spiral" by Reinder https://turtletoy.net/turtle/70b4fd8c25
    for (let i=0; i<300; i++) {
        const ratio = 0.38196601125;
        const r = 4 * Math.sqrt(i);
        const a = i * 2 * Math.PI * ratio;
        const x = Math.cos(a)*r;
        const y = Math.sin(a)*r;
        circle(add2(pos, [x*size*0.014*innerSize, y*size*0.014*innerSize]), size * 0.0185);
    }
    
    // make amount of leaves less precise on bigger grid
    if (grid > 0 && totalLeaves > 6) {
        totalLeaves += (-2+Math.random()*4) | 0;
    }
    
    // Draw leaves
    for(let i=0;i<totalLeaves;i++) {
        const angle1 = startAngle + (i+0) / totalLeaves * Math.PI*2;
        const leafAngle = startAngle + (i+0.5) / totalLeaves * Math.PI*2;
        const angle2 = startAngle + (i+1) / totalLeaves * Math.PI*2;
        
        const pos1 = add2(pos, fromAngle(angle1, size));
        const pos2 = add2(pos, fromAngle(angle2, size));
        const leafStart = add2(pos, fromAngle(leafAngle, size));
        const leafTip = add2(pos, fromAngle(leafAngle, size * leafSize));
        
        const r2 = Math.random();
        const r3 =Math.random();
      
        turtle.jump(pos1);
        for (let l=0;l<leafDetail;l++) {
            const t = l/(leafDetail-1);
            let tx = (1-t)*0.5;
            const p = lerpPath(pos1, leafTip, t, tx); // TODO
            turtle.goto(p);
        }
        
        turtle.jump(leafTip);
        for (let l=0;l<leafDetail;l++) {
            const t = l/(leafDetail-1);
            let tx = pingpong((1-t)*0.25)*r2;
            tx = t*0.5;
            const p = lerpPath(leafTip, pos2 , t, tx); 
            turtle.goto(p);
        }
        
        // inner leaf line 1
        turtle.jump(leafStart);
        for (let l=0;l<leafDetail * innerLeafLines;l++) {
            const t = l/(leafDetail-1);
            let tx = t*0.25*r3;
            const p = lerpPath(leafStart, leafTip, t, tx);
            turtle.goto(p);
        }
        
        // inner leaf line 2
        turtle.jump(leafStart);
        for (let l=0;l<leafDetail * innerLeafLines;l++) {
            const t = l/(leafDetail-1);
            let tx = pingpong(t/15)*r3;
            const p = lerpPath(leafStart, leafTip, t, tx);
            turtle.goto(p);
        }
    }
}

function circle(pos, r = 1, segments = 20) {
    const {x, y} = pos;
    for(let i = 0; i <= segments; i++) {
        const angle = i/segments * Math.PI*2;
        const p = add2(pos, fromAngle(angle, r));
        if (i === 0) turtle.jump(p);
        else turtle.goto(p);
    }
}

function lerpPath(a,b, t, t2) {
    const diff = sub2(b,a);
    const randomize = 0.04; // min=0, max=0.1, step=0.001
    let tt = pingpong(randomized(t, randomize)) * t2;
    return add2(lerp2(a, b, t), scl([-diff[1], diff[0]], tt));
}

const scl = (a,s) => [a[0]*s, a[1]*s]; 
const scl2 = (a,b) => [a[0]*b[0], a[1]*b[1]]; 
const add2 = (a,b) => [a[0]+b[0], a[1]+b[1]];
const sub2 = (a,b) => [a[0]-b[0], a[1]-b[1]];
const dot2 = (a,b) => a[0]*b[0] + a[1]*b[1];
const atan2 = a => Math.atan2(-a[1],a[0]);
const len2 = a => Math.sqrt(a[0]*a[0]+a[1]*a[1]);
const nrm2 = a => scl(a, 1/len2(a));
const fromAngle = (a,r = 1.0) => [Math.sin(a)*r, Math.cos(a)*r];
const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
const clamp01 = v => clamp(v, 0, 1);
const pingpong = t => (t < 0.5 ? t : 1-t) * 2;
const randomized = (t, range = 0.1) => t + -range + Math.random() * (range*2);
const mod2 = v => (v%2==0) ? v%1 : 1-((v-0.5)%1)
const lerp = (a,b,t) => a+(b-a)*t;
const lerp2 = (a,b,tx, ty=tx) => [lerp(a[0],b[0],tx), lerp(a[1],b[1],ty)];