// 교대 A1 흉벽 · 브라켓 배근 삽도 3장을 SVG로 저장한다 (PNG 확인: python3 -I ../verify/svg_to_png.py ). import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import * as XLSX from 'xlsx'; import { it } from 'vitest'; import { buildAbut } from '../../src/core/abut/geometry'; import { parseAbutments, toAbutInput } from '../../src/core/abut/parse'; import { buildMembers } from '../../src/core/abut/members'; import { buildWings } from '../../src/core/abut/wings'; import { resolveSlab } from '../../src/core/abut/slab'; import { abutFootingGeom, abutFootingRebar } from '../../src/core/abut/rebar/footing'; import { skewAngle } from '../../src/core/abut/rebar/skew-layout'; import { abutWallGeom, abutWallRebar } from '../../src/core/abut/rebar/wall'; import { abutParapetGeom, abutParapetRebar, slabSpanAt } from '../../src/core/abut/rebar/parapet'; import { abutPlanOutline, abutSkewK } from '../../src/view/abut-scene'; import { abutParapetDowelSvg, abutParapetElevationSvg, abutParapetSectionSvg } from '../../src/view/abut-parapet-rebar-svg'; it('dump 교대 A1 흉벽 삽도', () => { const out = process.env.DUMP_OUT ?? fileURLToPath(new URL('./out', import.meta.url)); mkdirSync(out, { recursive: true }); const xlsx = fileURLToPath(new URL('../../../../RAG/운곡교P1입력.xlsx', import.meta.url)); const rec = parseAbutments(XLSX.read(readFileSync(xlsx), { type: 'buffer' })).abutments[0]; const model = buildAbut(toAbutInput(rec)); const members = buildMembers(model, { bottomEl: rec.foundationBottomEl, pileLengthMm: rec.pileLengthMm }); const wings = buildWings(model, members); const angle = skewAngle(rec.skewDeg); const footing = abutFootingRebar(abutFootingGeom(model.length, members.shape, angle)); const wg = abutWallGeom(model.length, members, angle); const wall = abutWallRebar(wg, footing); const slab = resolveSlab(); const tM = ((wg.xb + members.shape.parapetBackM * 1000) / 2) / 1000; const span = slabSpanAt(abutPlanOutline(model, members, wings, slab).slab, tM, abutSkewK(model))!; const ch = (sEnd: number) => (wings.find((w) => w.sEnd === sEnd)?.haunchM ?? 0) * 1000; const g = abutParapetGeom(wg, members.shape, model.bearings[0].s, { B: model.wing!.slabWidthMm, a: span.a, b: span.b, nearT: members.shape.parapetBackM * 1000 - slab.parapetGapMm, chamferA: ch(0), chamferB: ch(model.length) }); const r = abutParapetRebar(g, wall); const ns = (svg: string) => svg.replace('