Files
Pier_v1/tests/abut-bearing-azimuth.test.ts
T
ypshimandClaude Opus 5.5 4e3950eb67 fix(abut): 교대 받침 방위각을 읽어 받침블럭 회전에 반영
- 원인: 교대 파서가 받침 시트의 방위각 열(6번째)을 읽지 않아, 블럭이 항상 교대축에 맞춰 그려졌음
- 방위각을 교각과 같은 변환(swapXYAzimuth)으로 읽고, 교대축 직각 기준 블럭 회전각(rotDeg)을 계산해 블럭·몰탈패드를 블럭 중심에서 회전
- 운곡교 A1: 회전 약 4.42° (교각 규칙과 같은 값). 날개벽(skew) 선과의 차이는 0.63°로 시안 AW01 값과 같음
- ② 받침 ELEVATION TABLE에 방위각 CAD / 진북, 블럭 회전 열 추가. 읽을 수 없는 방위각은 AP08 경고 후 축 방향 유지
- 테스트 5건 추가, 전체 647건 통과, 타입 검사·빌드 통과. 브라우저 시각 확인은 미실시

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 18:20:05 +09:00

58 lines
3.3 KiB
TypeScript
Raw 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 * 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()).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);
});
});