diff --git a/public/js/webgl-book-shape-lab.js b/public/js/webgl-book-shape-lab.js index 2b3d9f7..73eb656 100644 --- a/public/js/webgl-book-shape-lab.js +++ b/public/js/webgl-book-shape-lab.js @@ -296,20 +296,7 @@ function addCoverAssembly(pageWidth, depth, thickness, spineWidth, coverOuterX) } function createCoverAssemblyGeometry(pageWidth, depth, thickness, spineWidth, coverOuterX) { - const spineHalf = spineArcHalf(spineWidth); - const hingeX = spineHalf + hingeInset(); - const outerX = coverOuterX ?? spineHalf + pageWidth + COVER_OVERHANG; - const outerTopY = BOOK_PROFILE.tableY + thickness; - const connectionTopY = BOOK_PROFILE.raisedHingeY; - const spineTopY = BOOK_PROFILE.tableY + thickness; - const section = [ - { x: -outerX, y: outerTopY }, - { x: -hingeX, y: connectionTopY }, - { x: -spineHalf, y: spineTopY }, - { x: spineHalf, y: spineTopY }, - { x: hingeX, y: connectionTopY }, - { x: outerX, y: outerTopY } - ]; + const section = coverProfilePoints(spineWidth, coverOuterX ?? spineArcHalf(spineWidth) + pageWidth + COVER_OVERHANG); const positions = []; const uvs = []; const indices = []; @@ -409,6 +396,25 @@ function hingeInset() { return Math.max(0.001, BOOK_PROFILE.raisedHingeY - BOOK_PROFILE.coverThickness); } +function coverProfilePoints(spineWidth, coverOuterX) { + return coverProfilePointsFromFrame(spineArcHalf(spineWidth), coverOuterX); +} + +function coverProfilePointsFromFrame(spineHalf, coverOuterX) { + const hingeX = spineHalf + hingeInset(); + const outerTopY = BOOK_PROFILE.tableY + BOOK_PROFILE.coverThickness; + const connectionTopY = BOOK_PROFILE.raisedHingeY; + const spineTopY = BOOK_PROFILE.tableY + BOOK_PROFILE.coverThickness; + return [ + { x: -coverOuterX, y: outerTopY }, + { x: -hingeX, y: connectionTopY }, + { x: -spineHalf, y: spineTopY }, + { x: spineHalf, y: spineTopY }, + { x: hingeX, y: connectionTopY }, + { x: coverOuterX, y: outerTopY } + ]; +} + function calculateSpineWidth(bundleCount) { const minimumWidth = 0.16; if (bundleCount <= 1) return minimumWidth; @@ -894,16 +900,19 @@ function upwardNormalAt(points, index) { function coverTopYAtX(x) { const ax = Math.abs(x); - const spineHalf = currentSpineHalf(); - const hingeX = spineHalf + hingeInset(); - const outerX = activeCoverOuterX; - if (ax <= spineHalf) return BOOK_PROFILE.coverThickness; - if (ax <= hingeX) { - const t = (ax - spineHalf) / (hingeX - spineHalf); - return THREE.MathUtils.lerp(BOOK_PROFILE.coverThickness, BOOK_PROFILE.raisedHingeY, t); + const profile = coverProfilePointsFromFrame(currentSpineHalf(), activeCoverOuterX) + .filter((point) => point.x >= 0) + .sort((a, b) => a.x - b.x); + if (ax <= profile[0].x) return profile[0].y; + for (let index = 0; index < profile.length - 1; index += 1) { + const from = profile[index]; + const to = profile[index + 1]; + if (ax <= to.x) { + const t = (ax - from.x) / (to.x - from.x || 1); + return THREE.MathUtils.lerp(from.y, to.y, t); + } } - const t = THREE.MathUtils.clamp((ax - hingeX) / (outerX - hingeX), 0, 1); - return THREE.MathUtils.lerp(BOOK_PROFILE.raisedHingeY, BOOK_PROFILE.coverThickness, t); + return profile[profile.length - 1].y; } function currentSpineHalf() {