Files
Pier_v1/tests/coping-rebar-svg.test.ts
T

105 lines
4.7 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 { buildRebar3D } from '../src/view/rebar3d';
import { chainDims, copingBarGroup, copingEndStation, copingFrontSvg, copingSectionSvg } from '../src/view/coping-rebar-svg';
import { loadP1 } from './helpers';
const model = buildPier(loadP1());
const scene = buildRebar3D(model);
describe('코핑 배근 정면 · 단면 (승인 2026-10-26)', () => {
it('the 3D bar records include the coping bars, the same data as the meshes', () => {
const coping = scene.records.filter((r) => /^C\d/.test(r.name));
expect(coping.length).toBeGreaterThan(0);
expect(scene.records.length).toBeGreaterThan(coping.length - 1);
});
it('the front view draws one polyline per coping bar', () => {
const coping = scene.records.filter((r) => /^C\d/.test(r.name));
const svg = copingFrontSvg(scene.records, model.copingL * 1000);
expect((svg.match(/<polyline/g) ?? []).length).toBe(coping.length);
});
it('groups the bars: C1–C8 main, C9–C11 loops, C12–C13 sides, C14–C16 steps', () => {
expect(copingBarGroup('C1')).toBe('main');
expect(copingBarGroup('C9')).toBe('loop');
expect(copingBarGroup('C12')).toBe('side');
expect(copingBarGroup('C15')).toBe('step');
});
it('the section at mid-length shows the bars that cross it', () => {
const svg = copingSectionSvg(scene.records, model.copingL / 2);
expect((svg.match(/<circle/g) ?? []).length).toBeGreaterThan(0);
});
});
describe('단면 · 폐합 글자 겹침 (승인 2026-10-26)', () => {
it('writes each bubble label once', () => {
const svg = copingSectionSvg(scene.records, 6, model.copingRefTop, model.copingB * 1000);
// Only the top row and the side rows are shown here: their bubbles, once each.
for (const label of ['C1–6', 'C7·8', 'C12·13']) {
expect(svg.split(`>${label}<`).length - 1).toBe(1);
}
for (const label of ['C10', 'C14', 'C16']) {
expect(svg).not.toContain(`>${label}<`);
}
expect(svg).not.toContain('상면 간격');
});
});
describe('정면 번호 풍선과 치수 (승인 2026-10-26, 시안 ③)', () => {
const svg = copingFrontSvg(scene.records, model.copingL * 1000);
it('has one bubble per bar group, with its label', () => {
for (const label of ['C1–6', 'C12·13', 'C9', 'C10', 'C11', 'C7·8', 'C14', 'C15', 'C16']) {
expect(svg).toContain(`>${label}<`);
}
});
it('writes the 시안 length dimension (300 · 4500 · 2400 · 4500 · 300 = 12000)', () => {
expect(svg).toContain('18@250=4500');
expect(svg).toContain('8@300=2400');
expect(svg).toContain('코핑 길이 12000');
});
});
describe('정면 두 번째 치수선과 범례 (승인 2026-10-26, 시안)', () => {
const svg = copingFrontSvg(scene.records, model.copingL * 1000);
it('writes the column-centre span 10@1000=10000 and the legend', () => {
expect(svg).toContain('10@1000=10000');
expect(svg).toContain('기둥 중심');
expect(svg).toContain('주철근 (C1–C8)');
expect(svg).toContain('전단·띠 (C9–C11)');
});
});
describe('정면 치수는 3D 철근 위치에서 계산 (승인 2026-10-26)', () => {
it('the chains come from the bar positions and match the 시안 values', () => {
const svg = copingFrontSvg(scene.records, model.copingL * 1000, model.columns[0].s);
const texts = [...svg.matchAll(/font-size="220"[^>]*>([^<]*)</g)].map((x) => x[1]);
expect(texts).toEqual(['300', '18@250=4500', '8@300=2400', '18@250=4500', '300', '900', '10@1000=10000', '900']);
});
});
describe('chainDims', () => {
it('groups repeated gaps and writes a single gap as its length', () => {
expect(chainDims([300, 550, 800, 1100], 0, 1400).map((d) => d.text)).toEqual(['300', '2@250=500', '2@300=600']);
});
});
describe('아래 치수선의 0 = 기둥 중심 (승인 2026-10-26)', () => {
it('the column-centre tick sits at the middle of the 10@1000 span (the 10 intervals are centred on the column)', () => {
const col = model.columns[0].s * 1000;
const svg = copingFrontSvg(scene.records, model.copingL * 1000, model.columns[0].s);
expect(svg).toContain(`<line x1="${col}" y1=`);
const seg = [...svg.matchAll(/<line x1="([-\d.]+)" y1="[-\d.]+" x2="([-\d.]+)" y2="[-\d.]+" stroke="#18212B" stroke-width="10"/g)].map((m) => [Number(m[1]), Number(m[2])]);
const span = seg.find(([a, b]) => b - a > 9000 && b - a < 11000);
expect(span).toBeDefined();
expect((span![0] + span![1]) / 2).toBeCloseTo(col, 0);
});
});
describe('단부 위치 (승인 2026-10-26)', () => {
it('the 단부 section is at the first shear station, 0.3 m from the coping start for P1', () => {
expect(copingEndStation(scene.records)).toBeCloseTo(0.3, 6);
});
});