Skip to content

Commit

Permalink
bezier: geek out and write a general case
Browse files Browse the repository at this point in the history
Is this a bad idea? I think it is. But the high school math competition go-er in me demands it.
  • Loading branch information
Artoria2e5 authored and gka committed Jan 27, 2022
1 parent 5612043 commit a0245db
Showing 1 changed file with 24 additions and 10 deletions.
34 changes: 24 additions & 10 deletions src/generator/bezier.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ const Color = require('../Color');
require('../io/lab');
const scale = require('./scale');

// nth row of the pascal triangle
const binom_row = function(n) {
let row = [1, 1];
for (let i = 1; i < n; i++) {
let newrow = [1];
for (let j = 1; j <= row.length; j++) {
newrow[j] = (row[j] || 0) + row[j - 1];
}
row = newrow;
}
return row;
}

const bezier = function(colors) {
let I, lab0, lab1, lab2;
colors = colors.map(c => new Color(c));
Expand All @@ -32,18 +45,19 @@ const bezier = function(colors) {
const lab = ([0, 1, 2].map((i) => ((1-t)*(1-t)*(1-t) * lab0[i]) + (3 * (1-t) * (1-t) * t * lab1[i]) + (3 * (1-t) * t * t * lab2[i]) + (t*t*t * lab3[i])));
return new Color(lab, 'lab');
};
} else if (colors.length === 5) {
const I0 = bezier(colors.slice(0, 3));
const I1 = bezier(colors.slice(2, 5));
I = function(t) {
if (t < 0.5) {
return I0(t*2);
} else {
return I1((t-0.5)*2);
}
} else if (colors.length >= 5) {
// general case (degree n bezier)
let labs, row, n;
labs = colors.map(c => c.lab());
n = colors.length - 1
row = binom_row(n);
I = function (t) {
const u = 1 - t;
const lab = ([0, 1, 2].map((i) => labs.reduce((sum, el, j) => (sum + row[j] * u ** (n - 1) * t ** n * el[i]), 0)))
return new Color(lab, 'lab');
};
} else {
throw new RangeError("Bezier can only accept between 2 to 5 colors; got `${colors.length}`.")
throw new RangeError("No point in running bezier with only one color.")
}
return I;
};
Expand Down

0 comments on commit a0245db

Please sign in to comment.