feat(core,view): per-row pile counts 열별 본수 (plan C4)
- A 열 is one row across the footing width; each has its own count along the length. Default floor((L − 1400) / 2250) + 1 per 열, as in spec §4.6. - Counts are validated: one per 열, whole numbers 2–30. Spacing below the 2250 mm minimum is shown as a warning, not refused (the plan's 6본 → 5@1800 example). - PierInput gains an optional pileRows; absent means the defaults, so existing files and the P1 results are unchanged. - Change tracking compares arrays by value; 열별 본수 can be reverted and copied (copy item off by default). - The footing card has −/+ per 열 with spacing, total, and the display string. - Tests: defaults 4열 × 5본 = 20 and the 1단계 text; 6본 → 5@1800; limits; model-level 21 piles. - Not verified in a browser. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5b162c2441
commit
17b5b24682
9 files changed
+256
-39
No files matched your search
+20
-25
@@ -1,4 +1,5 @@
|
||||
import { buildAxis, copingSpan, fromAxis, kinkArc, nearKink, toAxis } from './axis';
|
||||
import { layoutText, resolveRowCounts, rowLayout, type PileGeometry } from './piles';
|
||||
import type { PierInput, Row } from './types';
|
||||
|
||||
/** Dimensions in m. Sources: intent.PR sheet (P1 rules) and spec.md §3 defaults. */
|
||||
@@ -363,7 +364,9 @@ export function buildPier(input: PierInput): PierModel {
|
||||
thickness: DIM.blindingT,
|
||||
});
|
||||
if (input.foundationType === '말뚝기초') {
|
||||
piles.push(...pilesFor(f.s, input.footingBottomEl, pileLength, f.length).map((p) => ({ ...p, k: f.k })));
|
||||
const g = pileGeometry(f.length);
|
||||
const counts = resolveRowCounts(input.pileRows, g);
|
||||
piles.push(...pilesFor(f.s, input.footingBottomEl, pileLength, g, counts).map((p) => ({ ...p, k: f.k })));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,7 +422,7 @@ export function buildPier(input: PierInput): PierModel {
|
||||
columnHeight: levelBottom - columns[0].bottom,
|
||||
soilCover: input.groundEl - (input.foundationType === '현장타설말뚝' ? input.footingBottomEl : footingTop),
|
||||
pileCount: piles.length,
|
||||
pileLayout: input.foundationType === '말뚝기초' ? pileLayoutText(footings[0].length) : null,
|
||||
pileLayout: input.foundationType === '말뚝기초' ? layoutText(resolveRowCounts(input.pileRows, pileGeometry(footings[0].length)), pileGeometry(footings[0].length)) : null,
|
||||
pileTipEl: piles.length ? pileTip : null,
|
||||
blockHeightFront,
|
||||
blockHeightBack,
|
||||
@@ -460,38 +463,30 @@ export function footingGroups(colS: number[]): { s: number; length: number }[] {
|
||||
* Piles under one footing (spec §4.6): rows across the footing width, piles along the length,
|
||||
* both with an end distance of 0.7 m and an even spacing that never exceeds 2.25 m.
|
||||
*/
|
||||
export function pileGrid(footingLength: number = DIM.footingL): { countS: number; countN: number; spacingS: number; spacingN: number } {
|
||||
const span = (size: number) => Math.floor((size - 2 * DIM.pileEnd) / DIM.pileSpacing) + 1;
|
||||
const countS = span(footingLength);
|
||||
const countN = span(DIM.footingW);
|
||||
return {
|
||||
countS,
|
||||
countN,
|
||||
spacingS: (footingLength - 2 * DIM.pileEnd) / (countS - 1),
|
||||
spacingN: (DIM.footingW - 2 * DIM.pileEnd) / (countN - 1),
|
||||
};
|
||||
/** Pile geometry of one footing, from the 1단계 constants (spec §4.6). */
|
||||
export function pileGeometry(footingLength: number): PileGeometry {
|
||||
return { footingLength, footingWidth: DIM.footingW, end: DIM.pileEnd, minSpacing: DIM.pileSpacing };
|
||||
}
|
||||
|
||||
/** Display string such as "4@2250 × 3@2250 = 20본" (gaps along the length × gaps across the width). */
|
||||
export function pileLayoutText(footingLength: number = DIM.footingL): string {
|
||||
const g = pileGrid(footingLength);
|
||||
return `${g.countS - 1}@${Math.round(g.spacingS * 1000)} × ${g.countN - 1}@${Math.round(g.spacingN * 1000)} = ${g.countS * g.countN}본`;
|
||||
}
|
||||
|
||||
export function pilesFor(s: number, topEl: number, length: number, footingLength: number = DIM.footingL): PileModel[] {
|
||||
const { countS, countN, spacingS, spacingN } = pileGrid(footingLength);
|
||||
/**
|
||||
* Piles under one footing (spec §4.6): one 열 per row across the width, each with its own count along the length.
|
||||
* counts holds the 본수 of each 열 (see core/piles.ts).
|
||||
*/
|
||||
export function pilesFor(s: number, topEl: number, length: number, g: PileGeometry, counts: number[]): PileModel[] {
|
||||
const rows = rowLayout(counts, g);
|
||||
const spacingN = (g.footingWidth - 2 * g.end) / (counts.length - 1);
|
||||
const out: PileModel[] = [];
|
||||
for (let i = 0; i < countS; i++) {
|
||||
for (let j = 0; j < countN; j++) {
|
||||
rows.forEach((row, j) => {
|
||||
for (let i = 0; i < row.count; i++) {
|
||||
out.push({
|
||||
s: s + (i - (countS - 1) / 2) * spacingS,
|
||||
s: s + (i - (row.count - 1) / 2) * row.spacing,
|
||||
k: 0,
|
||||
n: (j - (countN - 1) / 2) * spacingN,
|
||||
n: (j - (counts.length - 1) / 2) * spacingN,
|
||||
top: topEl,
|
||||
bottom: topEl - length,
|
||||
diameter: DIM.pileDiameter,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return out;
|
||||
}
|
||||
Reference in new issue
Block a user