feat(rebar): 격자 실간격을 교각축(B1–B4·B9)과 교각축 직각(B5–B8·B11·B12)으로 나눠 입력

- footing-settings: s → sAxis(교각축) · sPerp(교각축 직각), 범위는 동일 (100–150)
- grid·gridPositions가 방향 키를 받음. B1–B4 grid는 sAxis, B5–B8 grid는 sPerp, B9 행·열은 sAxis, B11·B12는 sPerp
- 철근표 간격·실간격과 근거가 방향별 값을 씀 (B12는 교각축 직각 값, 승인 2026-10-26)
- 3D 확대기초 그림의 위치도 방향별 값을 씀
- 패널 입력 두 칸으로 분리

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-26 17:10:31 +09:00
1 parent c40c58d27f
commit ddd6d55a72
7 files changed
+59 -32

No files matched your search

+11 -10
View File
@@ -1,5 +1,5 @@
import { hookLength, NOMINAL_DIAMETER, type BarSize } from './common';
import { DEFAULT_FOOTING_REBAR, type FootingRebarSettings } from './footing-settings';
import { DEFAULT_FOOTING_REBAR, type FootingGridKey, type FootingRebarSettings } from './footing-settings';
/**
* 확대기초 철근 B1–B8, B10–B12 (plan C5). Source: RAG/확대기초철근 (1).md, 2026-10-22 최종 정리.
@@ -23,10 +23,11 @@ export interface GridResult {
}
/** Grid along one side of the footing (§3.1). side = W for B1–B4, L for B5–B8. */
export function grid(side: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR): GridResult {
export function grid(side: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR, key: FootingGridKey = 'sAxis'): GridResult {
const s = f[key];
const A = side - 2 * f.cSide;
const n = Math.floor((A - 2 * f.eMin) / f.s);
const G = n * f.s;
const n = Math.floor((A - 2 * f.eMin) / s);
const G = n * s;
const e = (A - G) / 2;
return { n, G, e, positions: n + 1 };
}
@@ -87,7 +88,7 @@ export function bottomBars(L: number, W: number, H: number, f: FootingRebarSetti
/** B5–B8 (§6): the grid along L, with lengths from W. */
export function crossBars(L: number, W: number, H: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR): FootingBar[] {
const g = grid(L, f);
const g = grid(L, f, 'sPerp');
const n = g.positions;
const N8 = Math.ceil(n / 2); // B8 at even i
const N6 = Math.floor(n / 2); // B6, B5, B7 at odd i
@@ -144,8 +145,8 @@ export function assemblyBars(L: number, W: number, H: number, f: FootingRebarSet
const i0 = idx % 2 === 0 ? startOdd : startEven;
return Math.floor((n - i0) / 4) + 1;
});
const nW = grid(W, f).positions - 1; // 61
const nL = grid(L, f).positions - 1; // 79
const nW = grid(W, f, 'sPerp').positions - 1; // 61 (B12 uses the 교각축 직각 value, 승인 2026-10-26)
const nL = grid(L, f, 'sPerp').positions - 1; // 79 (B11 along L)
// B11 is spread along L (n = 79) and B12 along W (n = 61); each level has its own count.
const b11 = perLevel(nL, 0, 2).reduce((a, b) => a + b, 0);
const b12 = perLevel(nW, 0, 2).reduce((a, b) => a + b, 0);
@@ -159,9 +160,9 @@ export function assemblyBars(L: number, W: number, H: number, f: FootingRebarSet
}
/** Plane positions of the grid along one side, mm from the footing centre: x_i = −side/2 + c_s + e + i·s (§3.1). */
export function gridPositions(side: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR): number[] {
const g = grid(side, f);
return Array.from({ length: g.positions }, (_, i) => -side / 2 + f.cSide + g.e + i * f.s);
export function gridPositions(side: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR, key: FootingGridKey = 'sAxis'): number[] {
const g = grid(side, f, key);
return Array.from({ length: g.positions }, (_, i) => -side / 2 + f.cSide + g.e + i * f[key]);
}
/** B9 bar of the rule (§9.1, Q-B18): a vertical bar at (x, n), mm from the footing centre. */