1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-03 23:37:48 +02:00
Files
BezierInfo-2/components/sections/reordering/handler.js
bhegerle cc2a505cba Section on curve order raising/lowering (#211)
* edit to second curve order-raising derivation

* bug fix for curve order-lowering: could invert MtM because it had extra column of zeroes
2019-08-27 08:46:01 -07:00

151 lines
3.4 KiB
JavaScript

var invert = require('../../../lib/matrix-invert.js');
var multiply = require('../../../lib/matrix-multiply.js');
var transpose = require('../../../lib/matrix-transpose.js');
var Reordering = {
statics: {
keyHandlingOptions: {
values: {
"38": function(api) {
api.setCurve(api.curve.raise());
api.redraw();
},
"40": function(api) {
api.setCurve(Reordering.lower(api));
api.redraw();
}
}
}
},
// Based on http://www.sirver.net/blog/2011/08/23/degree-reduction-of-bezier-curves/
lower: function(api) {
var curve = api.curve,
pts = curve.points,
k = pts.length,
M = [],
n = k-1,
i;
// build M, which will be (k) rows by (k-1) columns
for(i=0; i<k; i++) {
M[i] = (new Array(k - 1)).fill(0);
if(i===0) { M[i][0] = 1; }
else if(i===n) { M[i][i-1] = 1; }
else {
M[i][i-1] = i / k;
M[i][i] = 1 - M[i][i-1];
}
}
// then, apply our matrix operations:
var Mt = transpose(M);
var Mc = multiply(Mt, M);
var Mi = invert(Mc);
if (!Mi) {
console.error('MtM has no inverse?');
return curve;
}
var V = multiply(Mi, Mt);
// And then we map our k-order list of coordinates
// to an n-order list of coordinates, instead:
var x = pts.map(p => [p.x]);
var nx = multiply(V, x);
var y = pts.map(p => [p.y]);
var ny = multiply(V, y);
var npts = nx.map((x,i) => {
return {
x: x[0],
y: ny[i][0]
};
});
return new api.Bezier(npts);
},
getInitialState: function() {
return {
order: 0
};
},
setup: function(api) {
var points = [];
var w = api.getPanelWidth(),
h = api.getPanelHeight();
for (var i=0; i<10; i++) {
points.push({
x: w/2 + (Math.random() * 20) + Math.cos(Math.PI*2 * i/10) * (w/2 - 40),
y: h/2 + (Math.random() * 20) + Math.sin(Math.PI*2 * i/10) * (h/2 - 40)
});
}
var curve = new api.Bezier(points);
api.setCurve(curve);
},
draw: function(api, curve) {
api.reset();
var pts = curve.points;
this.setState({
order: pts.length
});
var p0 = pts[0];
// 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:
for(var t=0; t<=1; t+=0.01) {
var q = JSON.parse(JSON.stringify(pts));
while(q.length > 1) {
for (var i=0; i<q.length-1; i++) {
q[i] = {
x: q[i].x + (q[i+1].x - q[i].x) * t,
y: q[i].y + (q[i+1].y - q[i].y) * t
};
}
q.splice(q.length-1, 1);
}
api.drawLine(p0, q[0]);
p0 = q[0];
}
p0 = pts[0];
api.setColor("black");
api.drawCircle(p0,3);
pts.forEach(p => {
if(p===p0) return;
api.setColor("#DDD");
api.drawLine(p0,p);
api.setColor("black");
api.drawCircle(p,3);
p0 = p;
});
},
getOrder: function() {
var order = this.state.order;
if (order%10 === 1 && order !== 11) {
order += "st";
} else if (order%10 === 2 && order !== 12) {
order += "nd";
} else if (order%10 === 3 && order !== 13) {
order += "rd";
} else {
order += "th";
}
return order;
},
onMouseMove: function(evt, api) {
api.redraw();
}
};
module.exports = Reordering;