feat(rebar): 상면 주철근 단 간격(세로) 입력 100 mm, 가로는 2d 고정
- 세로 단 간격은 입력(기본 100, 범위 80–120)으로 상면 C1–C6, C14 상면, 기둥 C3 높이에 쓴다 - 가로 단 간격은 2d(H29, 57.2 mm)로 고정 (코핑철근.md의 s_lay 하나를 둘로 나눔) - P1 기준 값 갱신: 상면 높이 43.284 / 43.184 / 43.084, C14 상면 43.208 / 43.108, P1 위 끝 zTop1 14776 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9c93a6aa01
commit
2acb427bab
10 files changed
+26
-25
No files matched your search
@@ -48,9 +48,9 @@ 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;
|
||||
// C3 (상면 3단) = the lowest coping top −127 (C1 cover) −2·57.2 (layer spacing 상면 주철근 단 간격); P1: 43.170.
|
||||
// C3 (상면 3단) = the lowest coping top −127 (C1 cover) −2·s_lay (상면 주철근 단 간격 input); P1 was 43.170 at 57.2.
|
||||
// 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 c3 = model.copingRefTop - 0.127 - 2 * (model.copingRebar.mainLayerGap / 1000);
|
||||
const eP1 = Math.round((seg.top - (c3 - 0.1)) * 1000);
|
||||
// e_top: the coping middle level (Level 하면 + 계단 상면)/2 is the top of P3 and P6 (승인 2026-10-23).
|
||||
const eTop = Math.round((seg.top - (model.levelBottom + seg.top) / 2) * 1000);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { DEFAULT_MATERIAL, fyOf, hookLength, Material, NOMINAL_DIAMETER, spliceLength } from './common';
|
||||
import { DEFAULT_COPING_REBAR } from './coping-settings';
|
||||
|
||||
/**
|
||||
* C1–C8 상·하면 주철근 (plan C3 continued). Source: RAG/코핑철근.md §5, 2026-10-22 최종 정리.
|
||||
@@ -10,9 +11,8 @@ export const MAIN = {
|
||||
/** 기본 간격 s_m and minimum end gap g_min. */
|
||||
spacing: 125,
|
||||
endGapMin: 80,
|
||||
/** 상면 단 간격 s_lay (EL, m) and its horizontal step (mm). */
|
||||
layEl: 0.057,
|
||||
layHorizontal: 57.2,
|
||||
/** 상면 단 가로 간격 = 2d (H29, mm). Fixed; the vertical step is the 상면 주철근 단 간격 input. */
|
||||
layHorizontal: 2 * NOMINAL_DIAMETER.H29,
|
||||
/** 90° 갈고리 l_h (mm, as in the document). */
|
||||
hook: 472,
|
||||
/** 하면 경사 구간 수평 길이 (mm, each side) and Level width. */
|
||||
@@ -56,9 +56,9 @@ export function widthLayout(B: number, dSt = NOMINAL_DIAMETER.H25, dM = NOMINAL_
|
||||
};
|
||||
}
|
||||
|
||||
/** Top-layer EL of the k-th row (k = 1, 2, 3): z_k = z_1 − (k − 1)·s_lay (m). */
|
||||
export function topRowEl(z1: number, k: number): number {
|
||||
return Math.round((z1 - (k - 1) * MAIN.layEl) * 1000) / 1000;
|
||||
/** Top-layer EL of the k-th row (k = 1, 2, 3): z_k = z_1 − (k − 1)·s_lay (m). s_lay is the 상면 주철근 단 간격 input. */
|
||||
export function topRowEl(z1: number, k: number, layEl = DEFAULT_COPING_REBAR.mainLayerGap / 1000): number {
|
||||
return Math.round((z1 - (k - 1) * layEl) * 1000) / 1000;
|
||||
}
|
||||
|
||||
/** Length of one top bar on row k: path L − 2·(c + (k−1)·step), plus two 90° hooks. */
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface CopingRebarSettings {
|
||||
mainSpacing: number;
|
||||
/** 주철근 끝단 최소 여유 (mm). */
|
||||
mainEndGap: number;
|
||||
/** 상면 주철근 단 간격 (mm). */
|
||||
/** 상면 주철근 단 간격 · 세로 (mm). The horizontal step is fixed at 2d (H29, 57.2 mm). */
|
||||
mainLayerGap: number;
|
||||
/** 첫 전단철근 최소 여유 (피복 다음, mm). */
|
||||
firstShearGap: number;
|
||||
@@ -33,7 +33,7 @@ export const DEFAULT_COPING_REBAR: CopingRebarSettings = {
|
||||
cover: 100,
|
||||
mainSpacing: 125,
|
||||
mainEndGap: 80,
|
||||
mainLayerGap: 57.2,
|
||||
mainLayerGap: 100,
|
||||
firstShearGap: 200,
|
||||
shearLegs: 6,
|
||||
spacingS: 250,
|
||||
@@ -49,7 +49,7 @@ export const COPING_REBAR_RANGES: Record<keyof CopingRebarSettings, [number, num
|
||||
cover: [80, 150],
|
||||
mainSpacing: [100, 150],
|
||||
mainEndGap: [60, 100],
|
||||
mainLayerGap: [50, 70],
|
||||
mainLayerGap: [80, 120],
|
||||
firstShearGap: [100, 300],
|
||||
shearLegs: [4, 8],
|
||||
spacingS: [200, 350],
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
import { DEFAULT_MATERIAL, developmentLength, fyOf, hookLength, Material, NOMINAL_DIAMETER } from './common';
|
||||
import { type CopingGeom, P1_COPING_GEOM } from '../coping-geom';
|
||||
import { DEFAULT_COPING_REBAR } from './coping-settings';
|
||||
export const COPING_REBAR = {
|
||||
/** 피복 (최외측 철근 중심까지). */
|
||||
cover: 100,
|
||||
@@ -178,7 +179,7 @@ export function undersideAt(L: number, x: number, endBottom: number, levelBottom
|
||||
* Lower rows use the side rows 7, 5, 3, 1 from the bottom (k = m − 2(j − 1)): odd j at x_c ± 2000k, even j at x_c ± 1000 ± 2000k,
|
||||
* only where that side row exists (x_w ≤ x ≤ L − x_w). `sideRows` are the side rows (z m, x_w mm), ascending.
|
||||
*/
|
||||
export function c14Bars(L: number, topEl: number, sideRows: { z: number; xw: number }[], under: (x: number) => number): C14Bar[] {
|
||||
export function c14Bars(L: number, topEl: number, sideRows: { z: number; xw: number }[], under: (x: number) => number, layEl = DEFAULT_COPING_REBAR.mainLayerGap / 1000): C14Bar[] {
|
||||
const leg = Math.round(hookLength('main90', NOMINAL_DIAMETER.H19)) / 1000; // 296 mm, EL m
|
||||
const xc = L / 2;
|
||||
const lo = COPING_REBAR.cover + C14_END_GAP;
|
||||
@@ -186,7 +187,7 @@ export function c14Bars(L: number, topEl: number, sideRows: { z: number; xw: num
|
||||
const out: C14Bar[] = [];
|
||||
const dUpper = (NOMINAL_DIAMETER.H29 + NOMINAL_DIAMETER.H19) / 2000; // m, over C2 / C3 (H29)
|
||||
for (const k of [2, 3]) {
|
||||
const z = topEl - 0.127 - (k - 1) * 0.057 + dUpper;
|
||||
const z = topEl - 0.127 - (k - 1) * layEl + dUpper;
|
||||
for (let q = -10; q <= 10; q++) {
|
||||
const x = xc + q * 1000;
|
||||
if (x >= lo && x <= hi) out.push({ line: k - 1, x, z, legs: z - leg >= under(x) });
|
||||
|
||||
@@ -200,7 +200,7 @@ export function rebarSummary(
|
||||
rows.push({ member: 'coping', name: 'C13', size: 'H25', count: 4 * side.c13.length, length: null, pieces: sidePieces(side.c13), note: `측면, 끝면까지, 일자 (${2 * side.c13.length}) · ㄷ ${Math.round(hook)} (${2 * side.c13.length})` });
|
||||
// C14 / C15 / C16 are derived from the model (코핑철근.md §7–8); the document's 38 / 11 / 22 and 3852 / 4070 / 4069 are checked in the tests.
|
||||
const L14 = model.copingL * 1000;
|
||||
const c14 = c14Bars(L14, model.copingRefTop, [...side.c12, ...side.c13], (x) => undersideAt(L14, x, model.endBottom, model.levelBottom, model.copingGeom.levelWidth));
|
||||
const c14 = c14Bars(L14, model.copingRefTop, [...side.c12, ...side.c13], (x) => undersideAt(L14, x, model.endBottom, model.levelBottom, model.copingGeom.levelWidth), model.copingRebar.mainLayerGap / 1000);
|
||||
const lineCount = (line: number) => c14.filter((b) => b.line === line).length;
|
||||
const omitted = c14.filter((b) => !b.legs).length;
|
||||
rows.push({ member: 'coping', name: 'C14', size: 'H19', count: c14.length, length: c14Length(model.copingB * 1000), note: `위 2 줄 ${lineCount(1)} · ${lineCount(2)}본씩, 아래 ${[3, 4, 5, 6].map(lineCount).join(' · ')} (합 ${c14.length}) · 연직 발 생략 ${omitted}개 (하면 밖)` });
|
||||
|
||||
+1
-1
@@ -1079,7 +1079,7 @@ const COPING_REBAR_FIELDS: { key: keyof CopingRebarSettings; label: string }[] =
|
||||
{ key: 'cover', label: '피복 (철근 중심, mm)' },
|
||||
{ key: 'mainSpacing', label: '주철근 기본간격 (mm)' },
|
||||
{ key: 'mainEndGap', label: '주철근 끝단 최소 여유 (mm)' },
|
||||
{ key: 'mainLayerGap', label: '상면 주철근 단 간격 (mm)' },
|
||||
{ key: 'mainLayerGap', label: '상면 주철근 단 간격 · 세로 (mm, 가로는 2d 고정)' },
|
||||
{ key: 'firstShearGap', label: '첫 전단철근 최소 여유 (피복 다음, mm)' },
|
||||
{ key: 'shearLegs', label: '전단철근 다리 수' },
|
||||
{ key: 'spacingS', label: '전단철근 간격 · 경사 (mm)' },
|
||||
|
||||
+2
-2
@@ -150,7 +150,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
||||
const topEl = m.copingRefTop;
|
||||
const hookTop = MAIN.hook / 1000;
|
||||
for (let k = 1; k <= 3; k++) {
|
||||
const z = topEl - 0.127 - (k - 1) * 0.057;
|
||||
const z = topEl - 0.127 - (k - 1) * (m.copingRebar.mainLayerGap / 1000);
|
||||
const xk = cover + ((k - 1) * MAIN.layHorizontal) / 1000;
|
||||
xs.forEach((n, j) => {
|
||||
const name = `C${k + (j % 2 === 1 ? 0 : 3)}`;
|
||||
@@ -239,7 +239,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
||||
const c14Hook = mm(hookLength('main90', NOMINAL_DIAMETER.H19));
|
||||
const c14Na = -B / 2 + mm(C14_INSET);
|
||||
const c14Nb = B / 2 - mm(C14_INSET);
|
||||
for (const b of c14Bars(L * 1000, topEl, [...side.c12, ...side.c13], (x) => undersideAt(L * 1000, x, m.endBottom, m.levelBottom, m.copingGeom.levelWidth))) {
|
||||
for (const b of c14Bars(L * 1000, topEl, [...side.c12, ...side.c13], (x) => undersideAt(L * 1000, x, m.endBottom, m.levelBottom, m.copingGeom.levelWidth), m.copingRebar.mainLayerGap / 1000)) {
|
||||
const xm = mm(b.x);
|
||||
addBar('C14', 0, [xm, b.z, c14Na], [xm, b.z, c14Nb], NOMINAL_DIAMETER.H19, COLOR.coping);
|
||||
// 연직 발 below the coping underside is left out (코핑철근.md §8).
|
||||
|
||||
@@ -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(14862, 0);
|
||||
expect(col.zTop1).toBeCloseTo(14776, 0);
|
||||
});
|
||||
|
||||
it('taper h2 = 3000: Level underside 39.411, Hc 11203, P2 top 13039 (= Level underside + l_d)', () => {
|
||||
@@ -22,7 +22,7 @@ describe('기둥 철근 높이는 모델에서 (Hc · h_cop, 승인 2026-10-23)'
|
||||
const col = columnRebar(input);
|
||||
expect(col.zTop2).toBeCloseTo(13039, 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);
|
||||
expect(col.zTop1).toBeCloseTo(14776, 0);
|
||||
});
|
||||
|
||||
it('P3 and P6 end at the coping middle level: P1 e_top 1322; taper 3000 gives e_top 2072, P3 37 ties, P6 32 bars', () => {
|
||||
|
||||
@@ -19,10 +19,10 @@ describe('C1–C8 상·하면 주철근 (코핑철근.md §5, plan C3)', () => {
|
||||
expect(w.text).toBe('127 · 110.5 · 21@125 · 110.5 · 127');
|
||||
});
|
||||
|
||||
it('heights: 43.284 / 43.227 / 43.170 for the three top rows', () => {
|
||||
it('heights: 43.284 / 43.184 / 43.084 for the three top rows (상면 단 간격 100)', () => {
|
||||
expect(topRowEl(43.284, 1)).toBe(43.284);
|
||||
expect(topRowEl(43.284, 2)).toBe(43.227);
|
||||
expect(topRowEl(43.284, 3)).toBe(43.17);
|
||||
expect(topRowEl(43.284, 2)).toBe(43.184);
|
||||
expect(topRowEl(43.284, 3)).toBe(43.084);
|
||||
});
|
||||
|
||||
it('top bar lengths 12744 / 12629.6 / 12515.2 (path + 2 × 472 hook)', () => {
|
||||
|
||||
@@ -20,11 +20,11 @@ describe('C14 / C15 / C16 (코핑철근.md §7–8)', () => {
|
||||
expect(bars.length).toBe(38);
|
||||
});
|
||||
|
||||
it('C14 heights: upper 43.251 / 43.194, lower 42.810 / 42.310 / 41.810 / 41.310', () => {
|
||||
it('C14 heights: upper 43.208 / 43.108, lower 42.810 / 42.310 / 41.810 / 41.310 (상면 단 간격 100)', () => {
|
||||
const bars = c14Bars(L, m.copingRefTop, rows, under);
|
||||
const z = (line: number) => bars.find((b) => b.line === line)!.z;
|
||||
expect(z(1)).toBeCloseTo(43.251, 3);
|
||||
expect(z(2)).toBeCloseTo(43.194, 3);
|
||||
expect(z(1)).toBeCloseTo(43.208, 3);
|
||||
expect(z(2)).toBeCloseTo(43.108, 3);
|
||||
expect([3, 4, 5, 6].map(z)).toEqual([42.81, 42.31, 41.81, 41.31].map((v) => expect.closeTo(v, 2)));
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user