From 301a23b1e02e8fd866aeaa34b0fc13c82d41685a Mon Sep 17 00:00:00 2001 From: Alexander Rose <alexander.rose@weirdbyte.de> Date: Sun, 25 Aug 2019 21:42:07 -0700 Subject: [PATCH] refactored cellpack curve to resuse Vec3 objects --- src/apps/viewer/extensions/cellpack/curve.ts | 159 +++++++++++-------- 1 file changed, 97 insertions(+), 62 deletions(-) diff --git a/src/apps/viewer/extensions/cellpack/curve.ts b/src/apps/viewer/extensions/cellpack/curve.ts index aeda0b1ea..011d2dd15 100644 --- a/src/apps/viewer/extensions/cellpack/curve.ts +++ b/src/apps/viewer/extensions/cellpack/curve.ts @@ -14,31 +14,35 @@ interface Frame { s: Vec3, } -function CubicInterpolate(y0: Vec3, y1: Vec3, y2: Vec3, y3: Vec3, mu: number): Vec3 { - const out = Vec3.zero() +const a0Tmp = Vec3() +const a1Tmp = Vec3() +const a2Tmp = Vec3() +const a3Tmp = Vec3() +function CubicInterpolate(out: Vec3, y0: Vec3, y1: Vec3, y2: Vec3, y3: Vec3, mu: number): Vec3 { const mu2 = mu * mu; - const a0 = Vec3() - const a1 = Vec3() - const a2 = Vec3() - const a3 = Vec3() - Vec3.sub(a0, y3, y2) - Vec3.sub(a0, a0, y0) - Vec3.add(a0, a0, y1) + Vec3.sub(a0Tmp, y3, y2) + Vec3.sub(a0Tmp, a0Tmp, y0) + Vec3.add(a0Tmp, a0Tmp, y1) - Vec3.sub(a1, y0, y1) - Vec3.sub(a1, a1, a0) + Vec3.sub(a1Tmp, y0, y1) + Vec3.sub(a1Tmp, a1Tmp, a0Tmp) - Vec3.sub(a2, y2, y0) + Vec3.sub(a2Tmp, y2, y0) - Vec3.copy(a3, y1) + Vec3.copy(a3Tmp, y1) - out[0] = a0[0] * mu * mu2 + a1[0] * mu2 + a2[0] * mu + a3[0] - out[1] = a0[1] * mu * mu2 + a1[1] * mu2 + a2[1] * mu + a3[1] - out[2] = a0[2] * mu * mu2 + a1[2] * mu2 + a2[2] * mu + a3[2] + out[0] = a0Tmp[0] * mu * mu2 + a1Tmp[0] * mu2 + a2Tmp[0] * mu + a3Tmp[0] + out[1] = a0Tmp[1] * mu * mu2 + a1Tmp[1] * mu2 + a2Tmp[1] * mu + a3Tmp[1] + out[2] = a0Tmp[2] * mu * mu2 + a1Tmp[2] * mu2 + a2Tmp[2] * mu + a3Tmp[2] return out } +const cp0 = Vec3() +const cp1 = Vec3() +const cp2 = Vec3() +const cp3 = Vec3() +const currentPosition = Vec3() function ResampleControlPoints(points: NumberArray, segmentLength: number) { const nP = points.length / 3 // insert a point at the end and at the begining @@ -50,23 +54,28 @@ function ResampleControlPoints(points: NumberArray, segmentLength: number) { // resampledControlPoints.Add(controlPoints[1]); let idx = 1 - let currentPosition = Vec3.create(points[idx * 3], points[idx * 3 + 1], points[idx * 3 + 2]) + // const currentPosition = Vec3.create(points[idx * 3], points[idx * 3 + 1], points[idx * 3 + 2]) + Vec3.fromArray(currentPosition, points, idx * 3) let lerpValue = 0.0 // Normalize the distance between control points while (true) { if (idx + 2 >= nP) break - const cp0 = Vec3.create(points[(idx-1)*3], points[(idx-1)*3+1], points[(idx-1)*3+2]) // controlPoints[currentPointId - 1]; - const cp1 = Vec3.create(points[idx*3], points[idx*3+1], points[idx*3+2]) // controlPoints[currentPointId]; - const cp2 = Vec3.create(points[(idx+1)*3], points[(idx+1)*3+1], points[(idx+1)*3+2]) // controlPoints[currentPointId + 1]; - const cp3 = Vec3.create(points[(idx+2)*3], points[(idx+2)*3+1], points[(idx+2)*3+2]); // controlPoints[currentPointId + 2]; + Vec3.fromArray(cp0, points, (idx - 1) * 3) + Vec3.fromArray(cp1, points, idx * 3) + Vec3.fromArray(cp2, points, (idx + 1) * 3) + Vec3.fromArray(cp3, points, (idx + 2) * 3) + // const cp0 = Vec3.create(points[(idx-1)*3], points[(idx-1)*3+1], points[(idx-1)*3+2]) // controlPoints[currentPointId - 1]; + // const cp1 = Vec3.create(points[idx*3], points[idx*3+1], points[idx*3+2]) // controlPoints[currentPointId]; + // const cp2 = Vec3.create(points[(idx+1)*3], points[(idx+1)*3+1], points[(idx+1)*3+2]) // controlPoints[currentPointId + 1]; + // const cp3 = Vec3.create(points[(idx+2)*3], points[(idx+2)*3+1], points[(idx+2)*3+2]); // controlPoints[currentPointId + 2]; let found = false for (; lerpValue <= 1; lerpValue += 0.01) { // lerp?slerp // let candidate:Vec3 = Vec3.lerp(Vec3.zero(), cp0, cp1, lerpValue); // const candidate:Vec3 = Vec3.bezier(Vec3.zero(), cp0, cp1, cp2, cp3, lerpValue); - const candidate = CubicInterpolate(cp0, cp1, cp2, cp3, lerpValue) + const candidate = CubicInterpolate(Vec3(), cp0, cp1, cp2, cp3, lerpValue) const d = Vec3.distance(currentPosition, candidate); if (d > segmentLength) { resampledControlPoints.push(candidate) @@ -83,6 +92,12 @@ function ResampleControlPoints(points: NumberArray, segmentLength: number) { return resampledControlPoints } + +const prevV = Vec3() +const tmpV1 = Vec3() +const tmpV2 = Vec3() +const tmpV3 = Vec3() + // easier to align to theses normals function GetSmoothNormals(points: Vec3[]) { const nP: number = points.length; @@ -92,79 +107,99 @@ function GetSmoothNormals(points: Vec3[]) { smoothNormals.push(Vec3.normalize(Vec3(), points[i])) return smoothNormals; } - let p0 = Vec3.copy(Vec3(), points[0]) // undefined? - let p1 = Vec3.copy(Vec3(), points[1]) - let p2 = Vec3.copy(Vec3(), points[2]) - const p21 = Vec3.sub(Vec3(), p2, p1) - const p01 = Vec3.sub(Vec3(), p0, p1) - const p0121 = Vec3.cross(Vec3(), p01, p21) - let last = Vec3.normalize(Vec3(), p0121) - smoothNormals.push(last) + let p0 = points[0] + let p1 = points[1] + let p2 = points[2] + const p21 = Vec3.sub(tmpV1, p2, p1) + const p01 = Vec3.sub(tmpV2, p0, p1) + const p0121 = Vec3.cross(tmpV3, p01, p21) + Vec3.normalize(prevV, p0121) + smoothNormals.push(Vec3.clone(prevV)) for (let i = 1; i < points.length - 1; ++i) { p0 = points[i - 1] p1 = points[i] p2 = points[i + 1] - const t = Vec3.normalize(Vec3(), Vec3.sub(Vec3(), p2 , p0)) - const b = Vec3.normalize(Vec3(), Vec3.cross(Vec3(), t, last)) - let n = Vec3.normalize(Vec3(), Vec3.cross(Vec3(), t, b)) - n = Vec3.scale(n, n, -1.0) - last = Vec3.copy(last, n) + const t = Vec3.normalize(tmpV1, Vec3.sub(tmpV1, p2 , p0)) + const b = Vec3.normalize(tmpV2, Vec3.cross(tmpV2, t, prevV)) + const n = Vec3.normalize(Vec3(), Vec3.cross(tmpV3, t, b)) + Vec3.negate(n, n) + Vec3.copy(prevV, n) smoothNormals.push(n) } - last = Vec3.normalize(Vec3(), Vec3.cross(Vec3(), Vec3.sub(Vec3(), points[nP - 3], points[nP-2]), Vec3.sub(Vec3(), points[nP-2] , points[nP-1]))) + const last = Vec3() + Vec3.normalize(last, Vec3.cross(last, + Vec3.sub(tmpV1, points[nP - 3], points[nP-2]), + Vec3.sub(tmpV2, points[nP-2] , points[nP-1])) + ) smoothNormals.push(last) return smoothNormals; } +const frameTmpV1 = Vec3() +const frameTmpV2 = Vec3() +const frameTmpV3 = Vec3() + function getFrame(reference: Vec3, tangent: Vec3) { - const t: Vec3 = Vec3.normalize(Vec3(), tangent); + const t = Vec3.normalize(Vec3(), tangent); // make reference vector orthogonal to tangent - const proj_r_to_t: Vec3 = Vec3.scale( - Vec3(), tangent, Vec3.dot(reference, tangent) / Vec3.dot(tangent, tangent) + const proj_r_to_t = Vec3.scale( + frameTmpV1, tangent, Vec3.dot(reference, tangent) / Vec3.dot(tangent, tangent) ) - const r: Vec3 = Vec3.normalize(Vec3(), Vec3.sub(Vec3(), reference , proj_r_to_t)) + const r = Vec3.normalize(Vec3(), Vec3.sub(frameTmpV2, reference, proj_r_to_t)) // make bitangent vector orthogonal to the others - const s: Vec3 = Vec3.normalize(Vec3(), Vec3.cross(Vec3(), t, r)) + const s = Vec3.normalize(Vec3(), Vec3.cross(frameTmpV3, t, r)) return { t, r, s } } +const mfTmpV1 = Vec3() +const mfTmpV2 = Vec3() +const mfTmpV3 = Vec3() +const mfTmpV4 = Vec3() +const mfTmpV5 = Vec3() +const mfTmpV6 = Vec3() +const mfTmpV7 = Vec3() +const mfTmpV8 = Vec3() +const mfTmpV9 = Vec3() + // easier to align to theses normals // https://github.com/bzamecnik/gpg/blob/master/rotation-minimizing-frame/rmf.py function GetMiniFrame(points: Vec3[], normals: Vec3[]) { const frames: Frame[] = []; - const t0: Vec3 = Vec3.normalize(Vec3(), Vec3.sub(Vec3(), points[1], points[0])) + const t0 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[1], points[0])) frames.push(getFrame(normals[0], t0)) for (let i = 0; i< points.length-2; ++i) { - const t2 = Vec3.normalize(Vec3(), Vec3.sub(Vec3(), points[i+2], points[i+1])) - const v1: Vec3 = Vec3.sub(Vec3(), points[i + 1], points[i]) // this is tangeant + const t2 = Vec3.normalize(mfTmpV1, Vec3.sub(mfTmpV1, points[i+2], points[i+1])) + const v1 = Vec3.sub(mfTmpV2, points[i + 1], points[i]) // this is tangeant const c1 = Vec3.dot(v1, v1) // compute r_i^L = R_1 * r_i - const v1r = Vec3.scale(Vec3(), v1, (2.0/c1)*Vec3.dot(v1, frames[i].r)) - const ref_L_i: Vec3 = Vec3.sub(Vec3(), frames[i].r, v1r) + const v1r = Vec3.scale(mfTmpV3, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].r)) + const ref_L_i = Vec3.sub(mfTmpV4, frames[i].r, v1r) // compute t_i^L = R_1 * t_i - const v1t = Vec3.scale(Vec3(), v1, (2.0/c1) * Vec3.dot(v1, frames[i].t)) - const tan_L_i: Vec3 = Vec3.sub(Vec3(), frames[i].t, v1t) + const v1t = Vec3.scale(mfTmpV5, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].t)) + const tan_L_i = Vec3.sub(mfTmpV6, frames[i].t, v1t) // # compute reflection vector of R_2 - const v2: Vec3 = Vec3.sub(Vec3(), t2 , tan_L_i) + const v2 = Vec3.sub(mfTmpV7, t2 , tan_L_i) const c2 = Vec3.dot(v2, v2) // compute r_(i+1) = R_2 * r_i^L - const v2l = Vec3.scale(Vec3(), v1, (2.0/c2) * Vec3.dot(v2, ref_L_i)) - const ref_next = Vec3.sub(Vec3(), ref_L_i, v2l) // ref_L_i - (2 / c2) * v2.dot(ref_L_i) * v2 + const v2l = Vec3.scale(mfTmpV8, v1, (2.0/c2) * Vec3.dot(v2, ref_L_i)) + const ref_next = Vec3.sub(mfTmpV9, ref_L_i, v2l) // ref_L_i - (2 / c2) * v2.dot(ref_L_i) * v2 frames.push(getFrame(ref_next, t2)) // frames.append(Frame(ref_next, tangents[i+1])) } return frames; } +const rpTmpVec1 = Vec3() + export function getMatFromResamplePoints(points: NumberArray) { - let segmentLength = 3.4 - let new_points: Vec3[] = ResampleControlPoints(points, 3.4) + const segmentLength = 3.4 + const new_points = ResampleControlPoints(points, 3.4) const npoints = new_points.length - let new_normal: Vec3[] = GetSmoothNormals(new_points) - let frames: Frame[] = GetMiniFrame(new_points, new_normal) + const new_normal = GetSmoothNormals(new_points) + const frames = GetMiniFrame(new_points, new_normal) const limit = npoints - let transforms: Mat4[] = [] - let pti: Vec3 = Vec3.copy(Vec3(), new_points[0]); + const transforms: Mat4[] = [] + const pti = Vec3.copy(rpTmpVec1, new_points[0]); // console.log(new_points.length) // console.log(points.length/3) // console.log(limit) @@ -174,9 +209,9 @@ export function getMatFromResamplePoints(points: NumberArray) { const d = Vec3.distance(pti, pti1) if (d >= segmentLength) { // use twist or random? - const quat: Quat = Quat.rotationTo(Quat.zero(), Vec3.create(0, 0, 1), frames[i].t) // Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),new_normal[i]);//Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),direction);new_normal - const rq: Quat = Quat.setAxisAngle(Quat.zero(), frames[i].t, Math.random()*3.60 ) // Quat.setAxisAngle(Quat.zero(),direction, Math.random()*3.60 );//Quat.identity();// - let m: Mat4 = Mat4.fromQuat(Mat4.zero(), Quat.multiply(Quat.zero(), rq, quat)) // Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),quat1,quat2));//Mat4.fromQuat(Mat4.zero(),quat);//Mat4.identity();//Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),rq,quat)); + const quat = Quat.rotationTo(Quat.zero(), Vec3.create(0, 0, 1), frames[i].t) // Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),new_normal[i]);//Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),direction);new_normal + const rq = Quat.setAxisAngle(Quat.zero(), frames[i].t, Math.random()*3.60 ) // Quat.setAxisAngle(Quat.zero(),direction, Math.random()*3.60 );//Quat.identity();// + const m = Mat4.fromQuat(Mat4.zero(), Quat.multiply(Quat.zero(), rq, quat)) // Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),quat1,quat2));//Mat4.fromQuat(Mat4.zero(),quat);//Mat4.identity();//Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),rq,quat)); // let pos:Vec3 = Vec3.add(Vec3.zero(),pti1,pti) // pos = Vec3.scale(pos,pos,1.0/2.0); // Vec3.makeRotation(Mat4.zero(),Vec3.create(0,0,1),frames[i].t);// @@ -185,9 +220,9 @@ export function getMatFromResamplePoints(points: NumberArray) { // let q:Quat = Quat.rotationTo(Quat.zero(), Vec3.create(0,1,0),Vec3.create(0,0,1)) // m2=Mat4.mul(Mat4.identity(),Mat4.fromQuat(Mat4.zero(),q),m2); transforms.push(m) - pti = Vec3.copy(pti, pti1) + Vec3.copy(pti, pti1) } if (transforms.length >= limit) break } return transforms -} +} \ No newline at end of file -- GitLab