feat(rebar): 확대기초 패널 규칙 값 표시 (상면·2단, B2·B6 디리, B9, 조립 단 수) 및 "규칙" 표기

- footingRuleValues: 패널 표시값을 계산 함수에서 직접 읽음 (새 공식 없음)
- B2·B6 디리 두 값, 조립 단 수(3단) 표시
- "(고정)"은 Δ₂ 100에만 사용, 4s·2s·상면 2s는 "(규칙)"으로 표기
- 테스트: 기본값 P1에서 250 · 100 · 1723 · 500·250 · 500·3단 @400

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-26 17:23:57 +09:00
1 parent ddd6d55a72
commit 48e6811600
3 files changed
+57 -11

No files matched your search

+31
View File
@@ -232,3 +232,34 @@ export function assemblyHeights(H: number, f: FootingRebarSettings = DEFAULT_FOO
const B12 = B11.map((z) => z + NOMINAL_DIAMETER.S19);
return { B11, B12 };
}
/**
* Values shown on the 확대기초 panel as rules and derived values (승인 2026-10-26). Each is read from the same functions the
* rebar table and the 3D view use, so the panel cannot drift from the calculation. H is the footing height (mm).
*/
export function footingRuleValues(H: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR): {
upper2sAxis: number;
upper2sPerp: number;
delta2: number;
b2Leg: number;
b6Leg: number;
b9Pitch: number;
b9Stagger: number;
assemblyPlanPitch: number;
assemblyVertical: number;
assemblyLevels: number;
} {
const z = layers(H, f);
return {
upper2sAxis: 2 * f.sAxis,
upper2sPerp: 2 * f.sPerp,
delta2: DELTA2,
b2Leg: legB2(H, f),
b6Leg: z.B5 - z.B68,
b9Pitch: 4 * f.sAxis,
b9Stagger: 2 * f.sAxis,
assemblyPlanPitch: 4 * f.sPerp,
assemblyVertical: f.n * f.sV,
assemblyLevels: assemblyJs(H, f).length,
};
}
+16 -10
View File
@@ -31,7 +31,7 @@ import { COPING_REBAR_RANGES, copingSettingsIssues, type CopingRebarSettings, DE
import { COLUMN_REBAR_RANGES, type ColumnRebarSettings, columnSettingsIssues, DEFAULT_COLUMN_REBAR } from './core/rebar/column-settings';
import { columnInputFor, columnRebar } from './core/rebar/column';
import { DEFAULT_FOOTING_REBAR, FOOTING_REBAR_RANGES, type FootingRebarSettings, footingSettingsIssues } from './core/rebar/footing-settings';
import { legB2 } from './core/rebar/footing';
import { footingRuleValues } from './core/rebar/footing';
import { columnElevationSvg } from './view/column-elevation-svg';
import { type ColumnSection, columnSectionSvg } from './view/column-section-svg';
import { groundSectionSvg } from './view/ground-svg';
@@ -1339,15 +1339,21 @@ function renderFootingSettings(box: HTMLDivElement, pier: Pier): void {
// Fixed rules and derived values (읽기 전용). Derived from the current settings of the first footing.
const fs = current;
const fixed = el('div', undefined, 'muted small');
const H = pier.model.footings[0] ? (pier.model.footings[0].top - pier.model.footings[0].bottom) * 1000 : undefined;
fixed.textContent = [
`B1–B4 간격 2·s (고정) ${2 * fs.sAxis} mm · B5–B8 간격 2·s (고정) ${2 * fs.sPerp} mm`,
`하면 1·2단 간격 Δ₂ (고정) 100 mm`,
`전단 B9 간격 4s · 행 엇갈림 2s (고정) ${4 * fs.sAxis} · ${2 * fs.sAxis} mm`,
`조립 평면 간격 4s · 연직 n·s_v (자동) ${4 * fs.sPerp} · ${fs.n * fs.sV} mm`,
`cycle 배치: 교대 배치 (고정)`,
H === undefined ? 'B2·B6 디리 (자동): 확대기초 없음' : `B2·B6 디리 (자동) z_B1 − z_B24 = ${legB2(H, fs)} mm`,
].join(' · ');
const foot = pier.model.footings[0];
const H = foot ? (foot.top - foot.bottom) * 1000 : undefined;
if (H === undefined) {
fixed.textContent = '확대기초 없음 · 확대기초 규칙을 표시하지 않습니다';
} else {
const r = footingRuleValues(H, fs);
fixed.textContent = [
`상면·2단 간격 B1·B3 = 2·s교각축 ${r.upper2sAxis} mm · B5·B7 = 2·s교각축직각 ${r.upper2sPerp} mm (규칙)`,
`하면 1·2단 간격 Δ₂ = ${r.delta2} mm (고정)`,
`B2 디리 ${r.b2Leg} mm · B6 디리 ${r.b6Leg} mm (자동, B1·B5 높이까지)`,
`B9 간격 4·s교각축 ${r.b9Pitch} · 행 엇갈림 2·s교각축 ${r.b9Stagger} mm (규칙)`,
`B11·B12 평면 간격 4·s교각축직각 ${r.assemblyPlanPitch} · 연직 n·s_v ${r.assemblyVertical} mm · 조립 단 ${r.assemblyLevels}단 (자동)`,
'cycle 배치: 교대 배치 (고정)',
].join(' · ');
}
wrap.appendChild(fixed);
const msg = el('p', undefined, 'muted small');
const apply = el('button', '적용', 'btn small');
+10 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import { buildPier } from '../src/core/geometry';
import { assemblyJs, gridPositions } from '../src/core/rebar/footing';
import { assemblyJs, footingRuleValues, gridPositions } from '../src/core/rebar/footing';
import { DEFAULT_FOOTING_REBAR, FOOTING_REBAR_RANGES, footingSettingsIssues } from '../src/core/rebar/footing-settings';
import { rebarSummary } from '../src/core/rebar/summary';
import { loadP1 } from './helpers';
@@ -58,6 +58,15 @@ describe('확대기초 배근 입력 (승인 2026-10-26, 시안 ③ 확대기초
expect(rowsAxis.find((r) => r.name === 'B5')!.basis).toBe('default');
});
it('패널 규칙 값 (P1, H 2000): 상면·2단 250 · Δ₂ 100 · B2·B6 1723 · B9 500·250 · 조립 500 · 3단 @400', () => {
const r = footingRuleValues(2000, DEFAULT_FOOTING_REBAR);
expect([r.upper2sAxis, r.upper2sPerp, r.delta2]).toEqual([250, 250, 100]);
expect(r.b2Leg).toBeCloseTo(1723, 0);
expect(r.b6Leg).toBeCloseTo(1723, 0);
expect([r.b9Pitch, r.b9Stagger]).toEqual([500, 250]);
expect([r.assemblyPlanPitch, r.assemblyVertical, r.assemblyLevels]).toEqual([500, 400, 3]);
});
it('the 조립 단 배수 n reaches the assembly levels', () => {
const H = 2000;
const base = assemblyJs(H, DEFAULT_FOOTING_REBAR);