feat(core): lengths for coping, column and the B2 split (추천안)
- Coping: C9/C10 lower U = 1740 + 2h with h linear along the slope and 2300 on the Level (3522 / 6098 / 6249 / 6340 from the document); C12 (3717–10183), C13 11746, C14 3447.5, C15 3852, C16 4070. - Column: P3 = C_t + 1.3·l_d(H19) lap (추천안 for Q-C6, lap 1146.6), P5 = C_t. - Footing: B2 13646 is split into two pieces at a splice with 1.3·l_d(S25, SD500) (추천안 for Q-B6), piece ≈ 7776 each. - Not done: C9/C11 cap (삿갓) lengths (Q-K5 open), P1/P2 per-line pieces. - Tests against the document values; P1 summary updated. - Not verified in a browser. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
73bff19aba
commit
5641bbe265
6 files changed
+105
-24
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { developmentLength, hookLength, NOMINAL_DIAMETER } from './common';
|
||||
import { developmentLength, hookLength, NOMINAL_DIAMETER, spliceLength } from './common';
|
||||
|
||||
/**
|
||||
* 기둥 철근 C4 (plan C4). Source: RAG/기둥철근 (1).md, 2026-10-22 최종 정리. Type-1 원형 중실 기둥.
|
||||
@@ -93,7 +93,15 @@ export function columnRebar(x: ColumnInput = COLUMN_P1) {
|
||||
const p6Hook = hookLength('tie90', dH16);
|
||||
const p6Length = p6Straight + 2 * p6Hook;
|
||||
|
||||
// P3 lap: Q-C6 is open; recommended = 1.3·l_d of H19 (fck 27, fy 400).
|
||||
const lapP3 = spliceLength(dH19, 400, 27);
|
||||
const p3Length = 2 * Math.PI * tieRadius + lapP3;
|
||||
const p5Length = 2 * Math.PI * tieRadius;
|
||||
|
||||
return {
|
||||
p3Length: round(p3Length, 1),
|
||||
p5Length: round(p5Length, 1),
|
||||
lapP3: round(lapP3, 1),
|
||||
r1: round(r1),
|
||||
r2: round(r2),
|
||||
angleStepDeg: 360 / x.nDiv,
|
||||
|
||||
@@ -62,3 +62,13 @@ export function hookLength(kind: HookKind, db: number): number {
|
||||
}
|
||||
return 2.5 * db * ((3 * Math.PI) / 4) + 6 * db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splice of a long bar into two pieces (추천안 for Q-B6): each piece is half the total plus half the lap,
|
||||
* and the lap is l_s = 1.3·l_d. Used only when the bar is longer than the standard bar length.
|
||||
*/
|
||||
export function splitPieces(total: number, db: number, fy: number, fck: number, standard: number): { pieces: number; pieceLength: number; lap: number } | null {
|
||||
if (total <= standard) return null;
|
||||
const lap = spliceLength(db, fy, fck);
|
||||
return { pieces: 2, pieceLength: total / 2 + lap / 2, lap };
|
||||
}
|
||||
@@ -71,3 +71,27 @@ export function c14Total(): number {
|
||||
|
||||
/** C15 (거꾸로 된 U, 가장 높은 계단) and C16 (L형, 2구간) counts (코핑철근.md §7). */
|
||||
export const STEP_BAR_COUNTS = { C15: 11, C16: 22 } as const;
|
||||
|
||||
/**
|
||||
* C9·C10 lower U length (코핑철근.md §4.3): 1740 + 2h. h rises linearly along the slope between the document's
|
||||
* ends (x 300 → h 890.9, x 4550 → h 2178.8) and stays at the Level height 2300 from the Level edge (4950) on.
|
||||
* The bar's upper cap (삿갓) length depends on l_cap, which is still open (Q-K5), so only the U is given here.
|
||||
*/
|
||||
export const SHEAR_U = { x0: 300, h0: 890.9, x1: 4550, h1: 2178.8, levelH: 2300, levelEdgeFromCentre: 1050, flat: 1740 } as const;
|
||||
|
||||
export function shearUHeight(x: number, coping: number): number {
|
||||
const xs = Math.min(x, coping - x); // mirror to the left half
|
||||
const slope = (SHEAR_U.h1 - SHEAR_U.h0) / (SHEAR_U.x1 - SHEAR_U.x0);
|
||||
const h = SHEAR_U.h0 + (xs - SHEAR_U.x0) * slope;
|
||||
return Math.min(h, SHEAR_U.levelH);
|
||||
}
|
||||
|
||||
export function shearULength(x: number, coping: number): number {
|
||||
return SHEAR_U.flat + 2 * shearUHeight(x, coping);
|
||||
}
|
||||
|
||||
/** C12 straight lengths per row (코핑철근.md §6 table, mm) and C13. */
|
||||
export const SIDE_LENGTHS = { C12: [3717, 5333, 6950, 8567, 10183], C13: 11746 } as const;
|
||||
|
||||
/** C15 (거꾸로 된 U, 3852) and C16 (L형, 4070 / 4069) lengths, mm (코핑철근.md §7). */
|
||||
export const STEP_LENGTHS = { C15: 3852, C16: [4070, 4069] as const, C14: 3447.5 } as const;
|
||||
+27
-22
@@ -1,9 +1,10 @@
|
||||
import type { PierModel } from '../geometry';
|
||||
import { bearingBlockRebar, totals } from './bearing-block';
|
||||
import { bottomPiece, topBarLength, widthLayout } from './coping-main';
|
||||
import { shearBars, sideRows, C14_COUNTS, c14Total, STEP_BAR_COUNTS } from './coping';
|
||||
import { shearBars, sideRows, C14_COUNTS, c14Total, STEP_BAR_COUNTS, shearULength, SIDE_LENGTHS, STEP_LENGTHS } from './coping';
|
||||
import { columnRebar, COLUMN_P1 } from './column';
|
||||
import { bottomBars, crossBars, sideBars, assemblyBars, shearB9 } from './footing';
|
||||
import { splitPieces } from './common';
|
||||
|
||||
/** One line of a 철근표. length is null where the document gives no length yet. */
|
||||
export interface RebarRow {
|
||||
@@ -49,23 +50,27 @@ export function rebarSummary(model: PierModel): { rows: RebarRow[]; warnings: Re
|
||||
rows.push({ member: 'coping', name: 'C7', size: 'H29', count: perRow, length: bottom.piece, note: '하면, 2조각 겹침이음' });
|
||||
rows.push({ member: 'coping', name: 'C8', size: 'H29', count: perRow, length: bottom.piece, note: '하면, 2조각 겹침이음' });
|
||||
const shear = shearBars(L);
|
||||
rows.push({ member: 'coping', name: 'C9', size: 'H25', count: shear.c9.length, length: null, note: '전단 좌 @250' });
|
||||
rows.push({ member: 'coping', name: 'C10', size: 'H25', count: shear.c10.length, length: null, note: '전단 Level @300' });
|
||||
rows.push({ member: 'coping', name: 'C11', size: 'H25', count: shear.c11.length, length: null, note: '전단 우 @250' });
|
||||
const uRange = (xs: number[]) => {
|
||||
const u = xs.map((x) => Math.round(shearULength(x, L)));
|
||||
return `${Math.min(...u)}–${Math.max(...u)}`;
|
||||
};
|
||||
rows.push({ member: 'coping', name: 'C9', size: 'H25', count: shear.c9.length, length: null, note: `전단 좌 @250, 하부 U ${uRange(shear.c9)} (삿갓 l_cap 미정)` });
|
||||
rows.push({ member: 'coping', name: 'C10', size: 'H25', count: shear.c10.length, length: null, note: `전단 Level @300, 하부 U ${uRange(shear.c10)} (삿갓 l_cap 미정)` });
|
||||
rows.push({ member: 'coping', name: 'C11', size: 'H25', count: shear.c11.length, length: null, note: `전단 우 @250, 하부 U ${uRange(shear.c11)} (삿갓 l_cap 미정)` });
|
||||
const side = sideRows(41.288, 42.538);
|
||||
rows.push({ member: 'coping', name: 'C12', size: 'H25', count: side.c12.length, length: null, note: '측면, 경사 하면에서 끊김' });
|
||||
rows.push({ member: 'coping', name: 'C13', size: 'H25', count: side.c13.length, length: null, note: '측면, 끝면까지' });
|
||||
rows.push({ member: 'coping', name: 'C14', size: 'H19', count: c14Total(), length: null, note: `직각 수평 ${C14_COUNTS.upperLines * C14_COUNTS.upperPerLine}+${C14_COUNTS.lower.join('+')}` });
|
||||
rows.push({ member: 'coping', name: 'C15', size: 'H19', count: STEP_BAR_COUNTS.C15, length: null, note: '계단부, 가장 높은 구간' });
|
||||
rows.push({ member: 'coping', name: 'C16', size: 'H19', count: STEP_BAR_COUNTS.C16, length: null, note: '계단부, 3·4구간' });
|
||||
rows.push({ member: 'coping', name: 'C12', size: 'H25', count: side.c12.length, length: null, note: `측면, 경사 하면에서 끊김, 일자 ${SIDE_LENGTHS.C12[0]}–${SIDE_LENGTHS.C12[4]}` });
|
||||
rows.push({ member: 'coping', name: 'C13', size: 'H25', count: side.c13.length, length: SIDE_LENGTHS.C13, note: '측면, 끝면까지' });
|
||||
rows.push({ member: 'coping', name: 'C14', size: 'H19', count: c14Total(), length: STEP_LENGTHS.C14, note: `직각 수평 ${C14_COUNTS.upperLines * C14_COUNTS.upperPerLine}+${C14_COUNTS.lower.join('+')}` });
|
||||
rows.push({ member: 'coping', name: 'C15', size: 'H19', count: STEP_BAR_COUNTS.C15, length: STEP_LENGTHS.C15, note: '계단부, 가장 높은 구간 (거꾸로 U)' });
|
||||
rows.push({ member: 'coping', name: 'C16', size: 'H19', count: STEP_BAR_COUNTS.C16, length: STEP_LENGTHS.C16[0], note: `계단부, 3·4구간 (${STEP_LENGTHS.C16[0]} / ${STEP_LENGTHS.C16[1]})` });
|
||||
|
||||
// Column (기둥철근.md · plan C4), P1 defaults
|
||||
const col = columnRebar(COLUMN_P1);
|
||||
rows.push({ member: 'column', name: 'P1', size: 'S32', count: col.mainP1, length: null, note: '외측 r 875, 커플러로 이음' });
|
||||
rows.push({ member: 'column', name: 'P2', size: 'S32', count: col.mainP2, length: null, note: '내측 r 843.2, 커플러로 이음' });
|
||||
rows.push({ member: 'column', name: '커플러', size: 'L150 Ø60', count: col.couplers, length: 150, note: '@3000, P2 +150' });
|
||||
rows.push({ member: 'column', name: 'P3', size: 'H19', count: col.p3Count, length: null, note: '일반 구간 띠철근 @300' });
|
||||
rows.push({ member: 'column', name: 'P5', size: 'H19', count: col.p5Count, length: null, note: '단부 띠철근 @120' });
|
||||
rows.push({ member: 'column', name: 'P3', size: 'H19', count: col.p3Count, length: col.p3Length, note: `일반 구간 띠철근 @300, 겹침 ${col.lapP3} (추천안, Q-C6)` });
|
||||
rows.push({ member: 'column', name: 'P5', size: 'H19', count: col.p5Count, length: col.p5Length, note: '단부 띠철근 @120, 커플러 1개' });
|
||||
rows.push({ member: 'column', name: 'P4', size: 'H19', count: col.p4Count, length: col.p4SemicircleLength * 2, note: '확대기초 안, 반원 2개 (길이는 반원 2개 합) · B11 간섭 무시' });
|
||||
rows.push({ member: 'column', name: 'P6', size: 'H16', count: col.p6Count, length: col.p6Length, note: '크로스타이, 8단 × 4' });
|
||||
|
||||
@@ -75,18 +80,18 @@ export function rebarSummary(model: PierModel): { rows: RebarRow[]; warnings: Re
|
||||
const Lf = f.length * 1000;
|
||||
const Wf = f.width * 1000;
|
||||
const Hf = (f.top - f.bottom) * 1000;
|
||||
for (const b of bottomBars(Lf, Wf, Hf)) {
|
||||
rows.push({ member: 'footing', name: b.name, size: b.size, count: b.count, length: b.length, note: '교각축' });
|
||||
if (b.length > STANDARD_BAR) {
|
||||
warnings.push({ code: 'RB-F08', message: `${b.name} 길이 ${Math.round(b.length)} mm가 정척 ${STANDARD_BAR} mm를 넘어 이음이 필요합니다 (Q-B6).` });
|
||||
// Bars longer than the standard length are split in two (추천안, Q-B6). The count is still the bar count.
|
||||
const addBar = (b: { name: string; size: string; count: number; length: number }, note: string) => {
|
||||
const split = splitPieces(b.length, 25.4, 500, 27, STANDARD_BAR);
|
||||
if (split) {
|
||||
rows.push({ member: 'footing', name: b.name, size: b.size, count: b.count, length: split.pieceLength, note: `${note}, 2조각 이음 (추천안, 겹침 ${Math.round(split.lap)})` });
|
||||
warnings.push({ code: 'RB-F08', message: `${b.name} 길이 ${Math.round(b.length)} mm > 정척 ${STANDARD_BAR} mm: 2조각 이음을 추천안으로 적용 (Q-B6).` });
|
||||
} else {
|
||||
rows.push({ member: 'footing', name: b.name, size: b.size, count: b.count, length: b.length, note });
|
||||
}
|
||||
}
|
||||
for (const b of crossBars(Lf, Wf, Hf)) {
|
||||
rows.push({ member: 'footing', name: b.name, size: b.size, count: b.count, length: b.length, note: '교각축 직각' });
|
||||
if (b.length > STANDARD_BAR) {
|
||||
warnings.push({ code: 'RB-F08', message: `${b.name} 길이 ${Math.round(b.length)} mm가 정척 ${STANDARD_BAR} mm를 넘어 이음이 필요합니다 (Q-B6).` });
|
||||
}
|
||||
}
|
||||
};
|
||||
for (const b of bottomBars(Lf, Wf, Hf)) addBar(b, '교각축');
|
||||
for (const b of crossBars(Lf, Wf, Hf)) addBar(b, '교각축 직각');
|
||||
for (const b of sideBars(Lf, Wf)) rows.push({ member: 'footing', name: b.name, size: b.size, count: b.count, length: b.length, note: '측면 수평' });
|
||||
for (const b of assemblyBars(Lf, Wf)) rows.push({ member: 'footing', name: b.name, size: b.size, count: b.count, length: b.length, note: '조립 수평' });
|
||||
const b9 = shearB9(Lf, Wf, Hf);
|
||||
|
||||
Reference in new issue
Block a user