feat(view): round bar bends at the centre-line radius; bend factors as inputs on ③
Bars drawn through several points are one tube each, with every bend rounded by R·tan(φ/2) at the centre-line radius (inner factor × d + d/2). The inside-radius factors (D16 and below, D19–D25, D29–D35, D38 and above) are inputs in 공통 설정, with KDS-based defaults 2 / 3 / 4 / 5. The size-class limits sit in one place (SIZE_CLASS), which also fixes D25 (25.4) being read as the D29–D35 class in hookLength. The helper bendDeduction gives the centre-line deduction for the length option, which is not yet applied to the 철근표 lengths. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
03bb1f9929
commit
30e5e75c22
7 files changed
+146
-21
No files matched your search
@@ -8,15 +8,50 @@ 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. */
|
||||
/**
|
||||
* Inside bend radius as a multiple of the nominal diameter (입력, 2026-10-23). Defaults follow KDS 14 20 52 as
|
||||
* recorded in the plan; confirm against the code. small16 is for D16 and below (ties and stirrups).
|
||||
*/
|
||||
export interface BendFactors {
|
||||
small16: number;
|
||||
main25: number;
|
||||
main35: number;
|
||||
main51: number;
|
||||
}
|
||||
|
||||
export const DEFAULT_BEND: BendFactors = { small16: 2, main25: 3, main35: 4, main51: 5 };
|
||||
|
||||
/**
|
||||
* Size classes by nominal diameter (mm). The limits lie between the sizes: D16 15.9, D25 25.4, D29 28.6, D35 34.9,
|
||||
* so 26 and 36 separate D25 from D29 and D35 from D38.
|
||||
*/
|
||||
export const SIZE_CLASS = { small: 17, d25: 26, d35: 36 } as const;
|
||||
|
||||
/** Centre-line bend radius (mm) of a bar of nominal diameter db: inner radius (factor × db) + db/2. */
|
||||
export function bendRadius(db: number, bend: BendFactors): number {
|
||||
const factor = db <= SIZE_CLASS.small ? bend.small16 : db <= SIZE_CLASS.d25 ? bend.main25 : db <= SIZE_CLASS.d35 ? bend.main35 : bend.main51;
|
||||
return factor * db + db / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Length the centre line loses at a bend of deflection phi (rad) compared with the sharp corner of the same bar:
|
||||
* 2R·tan(φ/2) − Rφ. For a 90° bend this is (2 − π/2)·R ≈ 0.429 R. Used by the centre-line length option.
|
||||
*/
|
||||
export function bendDeduction(phi: number, R: number): number {
|
||||
return 2 * R * Math.tan(phi / 2) - R * phi;
|
||||
}
|
||||
|
||||
/** Material inputs of ③ 공통 설정 (spec §6.2). fck, the grade per prefix and the bend factors are inputs. */
|
||||
export interface Material {
|
||||
/** 콘크리트 강도 fck (MPa). */
|
||||
fck: number;
|
||||
/** 규격 접두어별 철근 강도 (MPa): D = SD300, H = SD400, S = SD500 (입력). */
|
||||
grade: Record<GradeKey, number>;
|
||||
/** 굽힘 내면반경 배수 (입력). */
|
||||
bend: BendFactors;
|
||||
}
|
||||
|
||||
export const DEFAULT_MATERIAL: Material = { fck: 27, grade: { D: 300, H: 400, S: 500 } };
|
||||
export const DEFAULT_MATERIAL: Material = { fck: 27, grade: { D: 300, H: 400, S: 500 }, bend: DEFAULT_BEND };
|
||||
|
||||
/** Yield strength (MPa) of a bar from its 규격, e.g. H19 → the H grade. */
|
||||
export function fyOf(m: Material, size: string): number {
|
||||
@@ -28,14 +63,21 @@ export function fyOf(m: Material, size: string): number {
|
||||
* 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 r = (raw ?? {}) as { fck?: unknown; grade?: Partial<Record<GradeKey, unknown>>; fyH?: unknown; fyS?: unknown; bend?: Partial<Record<keyof BendFactors, unknown>> };
|
||||
const factor = (v: unknown, fallback: number) => (typeof v === 'number' && v > 0 ? v : fallback);
|
||||
const bend: BendFactors = {
|
||||
small16: factor(r.bend?.small16, DEFAULT_BEND.small16),
|
||||
main25: factor(r.bend?.main25, DEFAULT_BEND.main25),
|
||||
main35: factor(r.bend?.main35, DEFAULT_BEND.main35),
|
||||
main51: factor(r.bend?.main51, DEFAULT_BEND.main51),
|
||||
};
|
||||
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 };
|
||||
return { fck: typeof r.fck === 'number' ? r.fck : DEFAULT_MATERIAL.fck, grade, bend };
|
||||
}
|
||||
|
||||
/** Members that can take their own fck on ② (부재 카드). Other members always use the 공통 fck. */
|
||||
@@ -106,8 +148,8 @@ export type HookKind = 'main90' | 'tie90' | 'stirrup135';
|
||||
*/
|
||||
export function hookLength(kind: HookKind, db: number): number {
|
||||
if (kind === 'main90') {
|
||||
if (db <= 25) return 15.5 * db;
|
||||
if (db <= 35) return 16.5 * db;
|
||||
if (db <= SIZE_CLASS.d25) return 15.5 * db;
|
||||
if (db <= SIZE_CLASS.d35) return 16.5 * db;
|
||||
throw new Error(`주철근 90° 갈고리 표에 없는 지름입니다 (D${db}).`);
|
||||
}
|
||||
if (kind === 'tie90') {
|
||||
|
||||
Reference in new issue
Block a user