test(core): footing drawing-reproduction checks from the document's test table

- Leg offsets (B1 +25.4, B3 +22.25, B5 +28.6, B7 +23.85) and B11 / B12 heights
  (550 / 950 / 1350; 569.1 / 969.1 / 1369.1).
- Reproduction counts: W 7800 → B4 30 / B2 29; L 9350 → B8 36 / B6 35.
- Variables: W 8000 with s 150 → 50 steps, e 150; W 12000 → 92 steps.
- Splice cases: L 8700 → B2 11946 (no splice), L 12400 → B4 12200,
  W 8800 → B6 12046.
- Not covered: the 배근도 H 2200 case for B10 (the document's count is unclear).

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-22 11:39:42 +09:00
1 parent 1c6194cd48
commit 4d8bbf7f6e
2 files changed
+72 -1

No files matched your search

+28 -1
View File
@@ -37,7 +37,7 @@ export interface GridResult {
}
/** Grid along one side of the footing (§3.1). side = W for B1–B4, L for B5–B8. */
export function grid(side: number, s = FOOTING_DEFAULTS.s, cSide = FOOTING_DEFAULTS.cSide, eMin = FOOTING_DEFAULTS.eMin): GridResult {
export function grid(side: number, s: number = FOOTING_DEFAULTS.s, cSide: number = FOOTING_DEFAULTS.cSide, eMin: number = FOOTING_DEFAULTS.eMin): GridResult {
const A = side - 2 * cSide;
const n = Math.floor((A - 2 * eMin) / s);
const G = n * s;
@@ -165,3 +165,30 @@ export function shearB9(L: number, W: number, H: number): { rows: number; perRow
const lh = hookLength('stirrup135', d('H16'));
return { rows: rowIndices.length, perRow, count, length: lv + 2 * lh };
}
/** Leg offsets from the grid line (§5.3, §6.3): the B1/B3 and B5/B7 legs sit beside the outer leg. */
export function legOffsets(): { B1: number; B3: number; B5: number; B7: number } {
const dB2 = NOMINAL_DIAMETER.S25;
const dB1 = NOMINAL_DIAMETER.S25;
const dB3 = NOMINAL_DIAMETER.S19;
const dB6 = NOMINAL_DIAMETER.S29;
const dB5 = NOMINAL_DIAMETER.S29;
const dB7 = NOMINAL_DIAMETER.S19;
return {
B1: (dB2 + dB1) / 2,
B3: (dB2 + dB3) / 2,
B5: (dB6 + dB5) / 2,
B7: (dB6 + dB7) / 2,
};
}
/** B11/B12 heights (§8.1): B10 levels at 150 + k·s_v; the assembly levels are j = n, 2n, 3n (n = 2), and B12 sits d_B10 above B11. */
export function assemblyHeights(): { B11: number[]; B12: number[] } {
const { cBottom } = FOOTING_DEFAULTS;
const sV = FOOTING_DEFAULTS.sV;
const n = FOOTING_DEFAULTS.n;
const js = [n, 2 * n, 3 * n];
const B11 = js.map((j) => cBottom + j * sV);
const B12 = B11.map((z) => z + NOMINAL_DIAMETER.S19);
return { B11, B12 };
}
+44
View File
@@ -76,3 +76,47 @@ describe('확대기초 철근 (확대기초철근 (1).md, plan C5)', () => {
expect(b9.length).toBeCloseTo(2128, 0);
});
});
import { assemblyHeights, legOffsets } from '../src/core/rebar/footing';
describe('확대기초 배근도 재현 (확대기초철근 (1).md §13)', () => {
it('leg offsets: B1 +25.4, B3 +22.25, B5 +28.6, B7 +23.85', () => {
const o = legOffsets();
expect(o.B1).toBeCloseTo(25.4, 6);
expect(o.B3).toBeCloseTo(22.25, 6);
expect(o.B5).toBeCloseTo(28.6, 6);
expect(o.B7).toBeCloseTo(23.85, 6);
});
it('B11 at 550 / 950 / 1350 and B12 at 569.1 / 969.1 / 1369.1', () => {
const h = assemblyHeights();
expect(h.B11).toEqual([550, 950, 1350]);
expect(h.B12.map((z) => Math.round(z * 10) / 10)).toEqual([569.1, 969.1, 1369.1]);
});
it('배근도 재현 W 7800 → B4 30, B2 29 (odd count split)', () => {
const bars = bottomBars(10400, 7800, 2000);
expect(bars.find((b) => b.name === 'B4')!.count).toBe(30);
expect(bars.find((b) => b.name === 'B2')!.count).toBe(29);
});
it('배근도 재현 L 9350 → B8 36, B6 35', () => {
const bars = crossBars(9350, 8150, 2000);
expect(bars.find((b) => b.name === 'B8')!.count).toBe(36);
expect(bars.find((b) => b.name === 'B6')!.count).toBe(35);
});
it('variables: W 8000 with s 150 → 50 grid steps, e 150, B4 26 / B2 25; W 12000 → 92 steps, e 150', () => {
const g = grid(8000, 150);
expect(g.n).toBe(50);
expect(g.e).toBeCloseTo(150, 6);
expect(grid(12000).n).toBe(92);
expect(grid(12000).e).toBeCloseTo(150, 6);
});
it('splice cases: L 8700 → B2 11946 (no splice); L 12400 → B4 12200; W 8800 → B6 12046', () => {
expect(bottomBars(8700, 8150, 2000).find((b) => b.name === 'B2')!.length).toBeCloseTo(11946, 0);
expect(bottomBars(12400, 8150, 2000).find((b) => b.name === 'B4')!.length).toBeCloseTo(12200, 0);
expect(crossBars(10400, 8800, 2000).find((b) => b.name === 'B6')!.length).toBeCloseTo(12046, 0);
});
});