Files
Pier_v1/tests/abut-rebar-block.test.ts
T
ypshimandClaude Haiku 5.5 a68e4a0366 feat(abut-rebar): 교대 받침블럭 배근 삽도 (평면 · 단면)
- 평면: 블럭 1200 × 1200, S2 실선 (위) · S1 파선 (아래), 번호 풍선
- 단면: 교좌면 기준, 몰탈패드 50, S1 다리 · S2 본, 묻힘 치수 문자열
- 결과에 교좌면 높이(seatZ) 추가 — 단면 축을 교좌면 기준으로 맞춤
- verify/dump: 받침블럭 삽도 덤프

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-11-05 09:38:29 +09:00

89 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest';
import { abutBlockRebar, abutBarDepths } from '../src/core/abut/rebar/block';
// 교대 받침블럭 (교대 기획서 §10 · 받침블럭철근.md §6.6): 블럭 5개, 1200 × 1200, 높이 125 (패드 50 포함, 콘크리트 75).
const blocks = [1, 2, 3, 4, 5].map((no, i) => ({ no, s: 1 + i * 2, t: 0.2, rotDeg: 0, seatEl: 44.367, blockHeightMm: 125 }));
const bottom = 40.895;
const A1 = abutBlockRebar(blocks, bottom);
const bar = (r: typeof A1, m: 'S1' | 'S2') => r.bars.find((b) => b.mark === m)!;
describe('교대 받침블럭 배근 A1 (AD6, 교대 기획서 §10)', () => {
it('블럭 콘크리트 75 (블럭 125 − 패드 50), 깊이: S2 50 · S1 62.7 (H13 두 개)', () => {
expect(A1.concreteH).toBe(75);
expect(abutBarDepths(A1.settings)).toEqual({ S2: 50, S1: 50 + 6.35 + 6.35 });
});
it('본수: 블럭마다 8본 (7@125, 끝 162.5), 5개 → S1 40 · S2 40', () => {
expect(bar(A1, 'S1').count).toBe(40);
expect(bar(A1, 'S2').count).toBe(40);
expect(A1.paths.filter((p) => p.mark === 'S1' && p.block === 1).length).toBe(8);
// 블럭 1 (s = 1000 mm): S2 본은 블럭 모서리에서 162.5, 125 간격 → 첫 본 s = 1000 − 600 + 162.5 = 562.5.
const s2 = A1.paths.filter((p) => p.mark === 'S2' && p.block === 1).map((p) => p.pts[0][0]).sort((a, b) => a - b);
expect(s2[0]).toBeCloseTo(562.5, 6);
expect(s2[1] - s2[0]).toBeCloseTo(125, 6);
expect(s2.length).toBe(8);
});
it('길이 2500 (1100 직선 + 다리 700 × 2), 묻힘: S2 675 · S1 688', () => {
expect([bar(A1, 'S1').length, bar(A1, 'S2').length]).toEqual([2500, 2500]);
expect(Math.round(A1.embedment.S2)).toBe(675);
expect(Math.round(A1.embedment.S1)).toBe(688);
});
it('간섭 (Q-S4, 경고만): S1 다리가 W2 층을 지남 → RB-AK01 (W), 다른 오류 없음', () => {
const codes = A1.issues.map((i) => `${i.code}:${i.level}`);
expect(codes).toContain('RB-AK01:W');
expect(A1.issues.filter((i) => i.level === 'E')).toEqual([]);
});
it('간격 수정 → RB-AK03 "수정됨"', () => {
const r = abutBlockRebar(blocks, bottom, { spacingS1: 150 });
expect(r.issues.map((i) => i.code)).toContain('RB-AK03');
expect(bar(r, 'S1').modified).toBe(true);
expect(bar(r, 'S2').modified).toBe(false);
});
it('회전 (방위각): 블럭 축이 돌면 경로 점도 같이 돈다 (교대축 방향 길이 보존)', () => {
const r = abutBlockRebar([{ ...blocks[0], rotDeg: 30 }], bottom);
const p = r.paths.find((q) => q.mark === 'S1')!;
const len = Math.hypot(p.pts[2][0] - p.pts[1][0], p.pts[2][1] - p.pts[1][1]);
expect(len).toBeCloseTo(1100, 6);
});
});
import { applyBlockRebar } from '../src/core/abut/edit';
import { checkStoredAbutments } from '../src/core/project';
import { parseAbutments } from '../src/core/abut/parse';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import * as XLSX from 'xlsx';
describe('③ 받침블럭 배근 입력 저장', () => {
const rec = parseAbutments(XLSX.read(readFileSync(fileURLToPath(new URL('../../../RAG/운곡교P1입력.xlsx', import.meta.url))), { type: 'buffer' })).abutments[0];
it('stores only the changed values; undefined links back; refuses bad values', () => {
const a = applyBlockRebar(rec, { spacingS1: 150, legLength: 800 });
expect(a.rebar?.block).toEqual({ spacingS1: 150, legLength: 800 });
expect(applyBlockRebar(a, { spacingS1: undefined }).rebar?.block).toEqual({ legLength: 800 });
expect(() => applyBlockRebar(rec, { legLength: 0 })).toThrow();
});
it('the project file keeps the 받침블럭 input and refuses a non-number', () => {
expect(() => checkStoredAbutments([applyBlockRebar(rec, { coverTop: 60 })])).not.toThrow();
expect(() => checkStoredAbutments([{ ...rec, rebar: { block: { coverTop: 'x' } } as never }])).toThrow('받침블럭 배근');
});
});
import { abutBlockPlanSvg, abutBlockSectionSvg } from '../src/view/abut-block-rebar-svg';
describe('③ 받침블럭 삽도', () => {
it('평면: S1 · S2 번호 풍선, 단면: 묻힘 치수 문자열 · 몰탈패드 · 교좌면; 선택하면 나머지 흐리게 / 숨김', () => {
const p = abutBlockPlanSvg(A1);
expect(p).toContain('data-pick="S1"');
expect(p).toContain('data-pick="S2"');
const s = abutBlockSectionSvg(A1);
expect(s).toContain('블럭 콘크리트 75 · 묻힘 S2 675 · S1 688');
expect(s).toContain('몰탈패드 50');
expect(abutBlockSectionSvg(A1, { marks: new Set(['S2']), only: true })).toContain('opacity="0"');
});
});