Files
Pier_v1/tests/p1-regression.test.ts
ypshimandClaude Opus 5.5 a0b0929e13 feat(bearing): 교각 솔플레이트를 2026-11-06 결정으로 (짝 받침 S · 열 T · 거더 하면 고정)
받침방위각_솔플레이트검토.md §3과 시안(Version 110–113)을 따른다 (사용자 결정 2026-11-06: 시안 적용).
11-03 C안(받침높이 H 고정, h3 = H − T, S 입력)을 대체한다.
- S: 교량 전체(A1, P1 … Pn, A2) 거더 짝 받침의 z 차 / 수평거리. 없으면 교각 종단경사 입력 →
  다른 열 같은 순번 값(가정, WS03) → 0 %(WS03). 받침별 직접 수정(수정됨)
- 평면 L = A + 100, W = B + 100 (받침별 A × B, 기본 700 × 640 가정), h3 181
- T = 열마다 max(22, ⌈22 + L·|S|/2⌉), 열 T 직접 수정 가능(T2 < T_min → WS02).
  T1은 오르막 쪽(3D 쐐기의 두꺼운 끝도 그쪽), T2 반대쪽
- 거더 하면 고정: 블럭 상면 = z − (T − T_ref), T_ref 30
- 짝 받침은 불러오기·프로젝트 열기 때 교량 전체로 계산해 교각 생성에 넘김
- ② 카드: h3·T_ref·T_min·여유·열 T·종단경사 입력, 표에 짝 받침·S 근거·받침별 S/A/B 수정·검산 W08·검사
- P1 검증(A1과 함께): S −1.908 … −1.902 %, L 800 · W 740 · T 30 · T1 38 · T2 22, 블럭 높이 변화 없음
- 블럭·솔플레이트 테스트는 A1–P1 짝 문맥으로 실행 (짝이 없으면 S 0 · T 22 · 블럭 +8 mm)
교대(QA-15 C안)와 Pier 시트 종단경사 열 읽기는 아직 남음.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 14:48:10 +09:00

112 lines
4.5 KiB
TypeScript
Raw Permalink 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 { 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() };
/**
* Regression against spec.md §12 (P1, 운곡교, T형, 말뚝기초).
* Coordinates and EL: ±1 mm (0.001 m). Angles: ±0.01°.
*/
const TOL = 0.001;
const model = buildPier(loadP1(), P1CTX);
describe('P1 regression — spec.md §12', () => {
it('axis length and azimuth', () => {
expect(model.lengthIp).toBeCloseTo(12.166, 3);
expect(model.azimuthDeg).toBeCloseTo(99.63, 2);
});
it('BP1, BP2 coordinates (국토좌표 E, N)', () => {
expect(model.bp1.e).toBeCloseTo(179132.173, 2);
expect(model.bp1.n).toBeCloseTo(259866.681, 2);
expect(Math.abs(model.bp2.e - 179144.004)).toBeLessThan(TOL);
expect(Math.abs(model.bp2.n - 259864.674)).toBeLessThan(TOL);
});
it('IP2 reference recalculation and d_IP2', () => {
expect(Math.abs(model.dIp2 - 1.134)).toBeLessThan(TOL);
});
it('column centre coordinates', () => {
expect(Math.abs(model.pivot.e - 179138.089)).toBeLessThan(TOL);
expect(Math.abs(model.pivot.n - 259865.677)).toBeLessThan(TOL);
});
it('bearing positions: front row across-axis +0.698, back row −0.600; front s from 0.943 to 10.965', () => {
const front = model.bearings.filter((b) => b.row === '전열');
const back = model.bearings.filter((b) => b.row === '후열');
expect(front[0].n).toBeCloseTo(0.698, 3);
expect(back[0].n).toBeCloseTo(-0.6, 3);
expect(front[0].s).toBeCloseTo(0.943, 3);
expect(front[4].s).toBeCloseTo(10.965, 3);
expect(back[0].s).toBeCloseTo(1.029, 3);
expect(back[4].s).toBeCloseTo(11.05, 3);
});
it('step boundaries at the midpoints of front bearings: 2.196 / 4.701 / 7.207 / 9.712', () => {
const bounds = model.segments.slice(1).map((s) => s.s0);
[2.196, 4.701, 7.207, 9.712].forEach((b, i) => expect(Math.abs(bounds[i] - b)).toBeLessThan(TOL));
});
it('front segment tops: 43.411 / 43.483 / 43.555 / 43.626 / 43.698', () => {
const tops = model.segments.map((s) => s.top);
[43.411, 43.483, 43.555, 43.626, 43.698].forEach((t, i) => expect(Math.abs(tops[i] - t)).toBeLessThan(TOL));
});
it('bearing block heights: h1 = 150, h2 = 200 mm; concrete 100 / 150 mm', () => {
expect(model.h1).toBeCloseTo(0.15, 6);
expect(model.h2).toBeCloseTo(0.2, 6);
expect(model.derived.blockHeightFront).toBeCloseTo(0.1, 6);
expect(model.derived.blockHeightBack).toBeCloseTo(0.15, 6);
});
it('no lateral step (front and back tops agree)', () => {
expect(model.derived.frontBackDiffSpread).toBeLessThan(0.0051);
});
it('coping bottom: 42.411 at the ends, 40.911 at the Level zone', () => {
expect(Math.abs(model.endBottom - 42.411)).toBeLessThan(TOL);
expect(Math.abs(model.levelBottom - 40.911)).toBeLessThan(TOL);
});
it('column height 12.703 m and footing top 28.208 m, soil cover 0.723 m', () => {
expect(Math.abs(model.derived.columnHeight - 12.703)).toBeLessThan(TOL);
expect(Math.abs(model.footings[0].top - 28.208)).toBeLessThan(TOL);
expect(Math.abs(model.derived.soilCover - 0.723)).toBeLessThan(TOL);
});
it('piles: 4 rows × 5 = 20, spacing 2250 mm, tip at 2.208 m', () => {
expect(model.piles).toHaveLength(20);
expect(model.derived.pileCount).toBe(20);
expect(Math.abs((model.derived.pileTipEl ?? NaN) - 2.208)).toBeLessThan(TOL);
const sValues = [...new Set(model.piles.map((p) => p.s.toFixed(4)))];
const nValues = [...new Set(model.piles.map((p) => p.n.toFixed(4)))];
expect(sValues).toHaveLength(5);
expect(nValues).toHaveLength(4);
expect(Number(nValues[1]) - Number(nValues[0])).toBeCloseTo(2.25, 4);
expect(Number(sValues[1]) - Number(sValues[0])).toBeCloseTo(2.25, 4);
});
it('blinding concrete 10600 × 8350 × 100 under the footing', () => {
const b = model.blindings[0];
expect(b.length).toBeCloseTo(10.6, 4);
expect(b.width).toBeCloseTo(8.35, 4);
expect(b.thickness).toBeCloseTo(0.1, 4);
});
it('footing 10400 × 8150 × 2000 mm', () => {
const f = model.footings[0];
expect(f.length).toBeCloseTo(10.4, 4);
expect(f.width).toBeCloseTo(8.15, 4);
expect(f.top - f.bottom).toBeCloseTo(2.0, 4);
});
});
describe('pile layout text (spec §12, §6.8 display)', () => {
it('reads 4@2250 × 3@2250 = 20본', () => {
expect(model.derived.pileLayout).toBe('4@2250 × 3@2250 = 20본');
});
});