let points = []; setup() { const w = this.width, h = this.height; // let's create a wiggle-circle by randomizing points on a circle for (let i=0; i<10; i++) { points.push({ x: w/2 + random(20) + cos(PI*2 * i/10) * (w/2 - 40), y: h/2 + random(20) + sin(PI*2 * i/10) * (h/2 - 40) }); } setMovable(points); this.bindButtons(); } bindButtons() { let rbutton = find(`.raise`); if (rbutton) rbutton.listen(`click`, v => this.raise()); let lbutton = find(`.lower`); if (lbutton) lbutton.listen(`click`, v => this.lower()); } draw() { clear(); this.drawCurve(); } drawCurve() { // we can't "just draw" this curve, since it'll be an arbitrary order, // And the canvas only does 2nd and 3rd - we use de Casteljau's algorithm: start(); noFill(); setStroke(`black`); for(let t=0; t<=1; t+=0.01) { let q = JSON.parse(JSON.stringify(points)); while(q.length > 1) { for (let i=0; i vertex(p.x, p.y)); end(); setStroke(`black`); points.forEach(p => circle(p.x, p.y, 3)); } raise() { const p = points, np = [p[0]], k = p.length; // raising the order of a curve is lossless: for (let i = 1, pi, pim; i < k; i++) { pi = p[i]; pim = p[i - 1]; np[i] = { x: ((k - i) / k) * pi.x + (i / k) * pim.x, y: ((k - i) / k) * pi.y + (i / k) * pim.y, }; } np[k] = p[k - 1]; points = np; resetMovable(points); redraw(); } lower() { // Based on https://www.sirver.net/blog/2011/08/23/degree-reduction-of-bezier-curves/ // TODO: FIXME: this is the same code as in the old codebase, // and it does something odd to the either the // first or last point... it starts to travel // A LOT more than it looks like it should... O_o const p = points, k = p.length, data = [], n = k-1; if (k <= 3) return; // build M, which will be (k) rows by (k-1) columns for(let i=0; i [p.x])); const nx = V.multiply(x); const y = new Matrix(points.map(p => [p.y])); const ny = V.multiply(y); points = nx.data.map((x,i) => ({ x: x[0], y: ny.data[i][0] })); resetMovable(points); redraw(); }