import { describe, expect, it } from 'vitest'; import { developmentLength, hookLength, NOMINAL_DIAMETER, spliceLength } from '../src/core/rebar/common'; import { bottomPiece, topBarLength, topRowEl, widthLayout } from '../src/core/rebar/coping-main'; import { buildPier } from '../src/core/geometry'; import { rebarSummary } from '../src/core/rebar/summary'; import { DEFAULT_COPING_REBAR } from '../src/core/rebar/coping-settings'; import { loadP1 } from './helpers'; describe('C1–C8 상·하면 주철근 (코핑철근.md §5, plan C3)', () => { it('nominal diameters: H29 28.6, S32 31.8 (documents use these, not the round numbers)', () => { expect(NOMINAL_DIAMETER.H29).toBe(28.6); expect(NOMINAL_DIAMETER.S32).toBe(31.8); }); it('width layout for B 3100: edge 127, ends 110.5, 21@125, 24 bars (12 + 12)', () => { const w = widthLayout(3100); expect(w.yE).toBe(127); expect(w.S).toBe(2846); expect(w.n).toBe(21); expect(w.g).toBe(110.5); expect(w.count).toBe(24); expect(w.cyclePerKind).toBe(12); expect(w.text).toBe('127 · 110.5 · 21@125 · 110.5 · 127'); }); it('주철근 기본간격 input drives the layout: 140 → 19@140 (22 bars, even), 120 → 22@120 (25, odd)', () => { const w140 = widthLayout(3100, { ...DEFAULT_COPING_REBAR, mainSpacing: 140 }); expect(w140.spacing).toBe(140); expect(w140.n).toBe(19); expect(w140.count).toBe(22); expect(w140.text).toBe(`${w140.yE} · ${w140.g} · 19@140 · ${w140.g} · ${w140.yE}`); const w120 = widthLayout(3100, { ...DEFAULT_COPING_REBAR, mainSpacing: 120 }); expect(w120.n).toBe(22); expect(w120.count).toBe(25); }); it('CP04: the default P1 has an even count (no warning); 기본간격 120 gives an odd count and a CP04 warning', () => { const base = rebarSummary(buildPier(loadP1())).warnings.filter((w) => w.code === 'CP04'); expect(base).toEqual([]); const odd = buildPier({ ...loadP1(), copingRebar: { mainSpacing: 120 } }); const warnings = rebarSummary(odd).warnings.filter((w) => w.code === 'CP04'); expect(warnings).toHaveLength(1); expect(warnings[0].target).toBe('coping'); }); it('heights: 43.284 / 43.184 / 43.084 for the three top rows (상면 단 간격 100)', () => { expect(topRowEl(43.284, 1)).toBe(43.284); expect(topRowEl(43.284, 2)).toBe(43.184); expect(topRowEl(43.284, 3)).toBe(43.084); }); it('top bar lengths 12744 / 12686.8 / 12629.6 (path + 2 × 472 hook, 가로 단 간격 d = 28.6)', () => { expect(topBarLength(12000, 1)).toBeCloseTo(12744, 0); expect(topBarLength(12000, 2)).toBeCloseTo(12686.8, 1); expect(topBarLength(12000, 3)).toBeCloseTo(12629.6, 1); }); it('bottom piece ≈ 7448 with l_s = 1717.6 (1.3 × l_d of H29 at fck 27) — the document shows 1717', () => { const b = bottomPiece(); expect(b.path).toBeCloseTo(12235.6, 6); expect(b.ls).toBeCloseTo(1717.6, 0); expect(b.piece).toBeCloseTo(7448, 0); }); it('hook 472 (16.5 × 28.6) and splice from the same formula as C1', () => { expect(hookLength('main90', NOMINAL_DIAMETER.H29)).toBeCloseTo(472, 0); expect(spliceLength(NOMINAL_DIAMETER.H29, 400, 27)).toBeCloseTo(1.3 * developmentLength(NOMINAL_DIAMETER.H29, 400, 27), 9); }); });