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:
1 parent
16ab317094
commit
325c841733
6 files changed
+152
-5
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { buildPier } from '../src/core/geometry';
|
||||
import { validateGround } from '../src/core/ground';
|
||||
import { validateGround, validatePileEmbedment } from '../src/core/ground';
|
||||
import { changedKeys } from '../src/core/changes';
|
||||
import { COPY_ITEMS, applyCopy, planCopy } from '../src/core/copy';
|
||||
import type { Issue, PierInput } from '../src/core/types';
|
||||
@@ -103,3 +103,35 @@ describe('단면 그림 (삽도)', () => {
|
||||
expect(svg).toContain('지반고 28.931');
|
||||
});
|
||||
});
|
||||
|
||||
describe('말뚝 선단 근입 (G04·G05)', () => {
|
||||
// P1 model: pile tips at about EL 2.2 m, D 0.6096 m, so the limit is the 연암 top minus 0.6096.
|
||||
const model = buildPier(base);
|
||||
const deepest = Math.max(...model.piles.map((p) => p.bottom));
|
||||
|
||||
function embed(input: PierInput): string[] {
|
||||
const issues: Issue[] = [];
|
||||
validatePileEmbedment(input, model, issues);
|
||||
return issues.map((i) => i.code);
|
||||
}
|
||||
|
||||
it('no check and no message when no layers are entered yet', () => {
|
||||
expect(embed(withGround({}))).toEqual([]);
|
||||
});
|
||||
|
||||
it('G04: a pile tip above the 연암 top minus the embedment', () => {
|
||||
// 연암 top = the 매립토 bottom 2.5 m, so the limit is 2.5 − 0.6096 = 1.89 m, above the tips at 2.2 m.
|
||||
expect(deepest).toBeGreaterThan(2.5 - 0.6096);
|
||||
const rows = [{ name: '매립토', bottomEl: 2.5 }, { name: '연암', bottomEl: 1 }];
|
||||
expect(embed(withGround({ strataRows: rows }))).toEqual(['G04']);
|
||||
});
|
||||
|
||||
it('no G04 when the 연암 top is high enough above the tips', () => {
|
||||
const rows = [{ name: '매립토', bottomEl: 20 }, { name: '연암', bottomEl: 10 }];
|
||||
expect(embed(withGround({ strataRows: rows }))).toEqual([]);
|
||||
});
|
||||
|
||||
it('G05 (info): layers entered but no 연암 row, so the embedment is not checked', () => {
|
||||
expect(embed(withGround({ strataRows: [{ name: '풍화토', bottomEl: 20 }] }))).toEqual(['G05']);
|
||||
});
|
||||
});
|
||||
@@ -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('지층 값이 맞지 않습니다');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user