- 교대 형상(src/core/abut, 3D 장면, 목록·카메라·맞춤)과 교대 입력 패널 추가 - 교각 받침 기준 카드 제거, 솔플레이트 규칙을 교각별 입력으로 변경 - 받침 ELEVATION·솔플레이트 TABLE을 모델값으로 연결 - 교대 입력값 카드: 형식 행에 시점·종점 표시, 제목을 "A1 입력값 [입력]"으로 변경 - 테스트 614건 통과, 타입 검사 통과 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
60 lines
2.6 KiB
TypeScript
60 lines
2.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 } from '../src/core/abut/parse';
|
||
import { buildMembers } from '../src/core/abut/members';
|
||
|
||
const RAG = fileURLToPath(new URL('../../../RAG/운곡교P1입력.xlsx', import.meta.url));
|
||
|
||
// 운곡교 A1, 기준 입력 파일에서 읽음 (spec_abut §10.1).
|
||
const input = toAbutInput(parseAbutments(XLSX.read(readFileSync(RAG), { type: 'buffer' })).abutments[0]);
|
||
const model = buildAbut(input);
|
||
const m = buildMembers(model, { bottomEl: input.foundationBottomEl, pileLengthMm: input.pileLengthMm });
|
||
|
||
describe('교대 A1 벽체 · 흉벽 · 저판 · 말뚝 (AA3, spec_abut §10.1)', () => {
|
||
it('저판 상면 41.995 (기초 하단 40.895 + 두께 1.1)', () => {
|
||
expect(m.footingTopEl).toBeCloseTo(41.995, 3);
|
||
});
|
||
|
||
it('wall height ① 구간 2.372 m, five segments with the seat EL of each bearing', () => {
|
||
expect(m.wallSegments).toHaveLength(5);
|
||
const first = m.wallSegments.find((w) => Math.abs(w.seatEl - 44.367) < 1e-6)!;
|
||
expect(first.heightM).toBeCloseTo(2.372, 3);
|
||
});
|
||
|
||
it('wall segments tile the axis from 0 to L with the step boundaries', () => {
|
||
const w = m.wallSegments;
|
||
expect(w[0].sFrom).toBeCloseTo(0, 9);
|
||
expect(w[w.length - 1].sTo).toBeCloseTo(model.length, 9);
|
||
expect(w[0].sTo).toBeCloseTo(model.stepBounds[0], 9);
|
||
for (let i = 1; i < w.length; i++) expect(w[i].sFrom).toBeCloseTo(w[i - 1].sTo, 9);
|
||
});
|
||
|
||
it('흉벽 상단 EL 47.180 at IP1 end and 46.835 at IP3 end; slope −2.829 %', () => {
|
||
expect(m.parapetTopStartEl).toBeCloseTo(47.18, 2);
|
||
expect(m.parapetTopEndEl).toBeCloseTo(46.835, 2);
|
||
expect(m.parapetSlope * 100).toBeCloseTo(-2.829, 2);
|
||
});
|
||
|
||
it('말뚝 3열 × 6본 = 18, rows at t −1.15 / +0.85 / +2.15, spacing ≈ 2.179 m', () => {
|
||
expect(m.piles.map((r) => r.t)).toEqual([-1.15, 0.85, 2.15]);
|
||
expect(m.piles.every((r) => r.s.length === 6)).toBe(true);
|
||
const gap = m.piles[0].s[1] - m.piles[0].s[0];
|
||
expect(gap).toBeCloseTo(2.179, 2);
|
||
expect(m.piles[0].s[0]).toBeCloseTo(0.65, 6);
|
||
});
|
||
|
||
it('말뚝 선단 EL 19.295 (40.895 − 21.6 m)', () => {
|
||
expect(m.pileBottomEl).toBeCloseTo(19.295, 3);
|
||
});
|
||
|
||
it('without a foundation the footing and piles have no EL (no crash)', () => {
|
||
const bare = buildMembers(model);
|
||
expect(bare.footingBottomEl).toBeUndefined();
|
||
expect(bare.pileBottomEl).toBeUndefined();
|
||
expect(bare.piles[0].s).toHaveLength(6);
|
||
});
|
||
});
|