feat: [fire-shutter] 셔터박스 조립식 철판 구조, 라벨 오픈폭/오픈H 변경

This commit is contained in:
김보곤
2026-03-09 11:38:53 +09:00
parent 1cdeb24f50
commit 67c774960c

View File

@@ -65,15 +65,15 @@
</optgroup>
</select>
</div>
<div style="flex:0 0 100px;">
<label class="fs-label"> W0</label>
<div style="flex:0 0 90px;">
<label class="fs-label">오픈</label>
<input type="number" id="openWidth" class="fs-input" style="font-size:0.75rem;padding:0.375rem 0.5rem;" value="2000" onchange="fsCalc()">
</div>
<div style="flex:0 0 100px;">
<label class="fs-label">높이 H0</label>
<div style="flex:0 0 90px;">
<label class="fs-label">오픈H</label>
<input type="number" id="openHeight" class="fs-input" style="font-size:0.75rem;padding:0.375rem 0.5rem;" value="3000" onchange="fsCalc()">
</div>
<div style="flex:0 0 70px;">
<div style="flex:0 0 60px;">
<label class="fs-label">수량</label>
<input type="number" id="quantity" class="fs-input" style="font-size:0.75rem;padding:0.375rem 0.5rem;" value="1" min="1" onchange="fsCalc()">
</div>
@@ -417,9 +417,9 @@
// Product defaults
const PRODUCTS = {
steel: { marginW:110, marginH:350, weightFactor:25, gr:{width:120,depth:75,thickness:1.55,lip:15}, slatThick:1.6,
sb:{height:550, depth:650, frontRatio:0.20, shaftDia:120} },
sb:{height:550, depth:650, frontH:410, shaftDia:120} },
screen: { marginW:140, marginH:350, weightFactor:2, gr:{width:30,depth:25,thickness:1.5,lip:11}, slatThick:0.8,
sb:{height:380, depth:500, frontRatio:0.25, shaftDia:80} },
sb:{height:380, depth:500, frontH:240, shaftDia:80} },
};
const MOTORS = [{max:150,spec:'150K',inch:4},{max:300,spec:'300K',inch:4},{max:500,spec:'500K',inch:5},{max:750,spec:'750K',inch:5},{max:1000,spec:'1000K',inch:6},{max:1500,spec:'1500K',inch:6}];
const RAIL_LENGTHS = [2438, 3305, 4430];
@@ -1119,17 +1119,38 @@ function fs3dBuild() {
// 샤프트 중심 Z = -(반지름 + 여유), 박스는 샤프트를 감싸도록 배치
const boxZOffset = -(b.shaftDia / 2 + 5); // 샤프트 앞면이 Z≈-5 (가이드레일 바로 뒤)
// === SHUTTER BOX (CASE) ===
const boxGeo = new THREE.BoxGeometry(W1, b.height, b.depth);
// === SHUTTER BOX (CASE) — 조립식 철판 구조 ===
const p = PRODUCTS[S.productType];
const pt = b.thickness || 1.6; // 철판 두께
const frontH = p.sb.frontH; // 전면판 높이 (스크린:240, 철재:410)
const boxMat = new THREE.MeshStandardMaterial({ color: 0x374151, transparent: true, opacity: S.td.caseOpacity, side: THREE.DoubleSide });
meshes.case = new THREE.Mesh(boxGeo, boxMat);
meshes.case.position.set(0, H + b.height / 2, boxZOffset);
scene.add(meshes.case);
const boxEdgeMat = new THREE.LineBasicMaterial({ color: 0x94a3b8 });
meshes.case = new THREE.Group();
meshes.case.position.set(0, H, boxZOffset);
// Box wireframe (child of case — position (0,0,0) relative to parent)
const boxEdges = new THREE.EdgesGeometry(boxGeo);
const boxLine = new THREE.LineSegments(boxEdges, new THREE.LineBasicMaterial({ color: 0x94a3b8 }));
meshes.case.add(boxLine);
// 철판 생성 헬퍼
function addPlate(w, h, d, x, y, z) {
const geo = new THREE.BoxGeometry(w, h, d);
const m = new THREE.Mesh(geo, boxMat);
m.position.set(x, y, z);
meshes.case.add(m);
const edges = new THREE.EdgesGeometry(geo);
m.add(new THREE.LineSegments(edges, boxEdgeMat));
}
// 상판 (Top plate)
addPlate(W1, pt, b.depth, 0, b.height - pt / 2, 0);
// 후면판 (Back plate — 전체 높이)
addPlate(W1, b.height, pt, 0, b.height / 2, -b.depth / 2 + pt / 2);
// 전면판 (Front plate — 짧음, 상단에서 걸림)
addPlate(W1, frontH, pt, 0, b.height - frontH / 2, b.depth / 2 - pt / 2);
// 좌측판 (Left side plate — 전체 높이)
addPlate(pt, b.height, b.depth, -W1 / 2 + pt / 2, b.height / 2, 0);
// 우측판 (Right side plate — 전체 높이)
addPlate(pt, b.height, b.depth, W1 / 2 - pt / 2, b.height / 2, 0);
// 하단 개방 — 바닥판 없음 (가이드레일이 관통)
scene.add(meshes.case);
// === SHAFT ASSEMBLY (양쪽 브라켓 관통, 슬랫 폭과 동일) ===
const shaftY = H + b.height * 0.5; // 샤프트 중심 Y
@@ -1612,7 +1633,7 @@ function fs3dShowAll() {
window.fs3dOpacity = function(v) {
S.td.caseOpacity = Number(v) / 100;
$('opacityLabel').textContent = v + '%';
if (meshes.case) meshes.case.material.opacity = S.td.caseOpacity;
if (meshes.case) meshes.case.traverse(c => { if (c.isMesh) c.material.opacity = S.td.caseOpacity; });
};
window.fsToggle3d = function(el, key) {
el.classList.toggle('active');