feat(rebar): rebar strength per 규격 prefix as inputs on ③ (D SD300, H SD400, S SD500)
fyH and fyS become a grade per prefix (D · H · S), chosen from SD300 · SD400 · SD500. The defaults are the P1 values, so the P1 results do not change. Each bar takes its grade from its 규격 (fyOf). The 철근표 has a 강도 column. Older files that stored fyH / fyS are read into the grade map. Only fck is still an assumed value (I02). Approved 2026-10-23. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
398fa997e2
commit
b3533b69df
11 files changed
+102
-37
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { DEFAULT_MATERIAL, developmentLength, hookLength, Material, NOMINAL_DIAMETER, spliceLength } from './common';
|
||||
import { DEFAULT_MATERIAL, developmentLength, fyOf, hookLength, Material, NOMINAL_DIAMETER, spliceLength } from './common';
|
||||
import { layers } from './footing';
|
||||
|
||||
/**
|
||||
@@ -95,7 +95,7 @@ export function columnRebar(x: ColumnInput = COLUMN_P1, m: Material = DEFAULT_MA
|
||||
const r1 = x.D / 2 - x.c;
|
||||
const r2 = r1 - dS32;
|
||||
const zTop1 = x.Hc + x.hcop - x.eP1;
|
||||
const lD2 = developmentLength(dS32, m.fyS, m.fck);
|
||||
const lD2 = developmentLength(dS32, fyOf(m, 'S32'), m.fck);
|
||||
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;
|
||||
@@ -137,7 +137,7 @@ export function columnRebar(x: ColumnInput = COLUMN_P1, m: Material = DEFAULT_MA
|
||||
const p6Length = p6Straight + 2 * Math.round(p6Hook); // 135 mm per hook, as in the document
|
||||
|
||||
// P3 lap: Q-C6 is open; recommended = 1.3·l_d of H19 with the material inputs.
|
||||
const lapP3 = spliceLength(dH19, m.fyH, m.fck);
|
||||
const lapP3 = spliceLength(dH19, fyOf(m, 'H19'), m.fck);
|
||||
const p3Length = 2 * Math.PI * tieRadius + lapP3;
|
||||
const p5Length = 2 * Math.PI * tieRadius;
|
||||
|
||||
|
||||
@@ -1,18 +1,42 @@
|
||||
/**
|
||||
* ③ 철근배근 공통 규칙 (spec §6.2 · plan C1). Lengths in mm, stresses in MPa.
|
||||
* fck and fy are inputs. The defaults below are assumed values and must be shown as such (I02).
|
||||
* fck and the rebar grade per 규격 prefix are inputs. fck's default is an assumed value (I02); the grades' defaults are confirmed.
|
||||
*/
|
||||
/** Material inputs of ③ 공통 설정 (spec §6.2). fck and fy are inputs; the defaults are assumed values (I02). */
|
||||
/** Rebar strength choices on ③ (SD300 · SD400 · SD500, MPa). */
|
||||
export const GRADE_CHOICES = [300, 400, 500] as const;
|
||||
|
||||
/** Bar family by 규격 prefix: D · H · S. */
|
||||
export type GradeKey = 'D' | 'H' | 'S';
|
||||
|
||||
/** Material inputs of ③ 공통 설정 (spec §6.2). fck and the grade per prefix are inputs. */
|
||||
export interface Material {
|
||||
/** 콘크리트 강도 fck (MPa). */
|
||||
fck: number;
|
||||
/** H = SD400 항복강도 (MPa). */
|
||||
fyH: number;
|
||||
/** S = SD500 항복강도 (MPa). */
|
||||
fyS: number;
|
||||
/** 규격 접두어별 철근 강도 (MPa): D = SD300, H = SD400, S = SD500 (입력). */
|
||||
grade: Record<GradeKey, number>;
|
||||
}
|
||||
|
||||
export const DEFAULT_MATERIAL: Material = { fck: 27, fyH: 400, fyS: 500 };
|
||||
export const DEFAULT_MATERIAL: Material = { fck: 27, grade: { D: 300, H: 400, S: 500 } };
|
||||
|
||||
/** Yield strength (MPa) of a bar from its 규격, e.g. H19 → the H grade. */
|
||||
export function fyOf(m: Material, size: string): number {
|
||||
return m.grade[size.charAt(0) as GradeKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a material from the current shape, or from an older file that stored fyH / fyS.
|
||||
* A value outside GRADE_CHOICES falls back to the default for that prefix.
|
||||
*/
|
||||
export function materialFrom(raw: unknown): Material {
|
||||
const r = (raw ?? {}) as { fck?: unknown; grade?: Partial<Record<GradeKey, unknown>>; fyH?: unknown; fyS?: unknown };
|
||||
const pick = (v: unknown, fallback: number) => ((GRADE_CHOICES as readonly number[]).includes(v as number) ? (v as number) : fallback);
|
||||
const grade = {
|
||||
D: pick(r.grade?.D, DEFAULT_MATERIAL.grade.D),
|
||||
H: pick(r.grade?.H ?? r.fyH, DEFAULT_MATERIAL.grade.H),
|
||||
S: pick(r.grade?.S ?? r.fyS, DEFAULT_MATERIAL.grade.S),
|
||||
};
|
||||
return { fck: typeof r.fck === 'number' ? r.fck : DEFAULT_MATERIAL.fck, grade };
|
||||
}
|
||||
|
||||
/** Members that can take their own fck on ② (부재 카드). Other members always use the 공통 fck. */
|
||||
export type FckMember = 'column' | 'coping' | 'footing';
|
||||
@@ -27,9 +51,9 @@ export function materialFor(common: Material, byMember: FckByMember, member: Fck
|
||||
return { ...common, fck: byMember[member] ?? common.fck };
|
||||
}
|
||||
|
||||
/** True while the values are the assumed defaults (정보 I02 on the rebar screen). */
|
||||
/** True while fck is the assumed default (정보 I02 on the rebar screen). The grades are confirmed inputs (decision 2026-10-23). */
|
||||
export function isAssumedMaterial(m: Material): boolean {
|
||||
return m.fck === DEFAULT_MATERIAL.fck && m.fyH === DEFAULT_MATERIAL.fyH && m.fyS === DEFAULT_MATERIAL.fyS;
|
||||
return m.fck === DEFAULT_MATERIAL.fck;
|
||||
}
|
||||
|
||||
export const MATERIAL_DEFAULTS = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DEFAULT_MATERIAL, hookLength, Material, NOMINAL_DIAMETER, spliceLength } from './common';
|
||||
import { DEFAULT_MATERIAL, fyOf, hookLength, Material, NOMINAL_DIAMETER, spliceLength } from './common';
|
||||
|
||||
/**
|
||||
* C1–C8 상·하면 주철근 (plan C3 continued). Source: RAG/코핑철근.md §5, 2026-10-22 최종 정리.
|
||||
@@ -73,7 +73,7 @@ export function topBarLength(L: number, k: number): number {
|
||||
*/
|
||||
export function bottomPiece(m: Material = DEFAULT_MATERIAL): { path: number; ls: number; piece: number } {
|
||||
const path = 2 * MAIN.slopeEach + MAIN.level;
|
||||
const ls = spliceLength(NOMINAL_DIAMETER.H29, m.fyH, m.fck);
|
||||
const ls = spliceLength(NOMINAL_DIAMETER.H29, fyOf(m, 'H29'), m.fck);
|
||||
const lh = hookLength('main90', NOMINAL_DIAMETER.H29);
|
||||
return { path, ls, piece: path / 2 + ls / 2 + lh };
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* 코핑 철근 (plan C3). Source: RAG/코핑철근.md, 2026-10-22 최종 정리 (spec §6.4 is older and is not used here).
|
||||
* Positions are along the coping length from its start, in mm.
|
||||
*/
|
||||
import { DEFAULT_MATERIAL, developmentLength, hookLength, Material, NOMINAL_DIAMETER } from './common';
|
||||
import { DEFAULT_MATERIAL, developmentLength, fyOf, hookLength, Material, NOMINAL_DIAMETER } from './common';
|
||||
export const COPING_REBAR = {
|
||||
/** 피복 (최외측 철근 중심까지). */
|
||||
cover: 100,
|
||||
@@ -144,7 +144,7 @@ export const C14_INSET = COPING_REBAR.cover + (NOMINAL_DIAMETER.H25 + NOMINAL_DI
|
||||
|
||||
/** Development length l_d of H19 (882 for fy 400, fck 27), rounded to mm as the document does (§7.2). */
|
||||
export function stepDevLength(m: Material = DEFAULT_MATERIAL): number {
|
||||
return Math.round(developmentLength(NOMINAL_DIAMETER.H19, m.fyH, m.fck));
|
||||
return Math.round(developmentLength(NOMINAL_DIAMETER.H19, fyOf(m, 'H19'), m.fck));
|
||||
}
|
||||
|
||||
export interface C14Bar {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { bottomPiece, topBarLength, widthLayout } from './coping-main';
|
||||
import { shearBars, shearBarsMulti, copingSideBars, SIDE_HOOK_LEG, c14Bars, c14Length, stairBars, stepDevLength, undersideAt, shearULength, capLength, PIECES_PER_POSITION } from './coping';
|
||||
import { columnRebar, COLUMN_P1 } from './column';
|
||||
import { bottomBars, crossBars, sideBars, assemblyBars, shearB9 } from './footing';
|
||||
import { DEFAULT_MATERIAL, FckByMember, isAssumedMaterial, Material, materialFor, splitPieces } from './common';
|
||||
import { DEFAULT_MATERIAL, FckByMember, fyOf, isAssumedMaterial, Material, materialFor, splitPieces } from './common';
|
||||
|
||||
/** 근거 badge (spec §6.1): where the value comes from. */
|
||||
export type Basis = 'input' | 'default' | 'calc' | 'assumed';
|
||||
@@ -126,7 +126,7 @@ export function rebarSummary(
|
||||
// The I02 note stays while the common values are the assumed ones, unless every fck-bearing member has its own fck.
|
||||
const ownFck = (['column', 'coping', 'footing'] as const).every((k) => byMember[k] !== undefined);
|
||||
if (isAssumedMaterial(common) && !ownFck) {
|
||||
warnings.push({ code: 'I02', message: `fck ${common.fck} MPa · fy ${common.fyH} / ${common.fyS} MPa는 가정값입니다. 정착·이음 길이에 반영됩니다. 공통 설정에서 확인하세요.`, target: 'common' });
|
||||
warnings.push({ code: 'I02', message: `fck ${common.fck} MPa는 가정값입니다. 정착·이음 길이에 반영됩니다. 공통 설정에서 확인하세요.`, target: 'common' });
|
||||
}
|
||||
const L = model.copingL * 1000;
|
||||
const B = model.copingB * 1000;
|
||||
@@ -228,7 +228,7 @@ export function rebarSummary(
|
||||
}
|
||||
}
|
||||
for (const b of agg.values()) {
|
||||
const split = splitPieces(b.length, 25.4, mFooting.fyS, mFooting.fck, STANDARD_BAR);
|
||||
const split = splitPieces(b.length, 25.4, fyOf(mFooting, b.size), mFooting.fck, STANDARD_BAR);
|
||||
if (split && b.length > STANDARD_BAR && b.name !== 'B9') {
|
||||
rows.push({ member: 'footing', name: b.name, size: b.size, count: b.count, length: split.pieceLength, note: `${b.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).`, target: 'footing', bar: b.name });
|
||||
|
||||
Reference in new issue
Block a user