feat(rebar): B1–B4와 B5–B8 방향 교환 (B1–B4는 W 방향, B5–B8은 L 방향)
- 재료표(B5–B8 9150 = 9350 − 2c, B1–B4 7600 = 7800 − 2c)와 같은 방향 배정으로 맞춤 - 격자 키를 물리 방향으로 정리: sL = L 방향 간격, sW = W 방향 간격 (기존 sAxis → sL, sPerp → sW) - B1–B4: L 격자로 개수, 길이 W − 2c. B5–B8: W 격자로 개수, 길이 L − 2c - B9: 열(L)은 sL, 행(W)은 sW 격자 (물리 격자 일치), 개수 불변 - B11은 L 방향 간격(sL), B12는 W 방향 간격(sW) - 3D 확대기초 철근과 단면 그림의 역할을 교환 (B1–B4 선, B5–B8 점) - 철근표 간격과 규칙 값, 설정 라벨을 방향 기준으로 수정 - 테스트 기대값 갱신 (B1–B4 40, B5–B8 31, B6 13646 분할 경고) Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f2fa48913b
commit
752de2fd9d
12 files changed
+160
-167
No files matched your search
@@ -3,8 +3,8 @@
|
||||
* Defaults are the 확대기초철근 (1).md values; the ranges are proposed and pending the design-standard check.
|
||||
* Fixed values (k = 2, Δ₂ = 100, 전단 4s · 엇갈림 2s, cycle 교대 배치) are not inputs.
|
||||
*/
|
||||
/** Which grid spacing a helper uses: the 교각축 (sAxis) or the 교각축 직각 (sPerp). */
|
||||
export type FootingGridKey = 'sAxis' | 'sPerp';
|
||||
/** Which grid spacing a helper uses: along L (sL) or along W (sW). */
|
||||
export type FootingGridKey = 'sL' | 'sW';
|
||||
|
||||
export interface FootingRebarSettings {
|
||||
/** 상면 피복 (최외측 철근 중심까지, mm). */
|
||||
@@ -15,10 +15,10 @@ export interface FootingRebarSettings {
|
||||
cBottom: number;
|
||||
/** 첫 철근 최소 여유 (측면 피복 다음, mm). */
|
||||
eMin: number;
|
||||
/** 격자 실간격 · 교각축 (mm): B1–B4 along W, and the B9 grid (승인 2026-10-26). */
|
||||
sAxis: number;
|
||||
/** 격자 실간격 · 교각축 직각 (mm): B5–B8 along L, and B11·B12 (승인 2026-10-26). */
|
||||
sPerp: number;
|
||||
/** 격자 실간격 · L 방향 (mm): B1–B4 spacing, the B9 grid and B11 (승인 2026-10-26, 방향 교환). */
|
||||
sL: number;
|
||||
/** 격자 실간격 · W 방향 (mm): B5–B8 spacing and B12 (승인 2026-10-26, 방향 교환). */
|
||||
sW: number;
|
||||
/** B10 높이 간격 s_v (mm). */
|
||||
sV: number;
|
||||
/** B5 아래 최소 여유 e_top (mm). */
|
||||
@@ -36,8 +36,8 @@ export const DEFAULT_FOOTING_REBAR: FootingRebarSettings = {
|
||||
cSide: 100,
|
||||
cBottom: 150,
|
||||
eMin: 150,
|
||||
sAxis: 125,
|
||||
sPerp: 125,
|
||||
sL: 125,
|
||||
sW: 125,
|
||||
sV: 200,
|
||||
eTop: 150,
|
||||
n: 2,
|
||||
@@ -51,8 +51,8 @@ export const FOOTING_REBAR_RANGES: Record<keyof FootingRebarSettings, [number, n
|
||||
cSide: [80, 150],
|
||||
cBottom: [100, 200],
|
||||
eMin: [100, 200],
|
||||
sAxis: [100, 150],
|
||||
sPerp: [100, 150],
|
||||
sL: [100, 150],
|
||||
sW: [100, 150],
|
||||
sV: [150, 250],
|
||||
eTop: [100, 200],
|
||||
n: [1, 3],
|
||||
|
||||
+22
-21
@@ -23,7 +23,7 @@ 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, key: FootingGridKey = 'sAxis'): GridResult {
|
||||
export function grid(side: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR, key: FootingGridKey = 'sL'): GridResult {
|
||||
const s = f[key];
|
||||
const A = side - 2 * f.cSide;
|
||||
const n = Math.floor((A - 2 * f.eMin) / s);
|
||||
@@ -70,13 +70,13 @@ export interface FootingBar {
|
||||
length: number;
|
||||
}
|
||||
|
||||
/** B1–B4 (§5): the grid along W, with lengths from L. */
|
||||
/** B1–B4 (승인 2026-10-26, 방향 교환): run along W, spaced along L (grid L, sL), with lengths from W. */
|
||||
export function bottomBars(L: number, W: number, H: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR): FootingBar[] {
|
||||
const g = grid(W, f);
|
||||
const g = grid(L, f, 'sL');
|
||||
const n = g.positions;
|
||||
const N4 = Math.ceil(n / 2); // B4 at even i
|
||||
const N2 = Math.floor(n / 2); // B2 at odd i
|
||||
const l0 = L - 2 * f.cSide;
|
||||
const l0 = W - 2 * f.cSide;
|
||||
const leg2 = legB2(H, f);
|
||||
return [
|
||||
{ name: 'B1', size: 'S25', count: N2, length: l0 + 2 * legLength('S25') },
|
||||
@@ -86,13 +86,13 @@ export function bottomBars(L: number, W: number, H: number, f: FootingRebarSetti
|
||||
];
|
||||
}
|
||||
|
||||
/** B5–B8 (§6): the grid along L, with lengths from W. */
|
||||
/** B5–B8 (승인 2026-10-26, 방향 교환): run along L, spaced along W (grid W, sW), with lengths from L. */
|
||||
export function crossBars(L: number, W: number, H: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR): FootingBar[] {
|
||||
const g = grid(L, f, 'sPerp');
|
||||
const g = grid(W, f, 'sW');
|
||||
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
|
||||
const l0 = W - 2 * f.cSide;
|
||||
const l0 = L - 2 * f.cSide;
|
||||
const z = layers(H, f);
|
||||
const leg6 = z.B5 - z.B68;
|
||||
return [
|
||||
@@ -172,9 +172,9 @@ export function assemblyGridIndices(n: number, k: number, idx: number): number[]
|
||||
|
||||
export function assemblyBars(L: number, W: number, H: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR): FootingBar[] {
|
||||
const levelsJ = assemblyJs(H, f);
|
||||
// B11 is spread along L (교각축 직각 grid) and B12 along W (교각축 grid), per 확대기초철근 (1).md §8.
|
||||
const nW = grid(W, f, 'sAxis').positions - 1;
|
||||
const nL = grid(L, f, 'sPerp').positions - 1;
|
||||
// B11 is spread along L (grid L, sL) and B12 along W (grid W, sW), per 확대기초철근 (1).md §8 (after the 방향 교환).
|
||||
const nW = grid(W, f, 'sW').positions - 1;
|
||||
const nL = grid(L, f, 'sL').positions - 1;
|
||||
const b11 = levelsJ.reduce((a, _, idx) => a + assemblyGridIndices(nL, f.kB11, idx).length, 0);
|
||||
const b12 = levelsJ.reduce((a, _, idx) => a + assemblyGridIndices(nW, f.kB12, idx).length, 0);
|
||||
const hook = Math.round(hookLength('main90', d('S16'))); // 246 mm, rounded as in the document (§8.3)
|
||||
@@ -187,7 +187,7 @@ 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, key: FootingGridKey = 'sAxis'): number[] {
|
||||
export function gridPositions(side: number, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR, key: FootingGridKey = 'sL'): number[] {
|
||||
const g = grid(side, f, key);
|
||||
return Array.from({ length: g.positions }, (_, i) => -side / 2 + f.cSide + g.e + i * f[key]);
|
||||
}
|
||||
@@ -204,8 +204,9 @@ export interface B9Bar {
|
||||
* than the column radius plus half a bar to a column axis (Q-B20, applied: the 기둥 구역 is removed).
|
||||
*/
|
||||
export function b9Bars(L: number, W: number, columnX: number[], columnD: number = 2000, f: FootingRebarSettings = DEFAULT_FOOTING_REBAR): { rows: number; perRow: number[]; bars: B9Bar[] } {
|
||||
const xs = gridPositions(L, f);
|
||||
const ns = gridPositions(W, f);
|
||||
// B9: columns along L use the L grid (sL); rows along W use the W grid (sW) (방향 교환 후 물리적 격자, 승인 2026-10-26).
|
||||
const xs = gridPositions(L, f, 'sL');
|
||||
const ns = gridPositions(W, f, 'sW');
|
||||
const rowIndices: number[] = [];
|
||||
for (let i = 1; i < ns.length; i += 4) rowIndices.push(i);
|
||||
const halfBar = NOMINAL_DIAMETER.H16 / 2;
|
||||
@@ -265,8 +266,8 @@ export function assemblyHeights(H: number, f: FootingRebarSettings = DEFAULT_FOO
|
||||
* 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;
|
||||
upper2L: number;
|
||||
upper2W: number;
|
||||
delta2: number;
|
||||
b2Leg: number;
|
||||
b6Leg: number;
|
||||
@@ -279,15 +280,15 @@ export function footingRuleValues(H: number, f: FootingRebarSettings = DEFAULT_F
|
||||
} {
|
||||
const z = layers(H, f);
|
||||
return {
|
||||
upper2sAxis: 2 * f.sAxis,
|
||||
upper2sPerp: 2 * f.sPerp,
|
||||
upper2L: 2 * f.sL,
|
||||
upper2W: 2 * f.sW,
|
||||
delta2: DELTA2,
|
||||
b2Leg: legB2(H, f),
|
||||
b6Leg: z.B5 - z.B68,
|
||||
b9Pitch: 4 * f.sAxis,
|
||||
b9Stagger: 2 * f.sAxis,
|
||||
b11Pitch: f.kB11 * f.sPerp,
|
||||
b12Pitch: f.kB12 * f.sAxis,
|
||||
b9Pitch: 4 * f.sL,
|
||||
b9Stagger: 2 * f.sL,
|
||||
b11Pitch: f.kB11 * f.sL,
|
||||
b12Pitch: f.kB12 * f.sW,
|
||||
assemblyVertical: f.n * f.sV,
|
||||
assemblyLevels: assemblyJs(H, f).length,
|
||||
};
|
||||
|
||||
@@ -166,16 +166,16 @@ export function linkedSpacing(name: string, model: PierModel): Pick<RebarRow, 's
|
||||
const fd = DEFAULT_FOOTING_REBAR;
|
||||
if (/^B[1-4]$/.test(name)) {
|
||||
const cycle = name === 'B2' || name === 'B4';
|
||||
return { spacing: String(2 * fs.sAxis), actual: String(cycle ? fs.sAxis : 2 * fs.sAxis), basis: basis(fs.sAxis !== fd.sAxis) };
|
||||
return { spacing: String(2 * fs.sL), actual: String(cycle ? fs.sL : 2 * fs.sL), basis: basis(fs.sL !== fd.sL) };
|
||||
}
|
||||
if (/^B[5-8]$/.test(name)) {
|
||||
const cycle = name === 'B6' || name === 'B8';
|
||||
return { spacing: String(2 * fs.sPerp), actual: String(cycle ? fs.sPerp : 2 * fs.sPerp), basis: basis(fs.sPerp !== fd.sPerp) };
|
||||
return { spacing: String(2 * fs.sW), actual: String(cycle ? fs.sW : 2 * fs.sW), basis: basis(fs.sW !== fd.sW) };
|
||||
}
|
||||
if (name === 'B9') return { spacing: `${4 * fs.sAxis} (4s)`, actual: `${2 * fs.sAxis} (2s 엇갈림)`, basis: basis(fs.sAxis !== fd.sAxis) };
|
||||
if (name === 'B9') return { spacing: `${4 * fs.sL} (4s)`, actual: `${2 * fs.sL} (2s 엇갈림)`, basis: basis(fs.sL !== fd.sL) };
|
||||
// B11 along L uses the 교각축 직각 grid, B12 along W uses the 교각축 grid; each is k · s (승인 2026-10-26).
|
||||
if (name === 'B11') return { spacing: `${fs.kB11 * fs.sPerp} (${fs.kB11}s)`, actual: String(fs.kB11 * fs.sPerp), basis: basis(fs.sPerp !== fd.sPerp || fs.kB11 !== fd.kB11) };
|
||||
if (name === 'B12') return { spacing: `${fs.kB12 * fs.sAxis} (${fs.kB12}s)`, actual: String(fs.kB12 * fs.sAxis), basis: basis(fs.sAxis !== fd.sAxis || fs.kB12 !== fd.kB12) };
|
||||
if (name === 'B11') return { spacing: `${fs.kB11 * fs.sL} (${fs.kB11}s)`, actual: String(fs.kB11 * fs.sL), basis: basis(fs.sL !== fd.sL || fs.kB11 !== fd.kB11) };
|
||||
if (name === 'B12') return { spacing: `${fs.kB12 * fs.sW} (${fs.kB12}s)`, actual: String(fs.kB12 * fs.sW), basis: basis(fs.sW !== fd.sW || fs.kB12 !== fd.kB12) };
|
||||
if (name === 'B10-1' || name === 'B10-2') return { spacing: String(fs.sV), actual: String(fs.sV), basis: basis(fs.sV !== fd.sV) };
|
||||
if (name === 'S1') return { spacing: String(b.spacingS1), actual: String(b.spacingS1), basis: basis(b.spacingS1 !== bd.spacingS1) };
|
||||
if (name === 'S2') return { spacing: String(b.spacingS2), actual: String(b.spacingS2), basis: basis(b.spacingS2 !== bd.spacingS2) };
|
||||
|
||||
Reference in new issue
Block a user