Files
Pier_v1/tests/abut-ground.test.ts
ypshimandClaude Haiku 5.5 59c2607418 feat(abut): 교대 지반·지층 카드 — 교각과 같은 위치 · 수위 · 지층 행 입력, 교대 단면 삽도, 검사
- 위치 (육상 · 하상 · 해상)와 위치별 수위 입력, 지층 행 표 (교각과 공용 strataRowsEditor), 지반 모델 지층 불러오기
- 검사: 교각과 같은 G01–G14, 말뚝 근입 G04, 지반고 < 저판 하면이면 정보 AI01
- 삽도: 지층 · 수위 띠를 교각과 공용으로 빼고, 교대축 직각 단면(저판 · 벽체 · 흉벽 · 말뚝 열)을 EL. 표기로 그림
- 자동 값: 지반고 (엑셀 입력), 연암층 상면 EL, 지층 수. 프로젝트 파일 저장 · 검증

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-11-04 10:36:23 +09:00

72 lines
4.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import * as XLSX from 'xlsx';
import { describe, expect, it } from 'vitest';
import { buildAbut } from '../src/core/abut/geometry';
import { parseAbutments, toAbutInput, type AbutRecord } from '../src/core/abut/parse';
import { buildMembers } from '../src/core/abut/members';
import { setAbutGround } from '../src/core/abut/edit';
import { abutGroundChanged, abutGroundIssues, supportTopEl } from '../src/core/abut/ground';
import { abutMemberRows } from '../src/core/abut/member-list';
import { checkStoredAbutments } from '../src/core/project';
import { abutGroundSectionSvg } from '../src/view/ground-svg';
const RAG = fileURLToPath(new URL('../../../RAG/운곡교P1입력.xlsx', import.meta.url));
const rec = parseAbutments(XLSX.read(readFileSync(RAG), { type: 'buffer' })).abutments[0];
const membersOf = (r: AbutRecord) => buildMembers(buildAbut(toAbutInput(r)), { bottomEl: r.foundationBottomEl, pileLengthMm: r.pileLengthMm }, r.shape);
const codes = (r: AbutRecord) => abutGroundIssues(r, membersOf(r)).map((i) => i.code);
// A1: 지반고 33.984, 기초 하단 40.895, 말뚝 선단 19.295 (spec_abut §12).
const rows = [
{ name: '퇴적토', bottomEl: 30 },
{ name: '풍화암', bottomEl: 22 },
{ name: '연암', bottomEl: 10 },
];
describe('교대 지반·지층 (2026-11-04, 교각 카드와 같은 입력)', () => {
it('defaults: 육상, no water, no rows; only AI01 (지반고 below the 저판 하면) is reported', () => {
expect(codes(rec)).toEqual(['AI01']);
expect(abutGroundIssues(rec, membersOf(rec))[0].message).toContain('6.911');
expect(abutGroundChanged(rec.ground)).toBe(false);
});
it('the pier checks apply: G01 order, G02 water, G07 DHWL, G13 sea, G04 pile embedment into the 연암', () => {
expect(codes(setAbutGround(rec, { strataRows: [{ name: '퇴적토', bottomEl: 35 }] }))).toContain('G01');
expect(codes(setAbutGround(rec, { groundWaterOn: true }))).toContain('G02');
expect(codes(setAbutGround(rec, { groundPosition: '하상' }))).toContain('G07');
expect(codes(setAbutGround(rec, { groundPosition: '해상' }))).toContain('G13');
// 연암 상면 22.000 − 1.0 × 0.6 = 21.4; the tip 19.295 is deep enough.
expect(codes(setAbutGround(rec, { strataRows: rows }))).toEqual(['AI01']);
const shallow = setAbutGround(rec, { strataRows: [{ name: '풍화암', bottomEl: 19.5 }, { name: '연암', bottomEl: 10 }] });
expect(codes(shallow)).toContain('G04');
expect(supportTopEl(rec.groundEl, rows)).toBe(22);
expect(supportTopEl(rec.groundEl, [{ name: '퇴적토', bottomEl: 30 }])).toBeUndefined();
});
it('set: merges values, removes undefined, refuses non-numbers; the member row follows', () => {
const a = setAbutGround(rec, { groundPosition: '하상', floodLevelEl: 36 });
expect(setAbutGround(a, { floodLevelEl: undefined }).ground).toEqual({ groundPosition: '하상' });
expect(() => setAbutGround(rec, { groundWaterEl: Number.NaN })).toThrow('숫자');
const row = abutMemberRows(setAbutGround(rec, { strataRows: rows }), '—').find((r) => r.id === 'ground')!;
expect(row.summary).toBe('육상 · 지층 3 · 지반고 EL.33.984');
expect(row.changed).toBe(true);
});
it('the project file keeps the 지반 values and refuses wrong ones', () => {
expect(() => checkStoredAbutments([setAbutGround(rec, { groundPosition: '해상', highWaterEl: 35, strataRows: rows })])).not.toThrow();
expect(() => checkStoredAbutments([{ ...rec, ground: { groundPosition: '산지' } as never }])).toThrow('지반');
expect(() => checkStoredAbutments([{ ...rec, ground: { strataRows: [{ name: '연암', bottomEl: 'x' }] } as never }])).toThrow('지반');
});
it('삽도: layers, water and the abutment section with EL. labels', () => {
const m = membersOf(rec);
const s = m.shape;
const svg = abutGroundSectionSvg({
ground: { groundEl: rec.groundEl, groundWaterOn: true, groundWaterEl: 31, strataRows: rows },
footingTopEl: m.footingTopEl, footingBottomEl: m.footingBottomEl!, seatEl: rec.seatEl, parapetTopEl: m.parapetTopStartEl,
bracketHeightM: s.bracketHeightM, wallFrontM: s.wallFrontM, wallBackM: s.wallBackM, parapetBackM: s.parapetBackM,
footingFrontM: s.footingFrontM, footingBackM: s.footingBackM, pileRowsT: m.piles.map((r) => r.t), pileBottomEl: m.pileBottomEl,
});
for (const t of ['지반고 EL.33.984', '지하수위 EL.31.000', '연암층 상면 EL.22.000', '기초 하단 EL.40.895', '말뚝 선단 EL.19.295', '퇴적토', '풍화암']) expect(svg).toContain(t);
});
});