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:
ypshimandClaude Haiku 5.5 committed 2026-10-23 10:13:16 +09:00
1 parent 03bb1f9929
commit 30e5e75c22
7 files changed
+146 -21

No files matched your search

+20 -1
View File
@@ -13,7 +13,7 @@ import { pileGeometry } from './core/geometry';
import { rebarSummary, type RebarRow } from './core/rebar/summary';
import { shearSegments } from './core/rebar/coping';
import { buildRebar3D, type RebarColorMode, type RebarScene } from './view/rebar3d';
import { DEFAULT_MATERIAL, FCK_MEMBERS, fyOf, GRADE_CHOICES, isAssumedMaterial, materialFrom, type FckByMember, type FckMember, type GradeKey, type Material } from './core/rebar/common';
import { DEFAULT_MATERIAL, FCK_MEMBERS, fyOf, GRADE_CHOICES, isAssumedMaterial, materialFrom, type BendFactors, type FckByMember, type FckMember, type GradeKey, type Material } from './core/rebar/common';
import { allVisibleChecked, setVisibleChecked, type TypeFilter } from './core/selection';
import { choose, defaultSummary, isSelectable, SHAPE_GROUPS, UNDEFINED_REASON, type MemberId } from './core/shape-options';
import { parseProject, SCHEMA_VERSION, serializeProject, type ProjectFile, type ProjectInfo } from './core/project';
@@ -1000,6 +1000,9 @@ function renderMaterial(): void {
for (const k of ['d', 'h', 's'] as const) {
$<HTMLSelectElement>(`mat-grade-${k}`).value = String(m.grade[k.toUpperCase() as GradeKey]);
}
for (const k of ['small16', 'main25', 'main35', 'main51'] as const) {
$<HTMLInputElement>(`bend-${k}`).value = String(m.bend[k]);
}
$('mat-note').textContent = assumed ? 'fck 가정값 (I02): 입력을 바꾸면 정착·이음 길이가 달라집니다.' : '입력값을 사용합니다.';
}
@@ -1047,6 +1050,19 @@ function renderMemberFck(box: HTMLDivElement, member: FckMember): void {
box.appendChild(row);
}
/** Bend factor (× diameter) input on 공통 설정. Must be a positive number. */
function setBend(key: keyof BendFactors, raw: string): void {
const value = Number(raw);
if (!Number.isFinite(value) || value <= 0) {
setStatus('굽힘 내면반경 배수는 0보다 큰 숫자여야 합니다.');
renderMaterial();
return;
}
state.material = { ...state.material, bend: { ...state.material.bend, [key]: value } };
setupScene();
renderAll();
}
function setMaterial(key: 'fck' | GradeKey, raw: string): void {
const value = Number(raw);
const valid = key === 'fck' ? Number.isFinite(value) && value > 0 : (GRADE_CHOICES as readonly number[]).includes(value);
@@ -1461,6 +1477,9 @@ $<HTMLButtonElement>('nav-shape').addEventListener('click', () => setStage('shap
$<HTMLButtonElement>('nav-plan').addEventListener('click', () => setStage('plan'));
$<HTMLButtonElement>('nav-rebar').addEventListener('click', () => setStage('rebar'));
$<HTMLInputElement>('mat-fck').addEventListener('change', (ev) => setMaterial('fck', (ev.target as HTMLInputElement).value));
for (const k of ['small16', 'main25', 'main35', 'main51'] as const) {
$<HTMLInputElement>(`bend-${k}`).addEventListener('change', (ev) => setBend(k, (ev.target as HTMLInputElement).value));
}
for (const k of ['D', 'H', 'S'] as const) {
$<HTMLSelectElement>(`mat-grade-${k.toLowerCase()}`).addEventListener('change', (ev) => setMaterial(k, (ev.target as HTMLSelectElement).value));
}