import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import * as XLSX from 'xlsx'; import * as THREE from 'three'; import { describe, expect, it } from 'vitest'; import { bearingRotDeg, buildAbut } from '../src/core/abut/geometry'; import { parseAbutments, toAbutInput } from '../src/core/abut/parse'; import { buildMembers } from '../src/core/abut/members'; import { buildWings } from '../src/core/abut/wings'; import { buildAbutGroup } from '../src/view/abut-scene'; import { abutElevationRows, resolveBearingRule } from '../src/core/abut/bearing-table'; const RAG = fileURLToPath(new URL('../../../RAG/운곡교P1입력.xlsx', import.meta.url)); const rec = parseAbutments(XLSX.read(readFileSync(RAG), { type: 'buffer' })).abutments[0]; const model = buildAbut(toAbutInput(rec)); describe('교대 받침 방위각 (엑셀 받침 시트 6번째 열)', () => { it('reads the 방위각 of every bearing (75°56′55.9″ … 75°58′08.4″ in the workbook frame)', () => { expect(rec.bearings.every((b) => b.azimuthDeg !== undefined && Number.isFinite(b.azimuthDeg))).toBe(true); // model-xy = 90 − workbook value: 75.94886° → 14.05114° expect(rec.bearings.find((b) => b.no === 1)!.azimuthDeg).toBeCloseTo(90 - (75 + 56 / 60 + 55.9 / 3600), 6); }); it('turns each block like the pier rule (≈ 4.42° from the axis normal); against the wing (skew) line the rest is 0.63° (시안 AW01)', () => { const front = { e: model.nLeft.e * model.frontSide, n: model.nLeft.n * model.frontSide }; // 날개벽 방향: CAD 각 lineDeg → 진북 = 90 − CAD (시안: 진북 194.68°, CAD 255.32°). const wingRot = bearingRotDeg(90 - model.wing!.lineDeg, model.u, front); for (const b of model.bearings) { expect(Math.abs(b.rotDeg)).toBeGreaterThan(4.3); expect(Math.abs(b.rotDeg)).toBeLessThan(4.5); } const first = model.bearings.find((b) => b.no === 1)!; expect(Math.abs(first.rotDeg - wingRot)).toBeCloseTo(0.63, 1); }); it('without the 방위각 the blocks stay on the axis (rotation 0)', () => { const flat = buildAbut({ ...toAbutInput(rec), bearings: toAbutInput(rec).bearings.map((b) => ({ ...b, azimuthDeg: undefined })) }); expect(flat.bearings.every((b) => b.rotDeg === 0)).toBe(true); }); it('the 3D block turns with the bearing: its footprint is no longer axis-aligned', () => { const input = toAbutInput(rec); const members = buildMembers(model, { bottomEl: input.foundationBottomEl, pileLengthMm: input.pileLengthMm }); const group = buildAbutGroup(model, members, buildWings(model, members)); const block = (group.getObjectByName('blocks') as THREE.Group).children[0] as THREE.Mesh; const box = new THREE.Box3().setFromObject(block); // a turned 1.2 m square is wider than 1.2 m along s expect(box.max.x - box.min.x).toBeGreaterThan(1.2 + 1e-4); }); it('the ELEVATION table shows the 방위각 (CAD = the workbook value, 진북) and the block turn', () => { const [r] = abutElevationRows(model, resolveBearingRule(), rec.bearingHeightMm).filter((x) => x.no === 1); expect(r.azimuthCadDeg).toBeCloseTo(75 + 56 / 60 + 55.9 / 3600, 6); expect(r.azimuthNorthDeg).toBeCloseTo(90 - (75 + 56 / 60 + 55.9 / 3600), 6); expect(r.rotDeg).toBeCloseTo(model.bearings.find((b) => b.no === 1)!.rotDeg, 9); }); });