diff --git a/resources/views/rd/fire-shutter-drawing/index.blade.php b/resources/views/rd/fire-shutter-drawing/index.blade.php index 692ec1c0..9f126863 100644 --- a/resources/views/rd/fire-shutter-drawing/index.blade.php +++ b/resources/views/rd/fire-shutter-drawing/index.blade.php @@ -1143,19 +1143,38 @@ function fs3dBuild() { const motorBkThick = motorBkD; // 18mm const motorBkCX = motorDir * (W1 / 2 - motorBkThick / 2); const motorR = b.shaftDia * 0.45; - const motorSprocketR = 130 * 0.35; // shaftSprocketR * 0.35 - const motorZ = -(130 + motorSprocketR + 20); // 모터 Z 오프셋 (-Z = 셔터박스 뒤쪽) + const shaftSprocketR = 70; // 브라켓 높이(180mm) 내 크기 (ø140) + const motorSprocketR = 30; // 모터측 작은 스프로켓 (ø60) + const motorZ = -(shaftSprocketR + motorSprocketR + 20); // 모터 Z 오프셋 (-Z = 셔터박스 뒤쪽) // 브라켓: Z 중심은 샤프트(0)와 모터(motorZ) 사이 const motorBkGeo = new THREE.BoxGeometry(motorBkThick, motorBkH, motorBkW); const motorBk = new THREE.Mesh(motorBkGeo, bracketMat); motorBk.position.set(motorBkCX, 0, motorZ / 2); meshes.motor.add(motorBk); - // --- 2) 스프로켓 위치 기준 (체인 경로 계산용, 메시 없음) --- - const shaftSprocketR = 130; + // --- 2) 스프로켓 톱니바퀴 (샤프트측 + 모터측) --- const sprocketThick = 12; const sprocketFaceX = motorDir * (W1 / 2 - motorBkThick); const shaftSprocketX = sprocketFaceX - motorDir * sprocketThick / 2; + const sprocketMat = new THREE.MeshStandardMaterial({ color: 0x374151, metalness: 0.6, roughness: 0.35 }); + + // 샤프트 스프로켓 톱니바퀴 + const shaftSpGroup = new THREE.Group(); + const shaftSpBodyGeo = new THREE.CylinderGeometry(shaftSprocketR * 0.85, shaftSprocketR * 0.85, sprocketThick, 32); + shaftSpBodyGeo.rotateZ(Math.PI / 2); + shaftSpGroup.add(new THREE.Mesh(shaftSpBodyGeo, sprocketMat)); + const shaftTeethCount = 18; + const toothH = 8, toothTW = 6; + for (let i = 0; i < shaftTeethCount; i++) { + const a = (i / shaftTeethCount) * Math.PI * 2; + const tGeo = new THREE.BoxGeometry(sprocketThick * 0.8, toothTW, toothH); + const t = new THREE.Mesh(tGeo, sprocketMat); + t.position.set(0, (shaftSprocketR - toothH / 2) * Math.sin(a), (shaftSprocketR - toothH / 2) * Math.cos(a)); + t.rotation.x = a; + shaftSpGroup.add(t); + } + shaftSpGroup.position.set(shaftSprocketX, 0, 0); + meshes.motor.add(shaftSpGroup); // --- 3) 모터 (샤프트와 수평방향 Z 오프셋 — 슬랫과 간섭 없음) --- const motorBodyLen = motorR * 3; @@ -1190,12 +1209,23 @@ function fs3dBuild() { mMount.position.set(motorCX, -motorR - 2.5, motorZ); meshes.motor.add(mMount); - // 모터 출력 스프로켓 (샤프트 스프로켓과 같은 X면, Z=motorZ) - const mSpGeo = new THREE.CylinderGeometry(motorSprocketR, motorSprocketR, sprocketThick, 20); - mSpGeo.rotateZ(Math.PI / 2); - const mSpMesh = new THREE.Mesh(mSpGeo, darkMat); - mSpMesh.position.set(shaftSprocketX, 0, motorZ); - meshes.motor.add(mSpMesh); + // 모터 출력 스프로켓 톱니바퀴 (샤프트 스프로켓과 같은 X면, Z=motorZ) + const mSpGroup = new THREE.Group(); + const mSpBodyGeo = new THREE.CylinderGeometry(motorSprocketR * 0.8, motorSprocketR * 0.8, sprocketThick, 20); + mSpBodyGeo.rotateZ(Math.PI / 2); + mSpGroup.add(new THREE.Mesh(mSpBodyGeo, sprocketMat)); + const motorTeethCount = 10; + const mToothH = 6, mToothTW = 5; + for (let i = 0; i < motorTeethCount; i++) { + const a = (i / motorTeethCount) * Math.PI * 2; + const tGeo = new THREE.BoxGeometry(sprocketThick * 0.8, mToothTW, mToothH); + const t = new THREE.Mesh(tGeo, sprocketMat); + t.position.set(0, (motorSprocketR - mToothH / 2) * Math.sin(a), (motorSprocketR - mToothH / 2) * Math.cos(a)); + t.rotation.x = a; + mSpGroup.add(t); + } + mSpGroup.position.set(shaftSprocketX, 0, motorZ); + meshes.motor.add(mSpGroup); // --- 4) 체인 (RS #40, YZ 평면 — 수평으로 두 스프로켓 연결) --- // 샤프트 스프로켓: (Y=0, Z=0), 모터 스프로켓: (Y=0, Z=motorZ) @@ -1222,18 +1252,21 @@ function fs3dBuild() { chainLine.position.x = shaftSprocketX; meshes.motor.add(chainLine); - // 체인 직선 두께 (상/하단) + // 체인 직선 두께 (상/하단 — 스프로켓 반지름 차이만큼 기울기 적용) const tangentLen = Math.sqrt(Math.pow(R1 - R2, 2) + motorZ * motorZ); if (tangentLen > 10) { const halfZ = motorZ / 2; + const chainTilt = Math.atan2(R1 - R2, Math.abs(motorZ)); // 반지름 차이에 의한 기울기 // 상단 직선 const csGeo = new THREE.BoxGeometry(6, 4, tangentLen); const csTop = new THREE.Mesh(csGeo, chainMat); csTop.position.set(shaftSprocketX, (R1 + R2) / 2, halfZ); + csTop.rotation.x = chainTilt; meshes.motor.add(csTop); // 하단 직선 const csBot = new THREE.Mesh(csGeo.clone(), chainMat); csBot.position.set(shaftSprocketX, -(R1 + R2) / 2, halfZ); + csBot.rotation.x = -chainTilt; meshes.motor.add(csBot); }