feat(rebar): 전·후열 단차 300 mm 이상 블록 보강 C17·C18

전열·후열 상면 차가 300 mm 이상인 구간의 높은 쪽 블록에 (결정 2026-11-10, step-bars.ts):
- C17 ㄷ형 띠 H16 @전단간격: 단차면 + c ~ 측면 − c, 위 = 높은 상면 − c, 다리 낮은 상면 아래 l_d까지
- C18 수평 피부철근 H16 @측면간격: 단차면 안쪽, 낮은 상면 + 측면간격마다
T형(철근표·3D)과 다주형(편 좌표 → 꺾임 접기) 모두에 넣는다. 구간마다 따로 두고 이웃 구간과 잇지 않는다 (가정).

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-11-10 17:17:23 +09:00
1 parent 8f808f453e
commit 33aa2d9a61
5 files changed
+142 -4

No files matched your search

+43
View File
@@ -2,6 +2,8 @@ import { describe, expect, it } from 'vitest';
import { buildPier } from '../src/core/geometry';
import { tStepBars } from '../src/core/rebar/coping';
import { multicolCopingInfo } from '../src/core/rebar/multicol-coping';
import { stepBlockBars } from '../src/core/rebar/step-bars';
import { rebarSummary } from '../src/core/rebar/summary';
import type { PierInput } from '../src/core/types';
import { loadP1 } from './helpers';
@@ -84,3 +86,44 @@ describe('계단부 철근 일반 규칙', () => {
expect(info.warnings.some((w) => w.code === 'RB-M04')).toBe(false);
});
});
describe('전·후열 단차 블록 보강 C17 · C18 (결정 2026-11-10)', () => {
const raised = (dz: number, extra: Partial<PierInput> = {}) => {
const p1 = loadP1();
return buildPier({ ...p1, ...extra, bearings: p1.bearings.map((b) => (b.row === '후열' && b.no === 7 ? { ...b, z: b.z + dz, seatEl: b.seatEl! + dz } : b)) });
};
const opts = (m: ReturnType<typeof buildPier>) => ({ cover: 100, d: 15.9, ld: 600, tieSpacing: m.copingRebar.spacingS, skinSpacing: m.copingRebar.sideSpacing });
it('a 400 mm step: C17 ㄷ ties across the higher (back) block @전단간격, legs l_d below the lower top; one C18 row', () => {
const m = raised(0.4);
const bars = stepBlockBars(m, opts(m));
const c17 = bars.filter((b) => b.name === 'C17'), c18 = bars.filter((b) => b.name === 'C18');
expect(c17.length).toBe(10);
const [, back] = m.copingParts.filter((p) => p.k === 0);
const hi = m.backSegments![1].top, lo = m.segments[1].top;
for (const b of c17) {
for (const p of b.pts) { expect(p[2]).toBeGreaterThanOrEqual(back.nFrom - 1e-9); expect(p[2]).toBeLessThanOrEqual(back.nTo + 1e-9); }
expect(b.pts[1][1]).toBeCloseTo(hi - 0.1, 9);
expect(b.pts[0][1]).toBeCloseTo(lo - 0.6, 9);
expect(b.pts[0][0]).toBeGreaterThan(2.196 + 0.1 - 1e-6);
expect(b.pts[0][0]).toBeLessThan(4.701 - 0.1 + 1e-6);
}
expect(Math.abs(c17[1].pts[0][0] - c17[0].pts[0][0])).toBeCloseTo(0.25, 9);
expect(c18.length).toBe(1);
expect(c18[0].pts[0][1]).toBeCloseTo(lo + 0.25, 9);
});
it('below 300 mm no block bars', () => {
const m = raised(0.25);
expect(stepBlockBars(m, opts(m))).toEqual([]);
});
it('they reach the T형 철근표 and the multi-column bars', () => {
const rows = rebarSummary(raised(0.4)).rows;
expect(rows.find((r) => r.name === 'C17')!.count).toBe(10);
expect(rows.find((r) => r.name === 'C18')!.count).toBe(1);
const multi = multicolCopingInfo(raised(0.4, { type: '2주형', columnCount: 2, foundationType: '말뚝기초', groundEl: 30, pileLengthMm: 24000 }));
expect(multi.bars.some((b) => b.name === 'C17')).toBe(true);
expect(multi.bars.some((b) => b.name === 'C18')).toBe(true);
});
});