1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-25 17:42:46 +02:00
This commit is contained in:
Pomax
2020-09-05 22:50:12 -07:00
parent bec07e3297
commit 9434a71d34
46 changed files with 1795 additions and 1623 deletions

View File

@@ -1,5 +1,6 @@
import { enrich } from "../lib/enrich.js";
import { Bezier } from "./types/bezier.js";
import { BSpline } from "./types/bspline.js";
import { Vector } from "./types/vector.js";
import { Matrix } from "./types/matrix.js";
import { Shape } from "./util/shape.js";
@@ -791,4 +792,4 @@ class GraphicsAPI extends BaseAPI {
}
}
export { GraphicsAPI, Bezier, Vector, Matrix, Shape };
export { GraphicsAPI, Bezier, BSpline, Vector, Matrix, Shape };

View File

@@ -0,0 +1,85 @@
import interpolate from "../util/spline.js";
// cubic B-Spline
const DEGREE = 3;
class BSpline {
constructor(apiInstance, points) {
this.api = apiInstance;
this.ctx = apiInstance.ctx;
// the spline library needs points in array format [x,y] rather than object format {x:..., y:...}
this.points = points.map((v) => {
if (v instanceof Array) return v;
return [v.x, v.y];
});
}
getLUT(count) {
let c = count - 1;
return [...new Array(count)].map((_, i) => {
let p = interpolate(i / c, DEGREE, this.points, this.knots, this.weights);
return { x: p[0], y: p[1] };
});
}
formKnots(open = false) {
if (!open) return this.formUniformKnots();
let knots = [],
l = this.points.length,
m = l - DEGREE;
// form the open-uniform knot vector
for (let i = 1; i < l - DEGREE; i++) {
knots.push(i + DEGREE);
}
// add [degree] zeroes at the front
for (let i = 0; i <= DEGREE; i++) {
knots = [DEGREE].concat(knots);
}
// add [degree] max-values to the back
for (let i = 0; i <= DEGREE; i++) {
knots.push(m + DEGREE);
}
return (this.knots = knots);
}
formUniformKnots() {
return (this.knots = [...new Array(this.points.length + DEGREE + 1)].map(
(_, i) => i
));
}
formNodes() {
const knots = this.knots;
const domain = [DEGREE, knots.length - 1 - DEGREE],
nodes = [];
for (let k = 0; k < this.points.length; k++) {
let node = 0;
for (let offset = 1; offset <= DEGREE; offset++) {
node += knots[k + offset];
}
node /= DEGREE;
if (node < knots[domain[0]]) continue;
if (node > knots[domain[1]]) continue;
nodes.push(node);
}
return (this.nodes = nodes);
}
formWeights() {
return (this.weights = this.points.map((p) => 1));
}
setDegree(d) {
DEGREE += d;
this.knots = this.formKnots();
this.nodes = this.formNodes();
}
}
export { BSpline };

View File

@@ -0,0 +1,88 @@
// https://github.com/thibauts/b-spline
export default function interpolate(
t,
degree,
points,
knots,
weights,
result,
scaled
) {
var i, j, s, l; // function-scoped iteration variables
var n = points.length; // points count
var d = points[0].length; // point dimensionality
if (degree < 1) throw new Error("degree must be at least 1 (linear)");
if (degree > n - 1)
throw new Error("degree must be less than or equal to point count - 1");
if (!weights) {
// build weight vector of length [n]
weights = [];
for (i = 0; i < n; i++) {
weights[i] = 1;
}
}
if (!knots) {
// build knot vector of length [n + degree + 1]
var knots = [];
for (i = 0; i < n + degree + 1; i++) {
knots[i] = i;
}
} else {
if (knots.length !== n + degree + 1)
throw new Error("bad knot vector length");
}
var domain = [degree, knots.length - 1 - degree];
var low = knots[domain[0]];
var high = knots[domain[1]];
// remap t to the domain where the spline is defined
if (!scaled) {
t = t * (high - low) + low;
}
if (t < low || t > high) throw new Error("out of bounds");
// find s (the spline segment) for the [t] value provided
for (s = domain[0]; s < domain[1]; s++) {
if (t >= knots[s] && t <= knots[s + 1]) {
break;
}
}
// convert points to homogeneous coordinates
var v = [];
for (i = 0; i < n; i++) {
v[i] = [];
for (j = 0; j < d; j++) {
v[i][j] = points[i][j] * weights[i];
}
v[i][d] = weights[i];
}
// l (level) goes from 1 to the curve degree + 1
var alpha;
for (l = 1; l <= degree + 1; l++) {
// build level l of the pyramid
for (i = s; i > s - degree - 1 + l; i--) {
alpha = (t - knots[i]) / (knots[i + degree + 1 - l] - knots[i]);
// interpolate each component
for (j = 0; j < d + 1; j++) {
v[i][j] = (1 - alpha) * v[i - 1][j] + alpha * v[i][j];
}
}
}
// convert back to cartesian and return
var result = result || [];
for (i = 0; i < d; i++) {
result[i] = v[s][i] / v[s][d];
}
return result;
}

View File

@@ -207,7 +207,7 @@ class GraphicsElement extends CustomElement {
* Program source: ${src}
* Data attributes: ${JSON.stringify(this.dataset)}
*/
import { GraphicsAPI, Bezier, Vector, Matrix, Shape } from "${MODULE_PATH}/api/graphics-api.js";
import { GraphicsAPI, Bezier, BSpline, Vector, Matrix, Shape } from "${MODULE_PATH}/api/graphics-api.js";
${globalCode}