feat(rebar): C12 in the taper band (h2) and C13 in the end band (h1), from the coping geometry
The split between C12 and C13 follows the end underside, not a fixed level: C12 rows lie between the Level underside and the end underside (taper height h2), C13 rows between the end underside and the top (end height h1). The break is the end underside + 127 mm, the taper line's start at the end face. P1 is unchanged (C12 41.288–42.288, C13 42.538–42.788). Tests check the band rule for h1 and h2 changes. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ecaa45306c
commit
355bf4ea75
4 files changed
+40
-9
No files matched your search
+10
-5
@@ -14,11 +14,16 @@ export interface CopingGeom {
|
||||
/** P1 values: 끝단 높이 1000, 테이퍼 높이 1500, Level 폭 2100. Used when the input does not give them. */
|
||||
export const P1_COPING_GEOM: CopingGeom = { h1: 1000, h2: 1500, levelWidth: 2100 };
|
||||
|
||||
/** Bar centre to the face of the coping, 127 mm (코핑철근.md §6.1, y_e). */
|
||||
export const SIDE_COVER_M = 0.127;
|
||||
|
||||
/**
|
||||
* Side-row levels (EL m) of C12 / C13 from the Level underside. 코핑철근.md §6.1: z_0 = 하면 주철근 Level 높이 = 41.038,
|
||||
* which is the Level underside 40.911 plus 127; z_k = z_0 + k·250, and the break is z_6 = 42.538 (C12 below, C13 above).
|
||||
* So the rows keep this offset from the Level underside.
|
||||
* Side-row levels (EL m) of C12 / C13 (코핑철근.md §6.1). z_0 = Level underside + 127 (the lowest bottom bar's Level
|
||||
* height, 41.038 on P1), z_k = z_0 + k·250. The split is by height band:
|
||||
* C12 rows lie in the taper band (Level underside … end underside, height h2);
|
||||
* C13 rows lie in the end band (end underside … top, height h1).
|
||||
* zBreak = end underside + 127 is where the taper line starts at the end face (P1: 42.538).
|
||||
*/
|
||||
export function sideRowLevels(levelBottom: number): { zBottom: number; zBreak: number } {
|
||||
return { zBottom: levelBottom + 0.377, zBreak: levelBottom + 1.627 };
|
||||
export function sideRowLevels(levelBottom: number, endBottom: number): { zBottom: number; zBreak: number } {
|
||||
return { zBottom: levelBottom + SIDE_COVER_M + 0.25, zBreak: endBottom + SIDE_COVER_M };
|
||||
}
|
||||
@@ -190,7 +190,7 @@ export function rebarSummary(
|
||||
warnings.push({ code: 'RB-M01', message: `다주형 ${nCol}기둥: C14는 T형 기준으로 두었습니다 (기둥마다 반복 규칙 미정, Q-K11).`, target: 'coping' });
|
||||
}
|
||||
// Per row: two 일자 (side faces) and two ㄷ (one at each end), so 4 bars per row (코핑철근.md §6.2).
|
||||
const levels = sideRowLevels(model.levelBottom);
|
||||
const levels = sideRowLevels(model.levelBottom, model.endBottom);
|
||||
const side = copingSideBars(model.copingL * 1000, levels.zBottom, levels.zBreak, model.copingGeom);
|
||||
const hook = model.copingB * 1000 - 2 * 127 + 2 * SIDE_HOOK_LEG; // ㄷ body across the width + two legs
|
||||
const c12Range = side.c12.length ? `${Math.round(side.c12[0].straight)}–${Math.round(side.c12[side.c12.length - 1].straight)}` : '—';
|
||||
|
||||
+1
-1
@@ -204,7 +204,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
||||
// and two ㄷ bars: a body across the width at x_w, 25.4 above the row, with legs 1525 inward along the faces.
|
||||
const sideFace = B / 2 - 0.127;
|
||||
const dSide = NOMINAL_DIAMETER.H25;
|
||||
const levels = sideRowLevels(m.levelBottom);
|
||||
const levels = sideRowLevels(m.levelBottom, m.endBottom);
|
||||
const side = copingSideBars(L * 1000, levels.zBottom, levels.zBreak, m.copingGeom);
|
||||
for (const [name, rows] of [['C12', side.c12], ['C13', side.c13]] as const) {
|
||||
for (const r of rows) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { buildPier } from '../src/core/geometry';
|
||||
import { P1_COPING_GEOM, sideRowLevels } from '../src/core/coping-geom';
|
||||
import { P1_COPING_GEOM, SIDE_COVER_M, sideRowLevels } from '../src/core/coping-geom';
|
||||
import { sideRows } from '../src/core/rebar/coping';
|
||||
import { shearUHeight, shearULength } from '../src/core/rebar/coping';
|
||||
import { rebarSummary } from '../src/core/rebar/summary';
|
||||
import { buildRebar3D } from '../src/view/rebar3d';
|
||||
@@ -45,7 +46,7 @@ describe('① 코핑 끝단 높이 h1 · 테이퍼 높이 h2 · Level 폭 (1단
|
||||
});
|
||||
|
||||
it('side-row levels keep their P1 values from the Level underside (assumption, 명세 확인 필요)', () => {
|
||||
const levels = sideRowLevels(40.911);
|
||||
const levels = sideRowLevels(40.911, 42.411);
|
||||
expect(levels.zBottom).toBeCloseTo(41.288, 6);
|
||||
expect(levels.zBreak).toBeCloseTo(42.538, 6);
|
||||
});
|
||||
@@ -59,3 +60,28 @@ describe('① 코핑 끝단 높이 h1 · 테이퍼 높이 h2 · Level 폭 (1단
|
||||
expect(buildRebar3D(changed).byName.get('C10')!.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('C12 in the taper band (h2), C13 in the end band (h1)', () => {
|
||||
const bands = (input: Parameters<typeof buildPier>[0]) => {
|
||||
const m = buildPier(input);
|
||||
const lv = sideRowLevels(m.levelBottom, m.endBottom);
|
||||
const rows = sideRows(lv.zBottom, lv.zBreak);
|
||||
return { m, rows };
|
||||
};
|
||||
it.each([
|
||||
['P1', {}],
|
||||
['h1 800', { copingH1Mm: 800 }],
|
||||
['h1 1200', { copingH1Mm: 1200 }],
|
||||
['h2 1800', { copingH2Mm: 1800 }],
|
||||
])('%s: every C12 row is in the taper band and every C13 row in the end band', (_name, change) => {
|
||||
const { m, rows } = bands({ ...loadP1(), ...change });
|
||||
for (const z of rows.c12) {
|
||||
expect(z).toBeGreaterThanOrEqual(m.levelBottom - 1e-9);
|
||||
expect(z).toBeLessThan(m.endBottom + SIDE_COVER_M);
|
||||
}
|
||||
for (const z of rows.c13) {
|
||||
expect(z).toBeGreaterThanOrEqual(m.endBottom + SIDE_COVER_M - 1e-9);
|
||||
expect(z).toBeLessThanOrEqual(m.copingRefTop);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user