diff --git a/src/utils/html_generator.py b/src/utils/html_generator.py index 8002825..5d3d576 100644 --- a/src/utils/html_generator.py +++ b/src/utils/html_generator.py @@ -179,6 +179,7 @@ class HTMLGenerator: + @@ -495,6 +496,65 @@ class HTMLGenerator: pointcloudMesh.visible = pointcloudVisible; }} }} + + // ─── 分模拆分动画 ─── + let isSplit = false; + let splitAnimId = null; + + function splitMold() {{ + if (!cavityMesh && !coreMesh) return; + isSplit = !isSplit; + const btn = document.getElementById('splitBtn'); + btn.textContent = isSplit ? '合模' : '分模拆分'; + + // 计算拆分距离:取边界框高度的 40% + const bboxDims = geometryData.bounding_box?.dimensions || [100, 100, 100]; + const splitDist = bboxDims[1] * 0.4; + + // 目标位置 + const cavityTargetY = isSplit ? splitDist : 0; + const coreTargetY = isSplit ? -splitDist : 0; + + // 分型面动画目标透明度 + const partingTargetOpacity = isSplit ? 0 : 0.3; + + // 记录起始位置 + const cavityStartY = cavityMesh ? cavityMesh.position.y : 0; + const coreStartY = coreMesh ? coreMesh.position.y : 0; + const partingStartOpacity = partingMesh ? partingMesh.material.opacity : 0.3; + + const duration = 800; // ms + const startTime = performance.now(); + + if (splitAnimId) cancelAnimationFrame(splitAnimId); + + function animateSplit(now) {{ + const elapsed = now - startTime; + const t = Math.min(elapsed / duration, 1); + // 缓动函数 (easeInOutCubic) + const ease = t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; + + if (cavityMesh) {{ + cavityMesh.position.y = cavityStartY + (cavityTargetY - cavityStartY) * ease; + }} + if (coreMesh) {{ + coreMesh.position.y = coreStartY + (coreTargetY - coreStartY) * ease; + }} + if (partingMesh) {{ + partingMesh.material.opacity = partingStartOpacity + (partingTargetOpacity - partingStartOpacity) * ease; + if (isSplit && t >= 1) partingMesh.visible = false; + else partingMesh.visible = true; + }} + + if (t < 1) {{ + splitAnimId = requestAnimationFrame(animateSplit); + }} else {{ + splitAnimId = null; + }} + }} + + splitAnimId = requestAnimationFrame(animateSplit); + }}