Files
Pier_v1/tests/rebar-coping-main.test.ts
T

126 lines
6.2 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 { developmentLength, hookLength, NOMINAL_DIAMETER, spliceLength } from '../src/core/rebar/common';
import { bottomPiece, topBarLength, topRowEl, topSplicePieces, 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('철근표 간격: P1 기본값은 250 / 125 · 기본값 근거, 기본간격 140이면 280 / 140 · 입력 근거', () => {
const base = rebarSummary(buildPier(loadP1())).rows;
const c1 = base.find((r) => r.name === 'C1')!;
expect([c1.spacing, c1.actual, c1.basis]).toEqual(['250', '125', 'default']);
const c12 = base.find((r) => r.name === 'C12')!;
expect(c12.basis).toBe('default');
const c15 = base.find((r) => r.name === 'C15')!;
expect([c15.spacing, c15.actual, c15.basis]).toEqual(['250', '250', 'default']);
const m = buildPier({ ...loadP1(), copingRebar: { mainSpacing: 140 }, blockRebar: { spacingS1: 130 } });
const rows = rebarSummary(m).rows;
const c8 = rows.find((r) => r.name === 'C8')!;
expect([c8.spacing, c8.actual, c8.basis]).toEqual(['280', '140', 'input']);
expect(rows.find((r) => r.name === 'C12')!.basis).toBe('default');
const c16 = rows.find((r) => r.name === 'C16')!;
expect([c16.spacing, c16.actual, c16.basis]).toEqual(['280', '280', 'input']);
const s1 = rows.find((r) => r.name === 'S1')!;
expect([s1.spacing, s1.actual, s1.basis]).toEqual(['130', '130', 'input']);
});
it('상면 이음 (승인 2026-10-26): 기둥 중심 → total/2 + l_s/2 each; 단부 → total + l_s − 12000 and 12000', () => {
const center = topSplicePieces(12000, 1, 'center')!;
expect(center.lap).toBeGreaterThan(1700);
expect(center.pieces[0]).toBeCloseTo(12744 / 2 + center.lap / 2, 3);
expect(center.pieces[1]).toBeCloseTo(center.pieces[0], 3);
expect(center.pieces[0] + center.pieces[1]).toBeCloseTo(12744 + center.lap, 3);
const end = topSplicePieces(12000, 1, 'end')!;
expect(end.pieces[0]).toBeCloseTo(12744 + end.lap - 12000, 3);
expect(end.pieces[1]).toBeCloseTo(12000, 3);
});
it('상면 이음: a bar within the standard length is not split', () => {
expect(topSplicePieces(10000, 1, 'center')).toBeNull();
});
it('철근표: 이음 무시 → 단일 길이 12744 · 반영(기둥 중심) → 2조각, 각 조각 개수 = 행 개수', () => {
const ignore = rebarSummary(buildPier(loadP1())).rows.find((r) => r.name === 'C1')!;
expect(ignore.length).toBeCloseTo(12744, 0);
expect(ignore.pieces).toBeUndefined();
const applied = rebarSummary(buildPier({ ...loadP1(), topSplice: { mode: 'apply', at: 'center' } })).rows;
const c1 = applied.find((r) => r.name === 'C1')!;
const lap = topSplicePieces(12000, 1, 'center')!.lap;
expect(c1.length).toBeNull();
expect(c1.pieces).toHaveLength(2);
expect(c1.pieces![0].count).toBe(c1.count);
expect(c1.pieces![0].length).toBeCloseTo(12744 / 2 + lap / 2, 3);
expect(c1.pieces![1].length).toBeCloseTo(12744 / 2 + lap / 2, 3);
expect(c1.note).toContain('기둥 중심');
const end = rebarSummary(buildPier({ ...loadP1(), topSplice: { mode: 'apply', at: 'end' } })).rows.find((r) => r.name === 'C1')!;
expect(end.pieces![1].length).toBeCloseTo(12000, 3);
expect(end.note).toContain('단부');
});
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);
});
});