feat(abut): 접속슬래브 경사는 형식이 정함, 단면 · 접합 상세를 파단선 단면 하나로 합침, 흉벽 높이 입력
- 경사 선택 삭제: 매립형 = 하향 4 %, 노출형 = 종단경사 따라 (노트 표기). 예전 파일의 slope 값은 읽고 무시 - 단면 + 접합 상세: 흉벽 쪽과 먼 끝만 그리고 중간 생략, 부속재 · 치수(7000 · 450 · 850 · 295 · 헌치) · EL을 한 그림에 - 흉벽 높이 (브라켓 상면 ~ 흉벽 상단) 입력 = 벽체·흉벽 카드 브라켓 높이와 같은 값 - 자동 값: 브라켓 얹힘 길이 = 브라켓 폭 − 흉벽과 간격 (295) Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4b8b80ae97
commit
9835fb42b3
7 files changed
+157
-199
No files matched your search
+17
-23
@@ -7,12 +7,12 @@ import { buildAbut } from '../src/core/abut/geometry';
|
||||
import { parseAbutments, toAbutInput } from '../src/core/abut/parse';
|
||||
import { buildMembers } from '../src/core/abut/members';
|
||||
import { buildWings } from '../src/core/abut/wings';
|
||||
import { applyShapeEdit, applySlabEdit, setSlabForm, setSlabSlope } from '../src/core/abut/edit';
|
||||
import { applyShapeEdit, applySlabEdit, setSlabForm } from '../src/core/abut/edit';
|
||||
import { abutMemberRows } from '../src/core/abut/member-list';
|
||||
import { resolveSlab, slabChangedKeys, slabGradePct, slabIssues, slabSection, slabSlopeLabel } from '../src/core/abut/slab';
|
||||
import { checkStoredAbutments } from '../src/core/project';
|
||||
import { abutPlanOutline, buildAbutGroup } from '../src/view/abut-scene';
|
||||
import { abutSlabJointSvg, abutSlabPlanSvg, abutSlabSectionSvg } from '../src/view/abut-slab-svg';
|
||||
import { abutSlabPlanSvg, abutSlabSectionSvg } from '../src/view/abut-slab-svg';
|
||||
|
||||
const RAG = fileURLToPath(new URL('../../../RAG/운곡교P1입력.xlsx', import.meta.url));
|
||||
const rec = parseAbutments(XLSX.read(readFileSync(RAG), { type: 'buffer' })).abutments[0];
|
||||
@@ -25,14 +25,13 @@ const build = (r = rec) => {
|
||||
const SHAPE = { parapetBackM: -0.5, wallBackM: -0.8, bracketHeightM: 0.85 };
|
||||
|
||||
describe('접속슬래브 입력 (2026-11-04, spec_abut §4.8, 시안 ② 접속슬래브 카드)', () => {
|
||||
it('defaults: 매립형 · 하향 4 % · 7000 × 450 · 간격 5 / 20; the slope follows the form unless set', () => {
|
||||
expect(resolveSlab()).toEqual({ form: 'buried', slope: 'down4', lengthMm: 7000, thicknessMm: 450, parapetGapMm: 5, wingGapMm: 20, haunchLengthMm: 2000 });
|
||||
expect(resolveSlab({ form: 'exposed' }).slope).toBe('grade');
|
||||
const exposed = setSlabForm({ ...rec, slab: { slope: 'down4' } }, 'exposed');
|
||||
expect(exposed.slab).toEqual({ form: 'exposed' }); // picking a form resets the slope to the form's own
|
||||
expect(setSlabSlope(exposed, 'down4').slab).toEqual({ form: 'exposed', slope: 'down4' });
|
||||
expect(setSlabSlope(exposed, 'grade').slab).toEqual({ form: 'exposed' });
|
||||
expect(slabChangedKeys(exposed.slab)).toEqual(['form', 'slope']);
|
||||
it('defaults: 매립형 · 7000 × 450 · 간격 5 / 20; the form sets the slope, an old stored slope is dropped', () => {
|
||||
expect(resolveSlab()).toEqual({ form: 'buried', lengthMm: 7000, thicknessMm: 450, parapetGapMm: 5, wingGapMm: 20, haunchLengthMm: 2000 });
|
||||
const old = { form: 'exposed', slope: 'down4' } as unknown as Parameters<typeof resolveSlab>[0];
|
||||
expect(resolveSlab(old)).toEqual({ ...resolveSlab(), form: 'exposed' });
|
||||
expect(setSlabForm({ ...rec, slab: old }, 'exposed').slab).toEqual({ form: 'exposed' });
|
||||
expect(slabGradePct(resolveSlab(old), 1.91)).toBe(1.91); // 노출형 = 종단경사, whatever was stored
|
||||
expect(slabChangedKeys({ form: 'exposed' })).toEqual(['form']);
|
||||
expect(slabChangedKeys(undefined)).toEqual([]);
|
||||
});
|
||||
|
||||
@@ -43,7 +42,7 @@ describe('접속슬래브 입력 (2026-11-04, spec_abut §4.8, 시안 ② 접속
|
||||
expect(() => applyShapeEdit({ ...rec, slab: { thicknessMm: 600 } }, 'bracketHeightMm', 500)).toThrow('접속슬래브 두께');
|
||||
});
|
||||
|
||||
it('slope text and value: 하향 4 % = −4; 종단경사 = the wing slope (A1 = −i)', () => {
|
||||
it('slope text and value: 매립형 하향 4 % = −4; 노출형 종단경사 = the wing slope (A1 = −i)', () => {
|
||||
const { model } = build();
|
||||
expect(slabGradePct(resolveSlab(), model.wing!.slopePct)).toBe(-4);
|
||||
expect(slabGradePct(resolveSlab({ form: 'exposed' }), 1.91)).toBe(1.91);
|
||||
@@ -112,12 +111,13 @@ describe('접속슬래브 입력 (2026-11-04, spec_abut §4.8, 시안 ② 접속
|
||||
|
||||
it('the project file keeps the slab input and refuses a wrong form', () => {
|
||||
expect(() => checkStoredAbutments([{ ...rec, slab: { form: 'exposed', lengthMm: 8000 } }])).not.toThrow();
|
||||
expect(() => checkStoredAbutments([{ ...rec, slab: { form: 'exposed', slope: 'down4' } as never }])).not.toThrow(); // earlier files
|
||||
expect(() => checkStoredAbutments([{ ...rec, slab: { form: 'open' } }])).toThrow('접속슬래브');
|
||||
expect(() => checkStoredAbutments([{ ...rec, slab: { lengthMm: 'x' } }])).toThrow('접속슬래브');
|
||||
});
|
||||
});
|
||||
|
||||
describe('접속슬래브 삽도 (평면 · 단면 · 접합 상세)', () => {
|
||||
describe('접속슬래브 삽도 (평면, 단면 + 접합 상세)', () => {
|
||||
const { model, members, wings } = build();
|
||||
const sh = members.shape;
|
||||
const sectionOf = (form: 'buried' | 'exposed') => {
|
||||
@@ -137,19 +137,13 @@ describe('접속슬래브 삽도 (평면 · 단면 · 접합 상세)', () => {
|
||||
for (const s of [`폭 ${(model.wing!.slabWidthMm / 1000).toFixed(3)} m`, '>7000<', '모따기 300 × 300', '접속슬래브']) expect(svg).toContain(s);
|
||||
});
|
||||
|
||||
it('단면 매립형: 7000, 450, 하향 4 %, EL labels; 노출형 adds 헌치 2000 and 끝 850', () => {
|
||||
it('단면 + 접합 상세 (중간 생략): 7000, 450, 흉벽 높이 850, 얹힘 295, accessories and EL; 노출형 adds 헌치 2000', () => {
|
||||
const buried = sectionOf('buried');
|
||||
for (const s of ['>7000<', '>450<', '경사 하향 4 %', '흉벽 상단 EL.46.867', '브라켓 상면 EL.46.017', '간격 5', '다웰 D25 @400']) expect(buried).toContain(s);
|
||||
for (const s of ['7000 (중간 생략)', '>450<', '>850<', '>295<', '경사 하향 4 %', '흉벽 상단 EL.46.867', '브라켓 상면 EL.46.017',
|
||||
'간격 5 · 아스팔트 충진재', '스티로폼', '고무판 150 × 150 × 15', '타르페이퍼 T = 15', '다웰 D25 @400 · 강관 Φ60 L300']) expect(buried).toContain(s);
|
||||
expect(buried).not.toContain('헌치');
|
||||
expect(buried.match(/<polygon /g)).toHaveLength(3); // 흉벽 · 벽체, slab far piece, slab near piece
|
||||
const exposed = sectionOf('exposed');
|
||||
for (const s of ['헌치 2000', '끝 850', '경사 종단경사 +']) expect(exposed).toContain(s);
|
||||
});
|
||||
|
||||
it('접합 상세: the accessories and the EL labels', () => {
|
||||
const svg = abutSlabJointSvg({ form: 'buried', gradePct: -4, parapetTopEl: 46.867, bracketHeightM: 0.85, parapetGapMm: 5, thicknessMm: 450 });
|
||||
for (const s of ['간격 5 · 아스팔트 충진재', '스티로폼', '고무판 150 × 150 × 15', '타르페이퍼 T = 15', '다웰 D25 · 강관 Φ60 L300', 'S = 4.00 % (하향)', '흉벽 상단 EL.46.867', '브라켓 상면 EL.46.017', '접속슬래브 450']) {
|
||||
expect(svg).toContain(s);
|
||||
}
|
||||
expect(abutSlabJointSvg({ form: 'exposed', gradePct: 1.91, parapetTopEl: 46.867, bracketHeightM: 0.85, parapetGapMm: 5, thicknessMm: 450 })).toContain('노출형 · 끝 850');
|
||||
for (const s of ['헌치 2000', '경사 종단경사 +', '>295<']) expect(exposed).toContain(s);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user