import { describe, expect, it } from 'vitest'; import { buildPier, blockFramePoint } from '../src/core/geometry'; import { loadP1 } from './helpers'; const model = buildPier(loadP1()); const front = model.blocks.filter((b) => b.row === '전열'); const back = model.blocks.filter((b) => b.row === '후열'); describe('받침블럭 방위 (삽도 · 승인 2026-10-23)', () => { it('uses the bearing angles after the same X/Y reflection as positions: front ≈ +4.42°, back ≈ +3.11°', () => { for (const b of front) expect(Math.abs(b.rowSkewDeg - 4.42)).toBeLessThan(0.02); for (const b of back) expect(Math.abs(b.rowSkewDeg - 3.11)).toBeLessThan(0.02); }); it('a block side follows the bearing row: the n side of a block runs along (−sinδ, cosδ)', () => { const b = front[0]; const [s1, n1] = blockFramePoint(b, 0, -0.6); const [s2, n2] = blockFramePoint(b, 0, 0.6); const ds = s2 - s1; const dn = n2 - n1; const len = Math.hypot(ds, dn); const d = (b.rowSkewDeg * Math.PI) / 180; expect(ds / len).toBeCloseTo(-Math.sin(d), 9); expect(dn / len).toBeCloseTo(Math.cos(d), 9); }); it('turning keeps the block centre and the bearing spacing (the row is unchanged)', () => { const b = front[0]; const [s0, n0] = blockFramePoint(b, 0, 0); expect(s0).toBeCloseTo(b.s, 12); expect(n0).toBeCloseTo(b.n, 12); }); it('the turned block corners stay inside the coping ends', () => { const L = model.copingL; for (const b of model.blocks) { for (const [a, c] of [[-0.6, -0.6], [-0.6, 0.6], [0.6, -0.6], [0.6, 0.6]] as const) { const [s] = blockFramePoint(b, a, c); expect(s, `block ${b.no}`).toBeGreaterThan(0); expect(s, `block ${b.no}`).toBeLessThan(L); } } }); });