feat(ground): pile-tip embedment check and soil layers from the ground model

- ground.ts: G04 when a pile tip is above the 연암 상면 minus 1.0 × D; G05
  (info) when layers are entered but there is no 연암 row. No message while
  no layers are entered at all.
- ground-model.ts: reads the Python soil.layers as strata rows; the project
  file keeps and checks them.
- ② card: a button fills the layer rows from the ground model for the pier.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-26 10:35:41 +09:00
1 parent 16ab317094
commit 325c841733
6 files changed
+152 -5

No files matched your search

+34
View File
@@ -1,3 +1,4 @@
import type { PierModel } from './geometry';
import type { Issue, PierInput } from './types';
/** 위치 choices of the 지반·지층 card (시안 2026-10-26). */
@@ -9,6 +10,9 @@ export const STRATA_NAMES = ['매립토', '퇴적토', '풍화토', '풍화암',
/** The 지지층 for the pile tip check (지반 모델 G-7). */
export const SUPPORT_STRATUM = '연암';
/** 근입 = 이 값 × 말뚝 지름 (지반 모델 G-7, embed_d 1.0). */
export const PILE_EMBED_D = 1.0;
/**
* 지반·지층 입력 검사 (승인 2026-10-26).
* G01: 층 하단 EL은 위 경계보다 낮아야 함. G02: 지하수위는 지반고와 가장 아래 층 사이에 있어야 함.
@@ -37,3 +41,33 @@ export function validateGround(input: PierInput, issues: Issue[]): void {
}
}
}
/**
* 말뚝 선단 근입 (승인 2026-10-26): every pile tip must be at least PILE_EMBED_D × D below the 연암 상면.
* G04: a tip above that limit. G05 (info): piles but no 연암 row, so the embedment is not checked.
* The 연암 상면 is the bottom of the row above the 연암 row (ground EL for the first row).
*/
export function validatePileEmbedment(input: PierInput, model: PierModel, issues: Issue[]): void {
if (model.piles.length === 0) return;
const rows = input.strataRows ?? [];
const k = rows.findIndex((r) => r.name === SUPPORT_STRATUM);
if (k < 0) {
// No layers entered yet: nothing to say. Layers entered but no 연암 row: say so.
if (rows.length > 0) {
issues.push({ code: 'G05', level: 'I', pier: input.name, message: '연암 행이 없어 말뚝 선단 근입을 확인하지 않았습니다.' });
}
return;
}
const top = k === 0 ? input.groundEl : rows[k - 1].bottomEl;
const deepest = Math.max(...model.piles.map((p) => p.bottom));
const diameter = Math.max(...model.piles.map((p) => p.diameter));
const limit = top - PILE_EMBED_D * diameter;
if (deepest > limit + 1e-9) {
issues.push({
code: 'G04',
level: 'W',
pier: input.name,
message: `말뚝 선단 EL ${deepest.toFixed(3)}이 연암 상면 ${top.toFixed(3)} − 근입 ${(PILE_EMBED_D * diameter).toFixed(3)} = ${limit.toFixed(3)}보다 높습니다.`,
});
}
}