xxxxxxxxxx
192
function arcTo(cx, cy, r, from, to) {
for (let idx = 1; idx < 51; ++idx) {
const ang = map(idx, 0, 50, from, to);
vertex(cx + r * cos(ang), cy + r * sin(ang));
}
}
function fitArc(P, v, Q, rev) {
const w = p5.Vector.sub(Q, P);
const x = 0.5 * w.mag();
w.normalize();
// TODO: skip the trig
const theta = acos(v.dot(w));
const r = x / sin(theta);
const cx = P.x + r * v.y;
const cy = P.y - r * v.x;
/* console.log( r );
console.log( cx, cy );
console.log( "d1: " + dist( cx, cy, P.x, P.y ) );
console.log( "d2: " + dist( cx, cy, Q.x, Q.y ) );*/
const a = atan2(P.y - cy, P.x - cx);
const b = atan2(Q.y - cy, Q.x - cx);
if (rev) {
arcTo(cx, cy, r, b, a);
} else {
arcTo(cx, cy, r, a, b);
}
}
function petal(x, y) {
beginShape();
fitArc(createVector(-1, 0), createVector(0, 1), createVector(x, y), true);
arcTo(0, 0, 1, PI, TWO_PI);
fitArc(createVector(1, 0), createVector(0, 1), createVector(x, y), false);
endShape(CLOSE);
}
function flower( ccw ) {
push();
if( !ccw ) {
scale( -1, 1 );
}
petal( random(1,3), random(2,4) );
pop();
let choice = int(random(3)) + 1;
if( choice & 1 ) {
petal( random(2,4), random(1,3) );
}
if( choice & 2 ) {
push();
scale(-1,1);
petal( random(2,4), random(1,3) );
pop();
}
}
function spiral(cx, cy, r, fac, a1, a2, w1, w2) {
let res = [];
let wp = w1;
let ap = a1;
for (let idx = 0; idx < 50; ++idx) {
const t = (idx + 1) / 50.0;
const an = lerp(a1, a2, t);
const wn = lerp(w1, w2, t);
const x = cx + r * cos(an);
const y = cy + r * sin(an);
res.push([x, y, wn]);
beginShape();
vertex(cx + (r - wp) * cos(ap), cy + (r - wp) * sin(ap));
vertex(cx + (r + wp) * cos(ap), cy + (r + wp) * sin(ap));
r = r * fac;
vertex(cx + (r + wn) * cos(an), cy + (r + wn) * sin(an));
vertex(cx + (r - wn) * cos(an), cy + (r - wn) * sin(an));
endShape(CLOSE);
wp = wn;
ap = an;
}
return res;
}
function setup() {
createCanvas(400, 400);
seed = int(random(10000000));
}
function branch(x, y, dx, dy, ccw, sc, w) {
let pts;
if (ccw) {
const cx = x - (sc-w/2) * dy;
const cy = y + (sc-w/2) * dx;
const ang = atan2(y - cy, x - cx);
pts = spiral(
cx,
cy,
sc,
random(0.95, 0.99),
ang,
ang + random(PI, TWO_PI),
w,
w * random(0.2, 0.5)
);
} else {
const cx = x + (sc-w/2) * dy;
const cy = y - (sc-w/2) * dx;
const ang = atan2(y - cy, x - cx);
pts = spiral(
cx,
cy,
sc,
random(0.95, 0.99),
ang,
ang - random(PI, TWO_PI),
w,
w * random(0.2, 0.5)
);
}
const l = pts.length-1;
push();
translate( pts[l][0], pts[l][1] );
rotate( -HALF_PI + atan2( pts[l][1]-pts[l-1][1], pts[l][0]-pts[l-1][0] ) );
scale( sc * 0.1 );
translate( -0.9, 0 );
flower( ccw );
pop();
let num = 0;
if( random(1) < 0.6 ) {
++num;
if( random(1) < 0.5 ) {
++num;
}
}
for( let idx = 0; idx < num; ++idx ) {
// fork off a sub-branch
// const idx = int(pts.length*random(0.25,0.75));
let idx = int(pts.length*pow(random(0.1, 0.8),2));
idx = constrain(idx,1,pts.length-1);
const q = pts[idx];
const dx = q[0] - pts[idx-1][0];
const dy = q[1] - pts[idx-1][1];
const d = sqrt(dx*dx+dy*dy);
branch( q[0], q[1], dx/d, dy/d,
!ccw, sc * random( 0.5, 0.8 ), q[2] );
}
}
function draw() {
background(240);
push();
translate(width / 2, height / 2);
scale(20, -20);
noStroke();
fill(0);
const seed = int(random( Number.MAX_SAFE_INTEGER ));
randomSeed( seed );
branch(0, -4, 0, 1, true, 4, 0.2);
scale( -1, 1 );
randomSeed( seed );
branch(0, -4, 0, 1, true, 4, 0.2);
pop();
noLoop();
}
function keyPressed()
{
if( key == ' ' ) {
loop();
}
}