- 위치 (육상 · 하상 · 해상)와 위치별 수위 입력, 지층 행 표 (교각과 공용 strataRowsEditor), 지반 모델 지층 불러오기 - 검사: 교각과 같은 G01–G14, 말뚝 근입 G04, 지반고 < 저판 하면이면 정보 AI01 - 삽도: 지층 · 수위 띠를 교각과 공용으로 빼고, 교대축 직각 단면(저판 · 벽체 · 흉벽 · 말뚝 열)을 EL. 표기로 그림 - 자동 값: 지반고 (엑셀 입력), 연암층 상면 EL, 지층 수. 프로젝트 파일 저장 · 검증 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
72 lines
4.6 KiB
TypeScript
72 lines
4.6 KiB
TypeScript
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);
|
||
});
|
||
});
|