받침방위각_솔플레이트검토.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>
112 lines
4.5 KiB
TypeScript
112 lines
4.5 KiB
TypeScript
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본');
|
||
});
|
||
});
|