From b425a6010b8d09586afed0f00b24240995221e74 Mon Sep 17 00:00:00 2001 From: ypshim Date: Tue, 3 Nov 2026 16:31:35 +0900 Subject: [PATCH] =?UTF-8?q?fix(abut):=20=EB=B2=BD=EC=B2=B4=EC=99=80=20?= =?UTF-8?q?=ED=9D=89=EB=B2=BD=EC=9D=84=20=EC=82=BD=EB=8F=84=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 벽체: 배면 −0.8 … 전면 1.6의 2400 블록을 기초 상면부터 교좌면 단차까지 (삽도의 회색 블록) - 흉벽: 교좌면 단차 위에 얹음. 배면 단차부(−0.8 … −0.5)는 브라켓 상면(흉벽 상단 − 0.85)까지, 흉벽(−0.5 … 0)은 흉벽 상단까지 - 둘은 교좌면 단차에서 맞닿고 겹치지 않음. 배면 단차부는 흉벽 부재로 묶음 - 테스트 636건 통과, 타입 검사·빌드 통과. 브라우저 시각 확인은 미실시 Co-Authored-By: Claude Haiku 5.5 --- src/view/abut-scene.ts | 24 ++++++++++++------------ tests/abut-scene.test.ts | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/view/abut-scene.ts b/src/view/abut-scene.ts index 9829e66..7d92a84 100644 --- a/src/view/abut-scene.ts +++ b/src/view/abut-scene.ts @@ -133,29 +133,29 @@ export function buildAbutGroup( const footingTop = members.footingTopEl; const footingBottom = members.footingBottomEl; - // 벽체 (spec §4.3, 도면 type-1): the front part (t −0.5 … 1.6) stops at the 교좌면 step; the back ledge (t −0.8 … −0.5) - // rises to the 브라켓 상면 (흉벽 상단 − 0.85), where the 접속슬래브 sits. The two parts only touch the 흉벽 faces. + // 벽체 (spec §4.3, 삽도): the full 2400 block from the footing top up to the 교좌면 step (t −0.8 … 1.6). const parapetTopAt = (s: number) => members.parapetTopStartEl + ((members.parapetTopEndEl - members.parapetTopStartEl) * s) / L; const bracketAt = (s: number) => parapetTopAt(s) - members.shape.bracketHeightM; for (const seg of members.wallSegments) { - const front: [number, number][] = [ + const block: [number, number][] = [ [seg.sFrom, footingTop], [seg.sTo, footingTop], [seg.sTo, seg.seatEl], [seg.sFrom, seg.seatEl], ]; - add('wall', prism(front, members.shape.wallFrontM - members.shape.parapetBackM, new THREE.Vector3(0, 0, members.shape.parapetBackM), ex, ey, ez), 0xb7c7d3); - const ledge: [number, number][] = [ - [seg.sFrom, footingTop], - [seg.sTo, footingTop], + add('wall', prism(block, members.shape.wallFrontM - members.shape.wallBackM, new THREE.Vector3(0, 0, members.shape.wallBackM), ex, ey, ez), 0xb7c7d3); + } + + // 흉벽 (삽도): sits on the 벽체 top, above the 교좌면 step. The back strip (t −0.8 … −0.5) rises to the 브라켓 상면 (흉벽 상단 − 0.85), + // where the 접속슬래브 sits; the 흉벽 (t −0.5 … 0) rises to the parapet top line. Both start at the 교좌면 step, so nothing overlaps the 벽체. + for (const seg of members.wallSegments) { + const backStrip: [number, number][] = [ + [seg.sFrom, seg.seatEl], + [seg.sTo, seg.seatEl], [seg.sTo, bracketAt(seg.sTo)], [seg.sFrom, bracketAt(seg.sFrom)], ]; - add('wall', prism(ledge, members.shape.parapetBackM - members.shape.wallBackM, new THREE.Vector3(0, 0, members.shape.wallBackM), ex, ey, ez), 0xb7c7d3); - } - - // 흉벽: t −0.5 … 0, from the 교좌면 step (the top of the front wall) up to the parapet top line, so it never overlaps the wall. - for (const seg of members.wallSegments) { + add('parapet', prism(backStrip, members.shape.parapetBackM - members.shape.wallBackM, new THREE.Vector3(0, 0, members.shape.wallBackM), ex, ey, ez), 0x8898aa); const parapet: [number, number][] = [ [seg.sFrom, seg.seatEl], [seg.sTo, seg.seatEl], diff --git a/tests/abut-scene.test.ts b/tests/abut-scene.test.ts index 545d69c..316288d 100644 --- a/tests/abut-scene.test.ts +++ b/tests/abut-scene.test.ts @@ -21,9 +21,9 @@ const group = buildAbutGroup(model, members, wings); const count = (name: string) => (group.getObjectByName(name) as THREE.Group | undefined)?.children.length ?? 0; describe('교대 A1 3D 장면 (AA3·AA3b·AA3c)', () => { - it('has the members: 5 wall segments (front + back ledge), 5 parapet parts, 1 footing, 18 piles, 2 wings, 4 haunches', () => { - expect(count('wall')).toBe(10); // 5 front parts + 5 back ledges (도면 type-1) - expect(count('parapet')).toBe(5); // one per 교좌면 step, from the step up + it('has the members: 5 wall blocks, 10 parapet parts (2 per step), 1 footing, 18 piles, 2 wings, 4 haunches', () => { + expect(count('wall')).toBe(5); // one 벽체 block per 교좌면 step (삽도) + expect(count('parapet')).toBe(10); // per step: back strip (흉벽 배면 단차) and the 흉벽 (삽도) expect(count('footing')).toBe(1); expect(count('piles')).toBe(18); expect(count('wings')).toBe(2);