feat(ground): N value per layer row (text, blow count or 타수/관입량 mm)

- StrataRow.nValue: text. "23" is a blow count (0–100), "50/5" a refusal
  (50 blows for 5 mm, 1–300 mm). Empty means not known yet.
- G06 (warning): a malformed N value. Strict, because the values will feed the
  bearing-capacity and liquefaction checks.
- The layer table has an N값 column; the project file checks that the rows
  are well formed.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-26 10:48:37 +09:00
1 parent 7dd59dfc6c
commit 7b5517e312
6 files changed
+100 -5

No files matched your search

+37 -1
View File
@@ -1,6 +1,7 @@
import { describe, expect, it } from 'vitest';
import { buildPier } from '../src/core/geometry';
import { validateGround, validatePileEmbedment } from '../src/core/ground';
import { parseNValue, validateGround, validatePileEmbedment, validateStrataNValues } from '../src/core/ground';
import { parseProject, serializeProject, SCHEMA_VERSION } from '../src/core/project';
import { changedKeys } from '../src/core/changes';
import { COPY_ITEMS, applyCopy, planCopy } from '../src/core/copy';
import type { Issue, PierInput } from '../src/core/types';
@@ -135,3 +136,38 @@ describe('말뚝 선단 근입 (G04·G05)', () => {
expect(embed(withGround({ strataRows: [{ name: '풍화토', bottomEl: 20 }] }))).toEqual(['G05']);
});
});
describe('N값 입력 (승인 2026-10-26: 글자 입력, 타수/관입량 mm)', () => {
it('reads a blow count, a refusal in mm, and empty; surrounding spaces are ignored', () => {
expect(parseNValue('')).toEqual({ kind: 'empty' });
expect(parseNValue(undefined)).toEqual({ kind: 'empty' });
expect(parseNValue(' 23 ')).toEqual({ kind: 'n', n: 23 });
expect(parseNValue('0')).toEqual({ kind: 'n', n: 0 });
expect(parseNValue('50/5')).toEqual({ kind: 'refusal', blows: 50, mm: 5 });
});
it('rejects text, out-of-range blow counts, and penetrations', () => {
for (const bad of ['abc', '-3', '101', '50/0', '50/301', '50/', '/5', '23.5']) {
expect(parseNValue(bad).kind).toBe('invalid');
}
});
it('G06: a malformed N value is a warning; empty and valid values are not', () => {
const issues: Issue[] = [];
validateStrataNValues(withGround({ strataRows: [{ name: '매립토', bottomEl: 27, nValue: '가' }, { name: '풍화토', bottomEl: 22, nValue: '50/5' }, { name: '연암', bottomEl: 10 }] }), issues);
expect(issues.map((i) => i.code)).toEqual(['G06']);
expect(issues[0].level).toBe('W');
});
it('a project file refuses a layer row whose N value is not text', () => {
const bad = { ...loadP1(), strataRows: [{ name: '연암', bottomEl: 10, nValue: 5 }] } as unknown as PierInput;
const text = serializeProject({
schemaVersion: SCHEMA_VERSION,
project: { name: 'x', bridge: '운곡교', client: '', author: '', crs: 'KATEC', memo: '' },
source: { fileName: 'x.xlsx', sheets: [] },
piers: [{ id: 'P1', input: bad }],
history: [],
});
expect(() => parseProject(text)).toThrow('지층 행 형식');
});
});