1
0
mirror of https://github.com/Pomax/BezierInfo-2.git synced 2025-08-29 02:59:58 +02:00

full regeneration

This commit is contained in:
Pomax
2020-09-19 18:34:03 -07:00
parent ad872f83c5
commit 4c0e71cd4a
234 changed files with 1468 additions and 1376 deletions

View File

@@ -4,6 +4,7 @@ import { project, projectXY, projectXZ, projectYZ } from "./projection.js";
let d, cube;
setup() {
// We have the same setup as for the previous graphic
d = this.width/2 + 25;
cube = [
{x:0, y:0, z:0},
@@ -71,6 +72,7 @@ drawCurveProjections() {
}
drawPoint(t) {
// The only thing different compared to the previous graphic is this call:
const {o, r, n, dt } = this.getRMF(t, this.points);
setStroke(`red`);
@@ -102,75 +104,6 @@ drawCubeFront() {
line(c[7].x, c[7].y, c[4].x, c[4].y);
}
getRMF(t, originalPoints) {
const curve = new Bezier(this, originalPoints);
const d1curve = new Bezier(this, curve.dpoints[0]);
if (!this.rmf_LUT) {
this.rmf_LUT = this.generateRMF(originalPoints, curve, d1curve);
}
// find the frame for "t".
const last = this.rmf_LUT.length - 1;
const f = t * last;
const i = Math.floor(f);
// intenger index, or last index: we're done.
if (f === i) return this.rmf_LUT[i];
// no integer index: interpolate based on the adjacent frames.
const j = i + 1, ti = i/last, tj = j/last, ratio = (t - ti) / (tj - ti);
return this.lerpFrames(ratio, this.rmf_LUT[i], this.rmf_LUT[j]);
}
generateRMF(originalPoints, curve, d1curve) {
const frames = []
frames.push(this.getFrenetVectors(0, originalPoints));
for(let i=0, steps=24; i<steps; i++) {
const x0 = frames[i],
// get the next frame
t = (i+1)/steps,
x1 = {
o: curve.get(t),
dt: d1curve.get(t)
},
// then mirror the rotational axis and tangent
v1 = vec.minus(x1.o, x0.o),
c1 = vec.dot(v1, v1),
riL = vec.minus(x0.r, vec.scale(v1, 2/c1 * vec.dot(v1, x0.r))),
dtiL = vec.minus(x0.dt, vec.scale(v1, 2/c1 * vec.dot(v1, x0.dt))),
// and use those to compute a more stable rotational axis
v2 = vec.minus(x1.dt, dtiL),
c2 = vec.dot(v2, v2);
x1.r = vec.minus(riL, vec.scale(v2, 2/c2 * vec.dot(v2, riL)));
// and with that stable axis, a new normal.
x1.n = vec.cross(x1.r, x1.dt);
frames.push(x1);
}
return frames;
}
getFrenetVectors(t, originalPoints) {
const curve = new Bezier(this, originalPoints);
const d1curve = new Bezier(this, curve.dpoints[0]);
const dt = d1curve.get(t);
const ddt = d1curve.derivative(t);
const o = curve.get(t);
const b = vec.normalize(vec.plus(dt, ddt));
const r = vec.normalize(vec.cross(b, dt));
const n = vec.normalize(vec.cross(r, dt));
return { o, dt, r, n };
}
lerpFrames(t, f1, f2) {
var frame = {};
[`o`, `dt`, `r`, `n`].forEach(type => frame[type] = vec.lerp(t, f1[type], f2[type]));
return frame;
}
drawVector(from, vec, length, color, label) {
setStroke(color);
setFill(`black`);
@@ -189,3 +122,78 @@ drawVector(from, vec, length, color, label) {
});
text(label, from.x + txt.x, from.y + txt.y);
}
// This is where things are... rather different
getRMF(t, originalPoints) {
// If we don't have a rotation-minimizing lookup table, build it.
if (!this.rmf_LUT) {
const curve = new Bezier(this, originalPoints);
const d1curve = new Bezier(this, curve.dpoints[0]);
this.rmf_LUT = this.generateRMF(originalPoints, curve, d1curve);
}
// find the frame for "t":
const last = this.rmf_LUT.length - 1;
const f = t * last;
const i = Math.floor(f);
// If we're looking at an integer index, we're done.
if (f === i) return this.rmf_LUT[i];
// If we're not, we need to interpolate the adjacent frames
const j = i + 1, ti = i/last, tj = j/last, ratio = (t - ti) / (tj - ti);
return this.lerpFrames(ratio, this.rmf_LUT[i], this.rmf_LUT[j]);
}
generateRMF(originalPoints, curve, d1curve) {
// Start with the frenet frame just before t=0 and shift it to t=0
const first = this.getFrenetVectors(-0.001, originalPoints);
first.o = curve.get(0);
// Then we construct each next rotation-minimizing fame by reflecting
// the previous frame and correcting the resulting vectors.
const frames = [first];
for(let i=0, steps=24; i<steps; i++) {
const x0 = frames[i],
// get the next frame
t = (i+1)/steps,
x1 = {
o: curve.get(t),
dt: d1curve.get(t)
},
// then mirror the rotational axis and tangent
v1 = vec.minus(x1.o, x0.o),
c1 = vec.dot(v1, v1),
riL = vec.minus(x0.r, vec.scale(v1, 2/c1 * vec.dot(v1, x0.r))),
dtiL = vec.minus(x0.dt, vec.scale(v1, 2/c1 * vec.dot(v1, x0.dt))),
// then use those to compute a more stable rotational axis
v2 = vec.minus(x1.dt, dtiL),
c2 = vec.dot(v2, v2);
// Fix the axis of rotation vector...
x1.r = vec.minus(riL, vec.scale(v2, 2/c2 * vec.dot(v2, riL)));
// ... and then compute the normal as usual
x1.n = vec.cross(x1.r, x1.dt);
frames.push(x1);
}
return frames;
}
getFrenetVectors(t, originalPoints) {
const curve = new Bezier(this, originalPoints),
d1curve = new Bezier(this, curve.dpoints[0]),
dt = d1curve.get(t),
ddt = d1curve.derivative(t),
o = curve.get(t),
b = vec.normalize(vec.plus(dt, ddt)),
r = vec.normalize(vec.cross(b, dt)),
n = vec.normalize(vec.cross(r, dt));
return { o, dt, r, n };
}
lerpFrames(t, f1, f2) {
var frame = {};
[`o`, `dt`, `r`, `n`].forEach(type => frame[type] = vec.lerp(t, f1[type], f2[type]));
return frame;
}