xxxxxxxxxx
192
let consts = {
size: 400,
zoom: 200,
theta: 0,
inputs: undefined,
hop_i: undefined,
hop_j: undefined,
hop_k: undefined,
sheet: undefined
}
let controls = {
A: 3,
B: 11,
pen: 0.9,
I: 2,
J: 1,
K: 24,
rollers: true,
dots: false,
digits: true,
shape3: true,
go: false,
speed: 0.005,
frames: 60,
alpha: 50,
haze: false
}
function pt(x, y) {
return [consts.zoom * (1 + x), consts.zoom * (1 - y)];
}
function circ(x, y, r) {
circle(pt(x, y), r * consts.size);
}
function update() {
let i_max = (controls.B - controls.A);
let j_max = controls.A;
let k_max = i_max * j_max;
consts.hop_i.max(i_max).updateDisplay();
consts.hop_j.max(j_max).updateDisplay();
consts.hop_k.max(k_max).updateDisplay();
consts.hop_k.setValue(k_max);
draw();
}
function setup() {
consts.size = select('#animation').width;
consts.zoom = consts.size/2;
createCanvas(consts.size, consts.size).parent('animation');
consts.sheet = createGraphics(consts.size, consts.size);
frameRate(controls.frames);
consts.inputs = new dat.GUI({autoPlace: false});
select('#controls').child(consts.inputs.domElement);
let proportions = consts.inputs.addFolder('Proportions:');
proportions.add(controls, 'A', 1, 21, 1).name('A').onChange(update);
proportions.add(controls, 'B', 1, 21, 1).name('B').onChange(update);
proportions.add(controls, 'pen', 0, 1.4, 0.05).onChange(draw);
proportions.open();
let shape = consts.inputs.addFolder('Shape:');
shape.add(controls, 'shape3', true).name('show').onChange(draw);
let C = controls.B - controls.A;
consts.hop_i = shape.add(controls, 'I', 0, C, 1).name('hop in B-A').onChange(draw);
consts.hop_j = shape.add(controls, 'J', 0, controls.A, 1).name('hop in A').onChange(draw);
consts.hop_k = shape.add(controls, 'K', 1, controls.A*C, 1).name('vertices').onChange(draw);
shape.open();
let show = consts.inputs.addFolder('Show/Hide:');
show.add(controls, 'rollers').name('circles').onChange(draw);
show.add(controls, 'dots').name('points').onChange(draw);
show.add(controls, 'digits').name('digits').onChange(draw);
show.add(controls, 'shape3').name('shape').onChange(draw);
show.open();
let effects = consts.inputs.addFolder('Effects:');
effects.add(controls, 'haze').name('echo');
effects.add(controls, 'speed',0.001,0.05,0.001).name('speed');
effects.add(controls, 'frames', 1, 100, 1).name('frame rate')
.onChange(()=>frameRate(controls.frames));
effects.add(controls, 'alpha', 0, 100).name('alpha');
effects.add(controls, 'go').name('pause').onChange(draw);
textAlign(CENTER, CENTER);
noLoop();
}
function roller_pts(A, B, pen, theta) {
let rollers = [];
if(B <= A) return rollers;
let gamma = theta * (1-B/A);
for(let i = 0, ang = TAU/(B-A); i < (B-A); i++) {
let x1 = (1-A/B) * cos(ang*i + theta);
let y1 = (1-A/B) * sin(ang*i + theta);
let points = [];
for(let j = 0, ang = TAU/A; j < A; j++) {
let x2 = pen * A/B * cos(ang*j + gamma + PI);
let y2 = pen * A/B * sin(ang*j + gamma + PI);
points.push({x:x1+x2, y:y1+y2});
}
rollers.push({x:x1, y:y1, pts:points});
}
return rollers;
}
function center_pts(A, B, pen, theta) {
let center = [];
if(B <= A) return {r:0, pts:[]};
let C = B - 2*A;
let gamma = theta * (1+B/C);
let r = (1 - 2*A/B);
for(let i = 0, ang = TAU/C; i < abs(C); i++) {
let x = r * pen * cos(i*ang + gamma);
let y = r * pen * sin(i*ang + gamma);
center.push({x: x, y: y});
}
return {r:r, pts:center};
}
function draw() {
let rollers = roller_pts(controls.A, controls.B, controls.pen, consts.theta);
let center = center_pts(controls.A, controls.B, controls.pen, consts.theta);
background(245);
if(!rollers.length) return;
// Rollers option
if(controls.rollers) {
window.fill(250).noStroke();
circ(0, 0, 1);
fill(0, 10);
for(let r of rollers) circ(r.x, r.y, controls.A/controls.B);
circ(0, 0, center.r);
}
// Digits option
if(controls.digits) {
window.noStroke().fill(100);
for(let i = 0; i < rollers.length; i++) {
let r = rollers[i];
window.textSize(12).text(i+'', pt(r.x, r.y)).textSize(9);
for(let j = 0; j < r.pts.length; j++)
text(j+'', pt(r.pts[j].x, r.pts[j].y));
}
fill(255, 0, 0);
for(let i = 0; i < center.pts.length; i++)
text(''+i, pt(center.pts[i].x, center.pts[i].y));
}
if(controls.haze) {
consts.sheet.background(0, controls.alpha).stroke('firebrick');
} else {
consts.sheet.clear().stroke(0);
}
// Dots option
if(controls.dots && !controls.digits) {
consts.sheet.strokeWeight(3);
for(let r of rollers) for(let p of r.pts)
consts.sheet.point(pt(p.x, p.y));
stroke(255, 0, 0);
for(let p of center.pts)
consts.sheet.point(pt(p.x, p.y));
}
// Shapes option
if(controls.shape3) {
consts.sheet.strokeWeight(0.5).noFill();
let i = 0, j = 0, k = 0;
let C = controls.B - controls.A;
consts.sheet.beginShape();
while(true) {
let x = rollers[i].pts[j].x;
let y = rollers[i].pts[j].y;
consts.sheet.vertex(pt(x, y));
j = (j + controls.J) % controls.A;
i = (i + controls.I) % C;
k = k + 1;
if(k == controls.K) break;
}
consts.sheet.endShape(CLOSE);
}
image(consts.sheet, 0, 0);
controls.go ? noLoop() : loop();
consts.theta += controls.speed;
}