import { describe, expect, it } from 'vitest'; import { buildPier } from '../src/core/geometry'; import { c14Bars, c14Length, copingSideBars, stairBars, undersideAt } from '../src/core/rebar/coping'; import { loadP1 } from './helpers'; const m = buildPier(loadP1()); const L = m.copingL * 1000; const B = m.copingB * 1000; const side = copingSideBars(L, 41.288, 42.538); const rows = [...side.c12, ...side.c13]; const under = (x: number) => undersideAt(L, x, m.endBottom, m.levelBottom); describe('C14 / C15 / C16 (코핑철근.md §7–8)', () => { it('C14: 2 upper lines of 11 (C2, C3) and lower rows 5 / 6 / 3 / 2 = 38', () => { const bars = c14Bars(L, m.copingRefTop, rows, under); const count = (line: number) => bars.filter((b) => b.line === line).length; expect(count(1)).toBe(11); expect(count(2)).toBe(11); expect([3, 4, 5, 6].map(count)).toEqual([5, 6, 3, 2]); expect(bars.length).toBe(38); }); it('C14 heights: upper 43.251 / 43.194, lower 42.810 / 42.310 / 41.810 / 41.310', () => { const bars = c14Bars(L, m.copingRefTop, rows, under); const z = (line: number) => bars.find((b) => b.line === line)!.z; expect(z(1)).toBeCloseTo(43.251, 3); expect(z(2)).toBeCloseTo(43.194, 3); expect([3, 4, 5, 6].map(z)).toEqual([42.81, 42.31, 41.81, 41.31].map((v) => expect.closeTo(v, 2))); }); it('C14 length 3447.5 (2855.5 run + 2 × 296 legs)', () => { expect(c14Length(B)).toBeCloseTo(3447.5, 0); }); it('C15: 11 bars, z 43.598, length 3852 (2088 + 2 × 882)', () => { const { c15 } = stairBars(L, B, m.copingRefTop); expect(c15.length).toBe(11); expect(c15[0].z).toBeCloseTo(43.598, 3); expect(c15[0].length).toBeCloseTo(3852, 0); expect(c15[0].x0).toBeCloseTo(9812, 0); }); it('C16: 22 bars (3·4구간), z 43.436 / 43.507, lengths 4070 / 4069', () => { const { c16 } = stairBars(L, B, m.copingRefTop); expect(c16.length).toBe(22); expect(c16[0].z).toBeCloseTo(43.436, 3); expect(c16[11].z).toBeCloseTo(43.507, 3); expect(c16[0].length).toBeCloseTo(4070, 0); expect(c16[11].length).toBeCloseTo(4069, 0); }); it('C15 / C16 across positions: 137 from the cover line, then @250, 11 bars', () => { const { c15 } = stairBars(L, B, m.copingRefTop); expect(c15[0].n).toBeCloseTo(-B / 2 + 237, 0); expect(c15[10].n - c15[0].n).toBeCloseTo(2500, 0); }); }); describe('C14 연직 발 (코핑철근.md §8)', () => { it('upper lines keep their legs; a lower bar keeps its legs only if they end above the underside', () => { const bars = c14Bars(L, m.copingRefTop, rows, under); expect(bars.filter((b) => b.line <= 2).every((b) => b.legs)).toBe(true); // The leg of the C12 5단 bar (line 4) at the ends (x 1 m, 11 m) would end below the sloped underside, so it is left out. const omitted = bars.filter((b) => !b.legs).map((b) => [b.line, Math.round(b.x / 1000)]); expect(omitted).toEqual([[4, 1], [4, 11]]); }); });