Files
Pier_v1/tests/coping-rebar-svg.test.ts
T
ypshimandClaude Haiku 5.5 a4ae6de485 fix(rebar): 정면 dimension labels larger and the lines spaced clear of the 코핑 길이 text
- The two chains are raised and their labels enlarged (220 mm).
- 코핑 길이 sits above both chains; 기둥 중심 has its own line between them.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-26 14:57:53 +09:00

82 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 { buildRebar3D } from '../src/view/rebar3d';
import { chainDims, copingBarGroup, 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 bar name once, and each spot once', () => {
const svg = copingSectionSvg(scene.records, 6);
const labels = (svg.match(/<text /g) ?? []).length;
const names = new Set((svg.match(/font-size="120"[^>]*>(C\d+)</g) ?? []).map((s) => s.replace(/.*>/, '')));
expect(labels).toBe(names.size);
});
});
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']);
});
});