- 교대 형상(src/core/abut, 3D 장면, 목록·카메라·맞춤)과 교대 입력 패널 추가 - 교각 받침 기준 카드 제거, 솔플레이트 규칙을 교각별 입력으로 변경 - 받침 ELEVATION·솔플레이트 TABLE을 모델값으로 연결 - 교대 입력값 카드: 형식 행에 시점·종점 표시, 제목을 "A1 입력값 [입력]"으로 변경 - 테스트 614건 통과, 타입 검사 통과 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
84 lines
3.5 KiB
TypeScript
84 lines
3.5 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';
|
|
|
|
const RAG = fileURLToPath(new URL('../../../RAG/운곡교P1입력.xlsx', import.meta.url));
|
|
const load = (buf: Buffer) => XLSX.read(buf, { type: 'buffer' });
|
|
|
|
describe('교대 입력 읽기 (운곡교P1입력.xlsx, AA 입력)', () => {
|
|
const { abutments, issues } = parseAbutments(load(readFileSync(RAG)));
|
|
const a1 = abutments.find((a) => a.name === 'A1')!;
|
|
|
|
it('reads A1 without issues', () => {
|
|
expect(issues).toEqual([]);
|
|
expect(abutments.map((a) => a.name)).toEqual(['A1']);
|
|
expect(a1.type).toBe('A1');
|
|
expect(a1.seatEl).toBeCloseTo(44.367, 3);
|
|
expect(a1.foundation).toBe('말뚝기초');
|
|
expect(a1.pileLengthMm).toBe(21600);
|
|
expect(a1.skewDeg).toBeCloseTo(95 + 2 / 60 + 52 / 3600, 6);
|
|
expect(a1.slopeI).toBeCloseTo(-0.0191, 6);
|
|
});
|
|
|
|
it('IP1·IP2·IP3 use E = y_m, N = x_m (2026-11-03 규약)', () => {
|
|
expect(a1.ip1.e).toBeCloseTo(179131.917023, 6);
|
|
expect(a1.ip1.n).toBeCloseTo(259815.91973, 6);
|
|
expect(a1.ip3.e).toBeCloseTo(179119.891533, 6);
|
|
});
|
|
|
|
it('reads the five bearings with their own 교좌면 EL and the 받침높이 as written (275 mm)', () => {
|
|
expect(a1.bearings.map((b) => b.no)).toEqual([1, 2, 3, 4, 5]);
|
|
expect(a1.bearings.map((b) => b.seatEl)).toEqual([44.367, 44.438, 44.509, 44.58, 44.651]);
|
|
expect(a1.bearingHeightMm).toBe(275);
|
|
});
|
|
|
|
it('the parsed A1 gives the AA1 and AA2 values (length 12.197 m, wing 255.32°, slope +1.91 %)', () => {
|
|
const m = buildAbut(toAbutInput(a1));
|
|
expect(m.length).toBeCloseTo(12.197, 3);
|
|
expect(m.layoutMatchesType).toBe(true);
|
|
expect(m.wing!.lineDeg).toBeCloseTo(255.32, 1);
|
|
expect(m.wing!.slopePct).toBeCloseTo(1.91, 2);
|
|
});
|
|
});
|
|
|
|
describe('교대 입력 오류 표시', () => {
|
|
const rows = (type: string, skew: string) => [
|
|
['교대명', '형식', '교좌면\nEL_m', '기초 하단\nEL_m', '지반고\nEL_m', '기초 형식', '말뚝길이\n_mm', 'skew', '종단경사'],
|
|
['A1', type, 44.367, 40.895, 33.984, '말뚝기초', 21600, skew, -0.0191],
|
|
[],
|
|
['교대명', 'IP점', 'x_m', 'y_m'],
|
|
['A1', 'IP1', 259815.91973, 179131.917023],
|
|
['', 'IP2', 259815.91805, 179131.907126],
|
|
['', 'IP3', 259817.959709, 179119.891533],
|
|
[],
|
|
['교대명', '받침번호', 'x_m', 'y_m', 'z_m_EL', '방위각', '위치', '교좌면_EL', '받침높이'],
|
|
['A1', 1, 259818.5035, 179121.1404, 44.492, "75°56'55.9\"", '전열', 44.367, 275],
|
|
['', 2, 259818.0835, 179123.6148, 44.563, "75°57'14.1\"", '전열', 44.438, 275],
|
|
];
|
|
const book = (r: unknown[][]) => {
|
|
const wb = XLSX.utils.book_new();
|
|
XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(r), '교대');
|
|
return wb;
|
|
};
|
|
|
|
it('a wrong 형식 (A3) is an error and the abutment is left out', () => {
|
|
const r = parseAbutments(book(rows('A3', "95°02'52\"")));
|
|
expect(r.issues.map((i) => i.code)).toContain('AP02');
|
|
expect(r.abutments).toEqual([]);
|
|
});
|
|
|
|
it('an unreadable skew is an error', () => {
|
|
const r = parseAbutments(book(rows('A1', 'abc')));
|
|
expect(r.issues.map((i) => i.code)).toContain('AP03');
|
|
});
|
|
|
|
it('a clean sheet with the same layout reads with no issues', () => {
|
|
const r = parseAbutments(book(rows('A1', "95°02'52\"")));
|
|
expect(r.issues).toEqual([]);
|
|
expect(r.abutments[0].bearings).toHaveLength(2);
|
|
});
|
|
});
|