Files
Pier_v1/tests/bearing-coordinate-frame.test.ts

57 lines
2.9 KiB
TypeScript

import { readFileSync, readdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import * as XLSX from 'xlsx';
import { describe, expect, it } from 'vitest';
import { swapXYAzimuth } from '../src/core/coordinate-frame';
import { parseWorkbook } from '../src/core/parseWorkbook';
import { buildPier } from '../src/core/geometry';
import { parseProject, serializeProject, SCHEMA_VERSION, type ProjectFile } from '../src/core/project';
import { loadP1 } from './helpers';
describe('bearing position / direction coordinate agreement', () => {
it('reflects the direction vector with the exchanged coordinate axes', () => {
for (const angle of [0, 45, 90, 153.200861111, 180, 270, 350, -30, 720]) {
const original = angle * Math.PI / 180;
const converted = swapXYAzimuth(angle) * Math.PI / 180;
expect(Math.sin(converted)).toBeCloseTo(Math.cos(original), 12);
expect(Math.cos(converted)).toBeCloseTo(Math.sin(original), 12);
}
expect(swapXYAzimuth(NaN)).toBeNaN();
});
it('keeps every real Sanwoe bearing approximately aligned with its coping', () => {
const dir = fileURLToPath(new URL('../pierzainer_ground/', import.meta.url));
const name = readdirSync(dir).find((name) => name.includes('산외교') && name.endsWith('.xlsx'))!;
const { piers, issues } = parseWorkbook(XLSX.read(readFileSync(`${dir}/${name}`), { type: 'buffer' }));
expect(issues).toEqual([]);
expect(piers).toHaveLength(7);
for (const input of piers) {
const model = buildPier(input);
expect(model.blocks).toHaveLength(4);
for (const block of model.blocks) expect(Math.abs(block.rowSkewDeg), `${input.name}/${block.no}`).toBeLessThan(0.03);
}
expect(piers[0].bearings[0].azimuthDeg).toBeCloseTo(296.799138889, 8);
});
it('migrates legacy input/defaults/draft once, including backup-style project round trips', () => {
const normalized = loadP1();
const legacy = structuredClone(normalized);
delete legacy.bearingAzimuthFrame;
legacy.bearings = legacy.bearings.map((b) => ({ ...b, azimuthDeg: swapXYAzimuth(b.azimuthDeg) }));
const file: ProjectFile = {
schemaVersion: SCHEMA_VERSION,
project: { name: '', bridge: '', client: '', author: '', crs: '', memo: '' },
source: { fileName: 'legacy.xlsx', sheets: [] },
piers: [{ id: 'P1', input: legacy, defaults: structuredClone(legacy), draft: structuredClone(legacy) }], history: [],
};
const opened = parseProject(JSON.stringify(file));
for (const input of [opened.piers[0].input, opened.piers[0].defaults!, opened.piers[0].draft!]) {
expect(input.bearingAzimuthFrame).toBe('model-xy');
input.bearings.forEach((b, i) => expect(b.azimuthDeg).toBeCloseTo(normalized.bearings[i].azimuthDeg, 10));
expect(input.ips).toEqual(normalized.ips);
}
expect(parseProject(serializeProject(opened))).toEqual(opened);
expect(legacy.bearingAzimuthFrame).toBeUndefined();
});
});