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

+43 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { groundElFor, parseGroundModel } from '../src/core/ground-model';
import { groundElFor, parseGroundModel, strataRowsFor } from '../src/core/ground-model';
import { changedKeys, overrideKeys, revertDraft, type PierValues } from '../src/core/changes';
import { parseProject, serializeProject, SCHEMA_VERSION, type ProjectFile } from '../src/core/project';
import { loadP1 } from './helpers';
@@ -151,3 +151,45 @@ describe('프로젝트 파일의 지반 모델', () => {
expect(parseProject(serializeProject(project({}))).groundModel).toBeUndefined();
});
});
describe('지반 모델의 지층 기둥 (soil.layers)', () => {
const WITH_SOIL = JSON.stringify({
schema: 2,
piers: [{
id: 'P1',
ground: { center: 29.355, excel: 28.931 },
soil: { layers: [{ name: '매립토', top_el: 29.355, bottom_el: 27.5 }, { name: '연암', top_el: 27.5, bottom_el: 10 }] },
}],
});
it('reads the layers as strata rows (name and bottom EL, top to bottom)', () => {
const m = parseGroundModel(WITH_SOIL);
expect(strataRowsFor(m, 'P1')).toEqual([{ name: '매립토', bottomEl: 27.5 }, { name: '연암', bottomEl: 10 }]);
expect(strataRowsFor(m, 'P9')).toBeUndefined();
});
it('a pier without a soil column has no layers', () => {
expect(strataRowsFor(parseGroundModel(SAMPLE), 'P1')).toBeUndefined();
});
it('refuses a soil layers entry that is not a list', () => {
const data = JSON.parse(WITH_SOIL);
data.piers[0].soil.layers = { x: 1 };
expect(() => parseGroundModel(JSON.stringify(data))).toThrow('지층(soil.layers) 형식');
});
it('keeps the layers in a saved project and refuses a damaged layer', () => {
const m = parseGroundModel(WITH_SOIL);
const text = serializeProject({
schemaVersion: SCHEMA_VERSION,
project: { name: 'x', bridge: '운곡교', client: '', author: '', crs: 'KATEC', memo: '' },
source: { fileName: 'x.xlsx', sheets: [] },
piers: [{ id: 'P1', input: loadP1() }],
history: [],
groundModel: m,
});
expect(strataRowsFor(parseProject(text).groundModel!, 'P1')).toEqual(strataRowsFor(m, 'P1'));
const bad = text.replace('"bottomEl": 10', '"bottomEl": "10"');
expect(() => parseProject(bad)).toThrow('지층 값이 맞지 않습니다');
});
});