tower / files / test / cap-pattern.test.ts
cap-pattern.test.ts
c954a775 2026-09-28 Pavel Safronov | 1 | import { describe, expect, it } from 'vitest' |
| 2 | import { TRIANGLE_KM, triangleMullions } from '../src/views/cap-pattern.js' | |
| 3 | ||
| 4 | describe('the cap windows are identical triangles (D-078)', () => { | |
| 5 | const lines = triangleMullions() | |
| 6 | const height = (TRIANGLE_KM * Math.sqrt(3)) / 2 | |
| 7 | ||
| 8 | it('runs its mullions in three directions, 60° apart', () => { | |
| 9 | const dirs = new Set(lines.map(([x0, y0, x1, y1]) => { | |
| 10 | const a = (Math.atan2(y1 - y0, x1 - x0) * 180) / Math.PI | |
| 11 | return Math.round(((a % 180) + 180) % 180) | |
| 12 | })) | |
| 13 | expect([...dirs].sort((a, b) => a - b)).toEqual([0, 60, 120]) | |
| 14 | }) | |
| 15 | ||
| 16 | it('spaces every line a whole triangle height from the axis, so every triangle is the same', () => { | |
| 17 | for (const [x0, y0, x1, y1] of lines) { | |
| 18 | const len = Math.hypot(x1 - x0, y1 - y0) | |
| 19 | // Distance from the axis to the line: |cross(p0, d)|. | |
| 20 | const off = Math.abs(x0 * (y1 - y0) - y0 * (x1 - x0)) / len | |
| 21 | const k = off / height | |
| 22 | expect(Math.abs(k - Math.round(k))).toBeLessThan(1e-9) | |
| 23 | } | |
| 24 | }) | |
| 25 | ||
| 26 | it('stays inside the cap, and puts a vertex on the axis', () => { | |
| 27 | for (const [x0, y0, x1, y1] of lines) { | |
| 28 | expect(Math.hypot(x0, y0)).toBeLessThanOrEqual(50 + 1e-9) | |
| 29 | expect(Math.hypot(x1, y1)).toBeLessThanOrEqual(50 + 1e-9) | |
| 30 | } | |
| 31 | // One line of each family passes through the centre. | |
| 32 | const through = lines.filter(([x0, y0, x1, y1]) => Math.abs(x0 * y1 - y0 * x1) < 1e-9) | |
| 33 | expect(through).toHaveLength(3) | |
| 34 | }) | |
| 35 | }) |