scripts/path-controller/curve/curve1d_base.js
import nstructjs from "../util/struct.js";
import * as util from '../util/util.js';
export const CurveConstructors = [];
export const CURVE_VERSION = 1.0;
export const CurveFlags = {
SELECT: 1
};
export const TangentModes = {
SMOOTH: 1,
BREAK : 2
};
export function getCurve(type, throw_on_error = true) {
for (let cls of CurveConstructors) {
if (cls.name === type)
return cls;
if (cls.define().name === type)
return cls;
}
if (throw_on_error) {
throw new Error("Unknown curve type " + type)
} else {
console.warn("Unknown curve type", type);
return getCurve("ease");
}
}
let _udigest = new util.HashDigest();
export class CurveTypeData {
constructor() {
this.type = this.constructor.define().typeName;
}
get hasGUI() {
throw new Error("get hasGUI(): implement me!");
}
static register(cls) {
if (cls.define === CurveTypeData.define) {
throw new Error("missing define() static method");
}
let def = cls.define();
if (!def.name) {
throw new Error(cls.name + ".define() result is missing 'name' field");
}
if (!def.typeName) {
throw new Error(cls.name + ".define() is missing .typeName, which should equal class name; needed for minificaiton");
}
CurveConstructors.push(cls);
}
static define() {
return {
uiname : "Some Curve",
name : "somecurve",
typeName: CurveTypeData
}
}
calcHashKey(digest = _udigest.reset()) {
let d = digest;
d.add(this.type);
return d.get();
}
toJSON() {
return {
type: this.type
}
}
equals(b) {
return this.type === b.type;
}
loadJSON(obj) {
this.type = obj.type;
return this;
}
redraw() {
if (this.parent)
this.parent.redraw();
}
makeGUI(container) {
}
killGUI(container) {
container.clear();
}
evaluate(s) {
throw new Error("implement me!");
}
integrate(s1, quadSteps = 64) {
let ret = 0.0, ds = s1/quadSteps;
for (let i = 0, s = 0; i < quadSteps; i++, s += ds) {
ret += this.evaluate(s)*ds;
}
return ret;
}
derivative(s) {
let df = 0.0001;
if (s > 1.0 - df*3) {
return (this.evaluate(s) - this.evaluate(s - df))/df;
} else if (s < df*3) {
return (this.evaluate(s + df) - this.evaluate(s))/df;
} else {
return (this.evaluate(s + df) - this.evaluate(s - df))/(2*df);
}
}
derivative2(s) {
let df = 0.0001;
if (s > 1.0 - df*3) {
return (this.derivative(s) - this.derivative(s - df))/df;
} else if (s < df*3) {
return (this.derivative(s + df) - this.derivative(s))/df;
} else {
return (this.derivative(s + df) - this.derivative(s - df))/(2*df);
}
}
inverse(y) {
let steps = 9;
let ds = 1.0/steps, s = 0.0;
let best = undefined;
let ret = undefined;
for (let i = 0; i < steps; i++, s += ds) {
let s1 = s, s2 = s + ds;
let mid;
for (let j = 0; j < 11; j++) {
let y1 = this.evaluate(s1);
let y2 = this.evaluate(s2);
mid = (s1 + s2)*0.5;
if (Math.abs(y1 - y) < Math.abs(y2 - y)) {
s2 = mid;
} else {
s1 = mid;
}
}
let ymid = this.evaluate(mid);
if (best === undefined || Math.abs(y - ymid) < best) {
best = Math.abs(y - ymid);
ret = mid;
}
}
return ret === undefined ? 0.0 : ret;
}
onActive(parent, draw_transform) {
}
onInactive(parent, draw_transform) {
}
reset() {
}
destroy() {
}
update() {
if (this.parent)
this.parent._on_change();
}
draw(canvas, g, draw_transform) {
}
loadSTRUCT(reader) {
reader(this);
}
}
CurveTypeData.STRUCT = `
CurveTypeData {
type : string;
}
`;
nstructjs.register(CurveTypeData);
export function evalHermiteTable(table, t) {
let s = t*(table.length/4);
let i = Math.floor(s);
s -= i;
i *= 4;
let a = table[i] + (table[i + 1] - table[i])*s;
let b = table[i + 2] + (table[i + 3] - table[i + 2])*s;
return a + (b - a)*s;
//return table[i] + (table[i + 3] - table[i])*s;
}
export function genHermiteTable(evaluate, steps) {
//console.log("building spline approx");
let table = new Array(steps);
let eps = 0.00001;
let dt = (1.0 - eps*4.001)/(steps - 1);
let t = eps*4;
let lastdv1, lastf3;
for (let j = 0; j < steps; j++, t += dt) {
//let f1 = evaluate(t - eps*2);
let f2 = evaluate(t - eps);
let f3 = evaluate(t);
let f4 = evaluate(t + eps);
//let f5 = evaluate(t + eps*2);
let dv1 = (f4 - f2)/(eps*2);
dv1 /= steps;
if (j > 0) {
let j2 = j - 1;
table[j2*4] = lastf3;
table[j2*4 + 1] = lastf3 + lastdv1/3.0;
table[j2*4 + 2] = f3 - dv1/3.0;
table[j2*4 + 3] = f3;
}
lastdv1 = dv1;
lastf3 = f3;
}
return table;
}