diff --git a/src/view/coping-rebar-svg.ts b/src/view/coping-rebar-svg.ts index 881f34e..450d6c8 100644 --- a/src/view/coping-rebar-svg.ts +++ b/src/view/coping-rebar-svg.ts @@ -55,9 +55,24 @@ export function copingSectionSvg(records: BarRecord[], s0: number): string { crossings.push({ name: r.name, x: a[2] + (b[2] - a[2]) * t, y: a[1] + (b[1] - a[1]) * t, group: copingBarGroup(r.name) }); } } - const xs = crossings.map((c) => c.x * 1000); + // The same bar is recorded in several pieces, so the same spot can be crossed more than once: draw each spot once, + // and write each bar name once (at its first crossing), so the labels do not pile up. + const seen = new Set(); + const named = new Set(); + const unique = crossings.filter((c) => { + const key = `${Math.round(c.x * 1e4)}|${Math.round(c.y * 1e4)}|${c.name}`; + if (seen.has(key)) return false; + seen.add(key); + return true; + }); + const xs = unique.map((c) => c.x * 1000); const minX = Math.min(...xs, 0); const maxX = Math.max(...xs, 0); - const parts: string[] = crossings.map((c) => `${c.name}`); + const parts: string[] = unique.map((c) => { + const dot = ``; + if (named.has(c.name)) return dot; + named.add(c.name); + return `${dot}${c.name}`; + }); return `${parts.join('')}`; } diff --git a/tests/coping-rebar-svg.test.ts b/tests/coping-rebar-svg.test.ts index 87d5818..6a08fa8 100644 --- a/tests/coping-rebar-svg.test.ts +++ b/tests/coping-rebar-svg.test.ts @@ -32,3 +32,12 @@ describe('코핑 배근 정면 · 단면 (승인 2026-10-26)', () => { expect((svg.match(/ { + it('writes each bar name once, and each spot once', () => { + const svg = copingSectionSvg(scene.records, 6); + const labels = (svg.match(/]*>(C\d+) s.replace(/.*>/, ''))); + expect(labels).toBe(names.size); + }); +});