diff --git a/src/core/rebar/column.ts b/src/core/rebar/column.ts index 23bac4c..b210319 100644 --- a/src/core/rebar/column.ts +++ b/src/core/rebar/column.ts @@ -27,6 +27,8 @@ export interface ColumnInput { ctcCoupler: number; /** P2 커플러를 P1보다 올리는 높이. */ dzCp2: number; + /** 커플러는 P1 위 끝에서 이 거리(mm) 이상 아래에만 둔다 (커플러 여유, 가정 2500). */ + couplerTopMargin?: number; ctcP3: number; ctcP5: number; ctcP4: number; @@ -46,7 +48,11 @@ export function columnInputFor(model: PierModel, base: ColumnInput = COLUMN_P1): const seg = model.segments.find((g) => col.s >= g.s0 - 1e-9 && col.s <= g.s1 + 1e-9) ?? model.segments[0]; const Hc = Math.round((model.levelBottom - model.footings[0].top) * 1000 * 10) / 10; const hcop = Math.round((seg.top - model.levelBottom) * 1000 * 10) / 10; - return { ...base, Hc, hcop }; + // C3 (상면 3단) = the lowest coping top −127 (C1 cover) −2·57.2 (layer spacing 상면 주철근 단 간격); P1: 43.170. + // P1 top = C3 − 100 (계산 2026-10-23), so e_P1 = step top − (C3 − 0.1) = 485 on P1. + const c3 = model.copingRefTop - 0.127 - 2 * 0.0572; + const eP1 = Math.round((seg.top - (c3 - 0.1)) * 1000); + return { ...base, Hc, hcop, eP1 }; } export const COLUMN_P1: ColumnInput = { @@ -54,7 +60,7 @@ export const COLUMN_P1: ColumnInput = { Hc: 12703, hcop: 2644, c: 125, - eP1: 200, + eP1: 485, eTop: 1623, Hf: 2000, nDiv: 46, @@ -113,7 +119,10 @@ export function columnRebar(x: ColumnInput = COLUMN_P1, m: Material = DEFAULT_MA const zTop2 = x.Hc + lD2; // Bottom of P1 and P2: 확대기초 하면 2단 (B7) 위 + (d_B7 + d_P1)/2 (기둥철근.md §3.2, the same for both). const zBot = -x.Hf + layers(x.Hf).B7 + (NOMINAL_DIAMETER.S19 + dS32) / 2; - const couplerLevels = Array.from({ length: Math.max(0, Math.floor(zTop1 / x.ctcCoupler) - 1) }, (_, i) => (i + 1) * x.ctcCoupler); + // Couplers at k·ctc from the footing, kept at least the margin below the P1 top (커플러 여유). + const couplerMargin = x.couplerTopMargin ?? 2500; + const couplerCount = Math.max(0, Math.floor((zTop1 - couplerMargin) / x.ctcCoupler)); + const couplerLevels = Array.from({ length: couplerCount }, (_, i) => (i + 1) * x.ctcCoupler); // Pieces of each main bar between its couplers (기둥철근.md §3.2): the bottom piece carries the 90° hook (16.5·d = 525). const p1Hook = Math.round(hookLength('main90', dS32)); const p1Points = [zBot, ...couplerLevels, zTop1]; diff --git a/tests/column-model.test.ts b/tests/column-model.test.ts index 54668ee..38b0248 100644 --- a/tests/column-model.test.ts +++ b/tests/column-model.test.ts @@ -10,7 +10,7 @@ describe('기둥 철근 높이는 모델에서 (Hc · h_cop, 승인 2026-10-23)' expect(input.hcop).toBeCloseTo(2644, 0); const col = columnRebar(input); expect(col.zTop2).toBeCloseTo(14539, 0); - expect(col.zTop1).toBeCloseTo(15147, 0); + expect(col.zTop1).toBeCloseTo(14862, 0); }); it('taper h2 = 3000: Level underside 39.411, Hc 11203, P2 top 13039 (= Level underside + l_d)', () => { @@ -21,7 +21,7 @@ describe('기둥 철근 높이는 모델에서 (Hc · h_cop, 승인 2026-10-23)' expect(input.hcop).toBeCloseTo(4144, 0); const col = columnRebar(input); expect(col.zTop2).toBeCloseTo(13039, 0); - // The P1 top is anchored to the step top, so it does not move with h2. - expect(col.zTop1).toBeCloseTo(15147, 0); + // The P1 top is anchored to the step top (and C3), so it does not move with h2. + expect(col.zTop1).toBeCloseTo(14862, 0); }); }); diff --git a/tests/rebar-column.test.ts b/tests/rebar-column.test.ts index fdff22a..4b797d6 100644 --- a/tests/rebar-column.test.ts +++ b/tests/rebar-column.test.ts @@ -10,8 +10,8 @@ describe('기둥 철근 C4 (기둥철근.md, plan C4)', () => { expect(c.angleStepDeg).toBeCloseTo(360 / 46, 9); }); - it('heights: P1 top 15147, P2 top ≈ 14539 (l_d of S32 at fck 27, 1836.9 ≈ the document 1836)', () => { - expect(c.zTop1).toBe(15147); + it('heights: P1 top 14862 (= C3 43.170 − 0.1, e_P1 485), P2 top ≈ 14539 (l_d of S32 at fck 27, 1836.9 ≈ the document 1836)', () => { + expect(c.zTop1).toBe(14862); expect(Math.abs(c.zTop2 - 14539)).toBeLessThan(1); }); @@ -86,10 +86,10 @@ describe('RB-C07 P4 삭제 규칙 (기둥철근.md §6.2)', () => { }); describe('기둥철근 P1·P2 마디와 바닥 (기둥철근.md §3.2)', () => { - it('bottom at −1697.5 (−H_f + z_B7 + (d_B7 + d_P1)/2), P1 pieces 4697.5 + 525 / 3000 ×3 / 3147', () => { + it('bottom at −1697.5 (−H_f + z_B7 + (d_B7 + d_P1)/2), P1 pieces 4697.5 + 525 / 3000 ×3 / 2862', () => { expect(c.zBot).toBeCloseTo(-1697.55, 1); expect(c.p1Hook).toBe(525); - expect(c.p1Pieces.map((v) => Math.round(v))).toEqual([5223, 3000, 3000, 3000, 3147]); + expect(c.p1Pieces.map((v) => Math.round(v))).toEqual([5223, 3000, 3000, 3000, 2862]); }); it('P2 pieces 4847.5 / 3000 ×3 / 2389', () => {