Files
Pier_v1/tests/footing-section-svg.test.ts
T
ypshimandClaude Haiku 5.5 3fe94fa0e1 feat(rebar): 확대기초 단면 최외측 열에 B1–B4 연장선과 측면 피복 다리선 추가
- 최외측 두 열에 B1·B2·B3·B4 점을 모두 표시 (빠진 점은 'ext'로 추가, 표 개수 불변)
- 상단(B1)과 하단(B2·B4) 연장선을 측면 피복 c_s까지 이음
- 측면 피복선에 B2 다리선을 하면 1단에서 B1 높이까지 그림
- 테스트: 다리선 2개, 연장 표시 존재, 기존 개수 테스트 유지

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-26 18:12:59 +09:00

75 lines
3.8 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 { assemblyBars, assemblyGridIndices, assemblyJs, b9Bars, bottomBars, crossBars, sideBars } from '../src/core/rebar/footing';
import { DEFAULT_FOOTING_REBAR } from '../src/core/rebar/footing-settings';
import { footingSectionSvg } from '../src/view/footing-section-svg';
import { loadP1 } from './helpers';
const countMark = (svg: string, cls: string, bar: string) => svg.split(`class="${cls}" data-bar="${bar}"`).length - 1;
describe('확대기초 교각축 직각 단면 (폭 W) (승인 2026-10-26, 추천안 1단계)', () => {
const m = buildPier(loadP1());
const foot = m.footings[0];
const L = foot.length * 1000;
const W = foot.width * 1000;
const H = (foot.top - foot.bottom) * 1000;
const fs = DEFAULT_FOOTING_REBAR;
const svg = footingSectionSvg(m);
it('point and line counts match the rebar table families', () => {
const bottom = bottomBars(L, W, H, fs);
expect(countMark(svg, 'b1', 'B1')).toBe(bottom.find((b) => b.name === 'B1')!.count);
expect(countMark(svg, 'b2', 'B2')).toBe(bottom.find((b) => b.name === 'B2')!.count);
expect(countMark(svg, 'b4', 'B4')).toBe(bottom.find((b) => b.name === 'B4')!.count);
expect(countMark(svg, 'b9', 'B9')).toBe(b9Bars(L, W, [], 2000, fs).rows);
expect(countMark(svg, 'b10', 'B10-1')).toBe(sideBars(L, W, H, fs).find((b) => b.name === 'B10-1')!.count);
expect(countMark(svg, 'b11', 'B11')).toBe(assemblyJs(H, fs).length);
expect(countMark(svg, 'b12', 'B12')).toBe(assemblyBars(L, W, H, fs).find((b) => b.name === 'B12')!.count);
for (const name of ['B5', 'B6', 'B7', 'B8']) expect(countMark(svg, 'b5', name)).toBe(1);
expect(crossBars(L, W, H, fs).length).toBe(4);
});
it('shows the width, the grid string, and the B10 levels as dimensions', () => {
expect(svg).toContain('폭 8150');
expect(svg).toContain('8@200=1600');
expect(svg).toContain(`${fs.cBottom}`);
});
it('has one bubble per highlighted bar family', () => {
for (const name of ['B1', 'B2', 'B3', 'B4', 'B5', 'B11', 'B10-1']) expect(svg).toContain(`data-bubble="${name}"`);
});
it('조립 철근은 격자 가운데에 놓임: 양끝 여유 차이 ≤ 1칸 (B11 n 79, B12 n 61, k 8, 엇갈림 2칸 유지)', () => {
const levels = assemblyJs(H, fs).length;
for (const [n, k] of [[79, 8], [61, 8]] as const) {
const all = Array.from({ length: levels }, (_, idx) => assemblyGridIndices(n, k, idx)).flat();
const left = Math.min(...all);
const right = n - Math.max(...all);
expect(Math.abs(left - right)).toBeLessThanOrEqual(1);
}
expect(assemblyGridIndices(61, 8, 1)[0] - assemblyGridIndices(61, 8, 0)[0]).toBe(2);
});
it('조립 철근(B11·B12)은 짝수 격자에 놓여 B9(홀수 격자)와 겹치지 않음 (확대기초철근 (1).md §9.1)', () => {
const levels = assemblyJs(H, fs).length;
for (const [n, k] of [[79, 8], [61, 8]] as const) {
for (let idx = 0; idx < levels; idx++) {
for (const i of assemblyGridIndices(n, k, idx)) expect(i % 2).toBe(0);
}
}
});
it('2단계: B6 다리 주석 1723, 범례 5항목, 기둥과 말뚝 맥락 표시, 탭 4개 중 첫 탭만 작동', () => {
expect(svg).toContain('B6 다리 → B5');
expect(svg).toContain('높이 1723');
for (const label of ['주철근 (B5–B8)', '직각·보조 (B1–B4)', '전단·띠 (B9)', '측면 수평 (B10-1 · B10-2)', '조립 (B11·B12)']) expect(svg).toContain(label);
expect(svg).toContain('class="column"');
expect(svg.split('class="pile"').length - 1).toBeGreaterThan(0);
});
it('최외측 열: B1–B4 연장선과 측면 피복 다리선 (승인 2026-10-26)', () => {
expect(svg.split('class="leg"').length - 1).toBe(2);
expect(svg.split('class="ext"').length - 1).toBeGreaterThan(0);
});
});