Files
Pier_v1/tests/seat-el.test.ts
T
ypshimandClaude Haiku 5.5 8aedc9b969 feat(shape): 교좌면 EL로 받침별 코핑 상면 계단을 만든다 (W10은 정보)
입력 교좌면 EL이 있으면 그 받침 구간의 코핑 상면 = 교좌면 EL (없으면 z − h1 / z − h2).
받침블럭 바닥과 코핑 상면이 항상 맞아 블럭이 뜨거나 묻히지 않는다. seatCalc는 기울기 계산값으로 남겨
W10 비교 기준으로 쓰고, W10은 경고(W)에서 정보(I)로 바꾼다.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-11-10 15:07:19 +09:00

77 lines
3.4 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 { describe, expect, it } from 'vitest';
import { buildPier } from '../src/core/geometry';
import { validatePier } from '../src/core/validate';
import type { Issue, PierInput } from '../src/core/types';
import { loadP1, p1Pairs } from './helpers';
// Bridge context (A1 ↔ P1 girder pairs) as in the app, so the solplate slope is computed (2026-11-06).
const P1CTX = { pairs: p1Pairs() };
// 교좌면 EL of the P1 sheet (받침 1–10), 2026-11-03.
const SEAT = [43.411, 43.483, 43.555, 43.626, 43.698, 43.411, 43.483, 43.555, 43.626, 43.698];
function withSeat(input: PierInput, seats: number[]): PierInput {
return { ...input, bearings: input.bearings.map((b) => ({ ...b, seatEl: seats[b.no - 1] })) };
}
describe('교좌면 EL 입력 (2026-11-03)', () => {
it('the P1 교좌면 EL values reproduce the 두부보 상면 slope: the model does not change', () => {
const base = buildPier(loadP1(), P1CTX);
const seated = buildPier(withSeat(loadP1(), SEAT), P1CTX);
for (const b of base.blocks) {
const s = seated.blocks.find((x) => x.no === b.no)!;
expect(s.bottom).toBeCloseTo(b.bottom, 6);
expect(s.top).toBeCloseTo(b.top, 6);
}
});
it('an input 교좌면 EL sets the block bottom and so h1 = (EL.X − 50 mm) − 교좌면 EL', () => {
const m = buildPier(withSeat(loadP1(), [43.4, ...SEAT.slice(1)]), P1CTX);
const b1 = m.blocks.find((x) => x.no === 1)!;
expect(b1.bottom).toBeCloseTo(43.4, 6);
expect((b1.top - b1.bottom) * 1000).toBeCloseTo(111, 6);
});
it('without 교좌면 EL the seatCalc is the slope value (the check reference)', () => {
const m = buildPier(loadP1(), P1CTX);
expect(m.blocks.every((b) => Math.abs(b.seatCalc - b.bottom) < 1e-9)).toBe(true);
});
it('warns (W10) when the input 교좌면 EL differs from the slope by more than 5 mm, and keeps the input', () => {
const input = withSeat(loadP1(), [43.5, ...SEAT.slice(1)]);
const m = buildPier(input, P1CTX);
const issues: Issue[] = [];
validatePier(input, m, issues);
const w = issues.filter((i) => i.code === 'W10');
expect(w.length).toBe(1);
expect(w[0].message).toContain('1번');
expect(m.blocks.find((x) => x.no === 1)!.bottom).toBeCloseTo(43.5, 6);
});
it('no W10 for the P1 values', () => {
const input = withSeat(loadP1(), SEAT);
const m = buildPier(input, P1CTX);
const issues: Issue[] = [];
validatePier(input, m, issues);
expect(issues.filter((i) => i.code === 'W10')).toEqual([]);
});
it('an input 교좌면 EL also sets the coping top of that step, so the block sits on the coping (2026-11-10)', () => {
const m = buildPier(withSeat(loadP1(), [43.4, ...SEAT.slice(1)]), P1CTX);
const b1 = m.blocks.find((x) => x.no === 1 && x.row === '전열')!;
const seg = m.segments.find((s) => b1.g >= s.s0 && b1.g < s.s1)!;
expect(seg.top).toBeCloseTo(43.4, 6);
expect(b1.bottom).toBeCloseTo(seg.top, 9);
// seatCalc keeps the slope value (z − h1) as the W10 reference.
expect(b1.seatCalc).toBeCloseTo(43.411, 3);
});
it('W10 is information (I), not a warning, since the input builds the geometry', () => {
const input = withSeat(loadP1(), [43.5, ...SEAT.slice(1)]);
const m = buildPier(input, P1CTX);
const issues: Issue[] = [];
validatePier(input, m, issues);
expect(issues.filter((i) => i.code === 'W10').map((i) => i.level)).toEqual(['I']);
});
});