Files
Pier_v1/tests/footing-section-svg.test.ts
T
ypshimandClaude Haiku 5.5 f793a69d3f fix(rebar): 확대기초 단면 B6 다리 주석을 우측 여백으로, 격자 치수 글자를 치수선 위로
- B6 다리 주석 "B6 다리 → B5 / 높이 1723"을 우측 여백에 두고 B6 다리 끝까지 지시선을 그림
- 격자 치수 "61@125=7625"를 치수선 위로 옮겨 하단 지시선과 겹치지 않게 함

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

70 lines
3.6 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);
});
});