feat(rebar): 확대기초 단면 그림에서 B1–B4와 B10-1 제외

- B1–B4 선, B2 다리선, B1–B4 풍선 제거 (그림에서만, 철근표·3D는 그대로)
- B10-1 점과 풍선 제거, 범례의 B1–B4·B10 항목 제거
- 테스트 갱신

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-27 11:19:36 +09:00
1 parent 61a8db916d
commit 77ad63fcbf
3 files changed
+31 -32

No files matched your search

+22
View File
@@ -0,0 +1,22 @@
# CLAUDE.md — Code/3d-drawing 작업 규칙
> 근거: `RAG/Task: Pierzainer 개발.yaml` ("유의미한 코드 생성 및 수정시 git log 자동 수행", "생성 코드 작업 위치(git 포함): Code\3d-drawing").
> 전역 지침은 `.claude/taskexecutionagent.md`이며, 커밋 규칙은 여기에만 있다.
## 커밋 자동 수행
**대상 변경:** `src/`, `tests/`, `scripts/`, `verify/`, `index.html`, `package.json`, `package-lock.json`, `tsconfig.json`, `public/`.
**커밋하지 않는 것:** `dist/`, `node_modules/`, 저장소 밖의 `RAG/`, `DOC/`, `context-migration/`, `prompt/`.
**순서**
1. 대상 변경을 끝낸 뒤 `npx vitest run`을 실행한다.
2. 모두 통과할 때만 커밋한다. 실패하면 커밋하지 않고 실패 내용을 보고한다.
3. 경로를 지정해 스테이징한다. `git add -A`는 쓰지 않는다.
4. 작업과 무관한 변경이 남아 있으면 멈추고 확인한다.
5. 한 커밋에는 한 가지 변경만 담는다. 커밋 해시를 보고한다.
**메시지**
- 형식: `type(scope): summary` (예: `feat(rebar): ...`, `fix(view): ...`). 요약에 한국어를 써도 된다.
- 끝에 `Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>`을 붙인다.
**push 금지:** 커밋만 한다. `origin`(gitea)으로 push하지 않는다. push는 별도 확인을 받는다.
+1 -26
View File
@@ -6,8 +6,7 @@ import { DEFAULT_FOOTING_REBAR } from '../core/rebar/footing-settings';
/**
* 확대기초 · 교각축 직각 단면 (폭 W) (승인 2026-10-26, 추천안 1·2단계). A cut across the footing width: horizontal = W, vertical = height
* from the 하면 at true scale. Every mark comes from the same functions as the rebar table and the 3D view:
* - B1–B4 orange lines (bars along W, cover to cover), B5–B8 teal points on the grid along W (방향 교환), B9 purple lines per row,
* - B10-1 green points at both W faces per level, B11 grey dashed lines per assembly level, B12 grey points on its W grid.
* - B5–B8 teal points on the grid along W (방향 교환), B9 purple lines per row, B11 grey dashed lines, B12 grey points (B1–B4 and B10-1 are not drawn in this view, 승인 2026-10-27),
* Legs are not drawn; the B6 leg length is noted in the figure. The column and the piles are shown as context.
* Each mark carries data-bar="<철근 번호>" so a bubble can highlight its bars (철근표 강조와 같은 방식).
*/
@@ -69,15 +68,6 @@ export function footingSectionSvg(model: PierModel): string {
// Cover lines on the W faces (측면 피복 c_s).
const xa = x(-W / 2 + fs.cSide);
const xb = x(W / 2 - fs.cSide);
// B1–B4 (방향 교환, 승인 2026-10-26): run along W, so in this section they are lines from cover to cover.
// The B2 legs turn up to the B1 height at both W ends (측면 피복선), drawn heavier.
parts.push(line('b1', 'B1', xa, xb, y(z.B1), COLOR.b14, 1.4));
parts.push(line('b2', 'B2', xa, xb, y(z.B24), COLOR.b14, 1.6));
parts.push(line('b3', 'B3', xa, xb, y(z.B3), COLOR.b14, 1.2));
parts.push(line('b4', 'B4', xa, xb, y(z.B24), COLOR.b14, 1.2));
for (const xx of [xa, xb]) {
parts.push(`<line class="leg" data-bar="B2" x1="${xx.toFixed(1)}" x2="${xx.toFixed(1)}" y1="${y(z.B1).toFixed(1)}" y2="${y(z.B24).toFixed(1)}" stroke="${COLOR.b14}" stroke-width="1.8"/>`);
}
// B6 leg note: the B6 leg runs from the 하면 1단 up to the B5 height (B6 다리 → B5 높이), shown in the right margin below.
// B5–B8 (방향 교환): run along L and are spaced along W (sW). In this section they are points on the W grid:
@@ -107,15 +97,7 @@ export function footingSectionSvg(model: PierModel): string {
const b9 = b9Bars(L, W, [], 2000, fs);
for (const n of [...new Set(b9.bars.map((b) => b.n))]) parts.push(vline('b9', 'B9', x(n), y(z.B24), y(z.B5), COLOR.b9));
// B10-1: green points at both W faces, one per level above the lowest (8 of 9 levels), at the side depth of the table.
const levels = b10Levels(H, fs);
const dB1 = sideDepth(NOMINAL_DIAMETER.S29, NOMINAL_DIAMETER.S19, fs);
// The lowest level is removed (승인 2026-10-26): the 하면 1단 B2·B4 take its place at the corner.
for (let j = 1; j < levels; j++) {
const zj = fs.cBottom + j * fs.sV;
parts.push(dot('b10', 'B10-1', x(-W / 2 + dB1), y(zj), COLOR.b10, 2.2));
parts.push(dot('b10', 'B10-1', x(W / 2 - dB1), y(zj), COLOR.b10, 2.2));
}
// B11: grey dashed lines per assembly level. B12: grey points on its W grid, every k·s, on the even grid (1단계 규칙).
const js = assemblyJs(H, fs);
@@ -163,19 +145,12 @@ export function footingSectionSvg(model: PierModel): string {
const yBot = Y0 + 100;
// Each bottom bubble sits straight below its own bar (B2 left of centre, B4 at centre, B3 right of centre) on a bar of the right parity.
parts.push(bubble('B5', xa + 12, yTop, x(xsW[1]), y(z.B5), COLOR.b5));
parts.push(bubble('B1', cx - 60, yTop, cx - 60, y(z.B1), COLOR.b14));
parts.push(bubble('B11', xb - 20, yTop, xb, y(zB11), COLOR.b11));
parts.push(bubble('B10-1', X0 - 18, y(fs.cBottom + (levels - 1) * fs.sV / 2), X0 + 2, y(fs.cBottom + (levels - 1) * fs.sV / 2), COLOR.b10));
parts.push(bubble('B2', cx - 70, yBot, cx - 70, y(z.B24), COLOR.b14));
parts.push(bubble('B4', cx, yBot, cx, y(z.B24), COLOR.b14));
parts.push(bubble('B3', cx + 70, yBot, cx + 70, y(z.B3), COLOR.b14));
// Legend (선 모양별, 삽도 기준) and the units note.
const yLeg = 352;
parts.push(`<circle cx="20" cy="${yLeg}" r="2.6" fill="${COLOR.b5}"/>${text(28, yLeg + 3, '주철근 (B5–B8)', 'start', COLOR.outline)}`);
parts.push(`<line x1="180" x2="204" y1="${yLeg}" y2="${yLeg}" stroke="${COLOR.b14}" stroke-width="1.6"/>${text(212, yLeg + 3, '직각·보조 (B1–B4)', 'start', COLOR.outline)}`);
parts.push(`<line x1="330" x2="330" y1="${yLeg - 8}" y2="${yLeg + 8}" stroke="${COLOR.b9}" stroke-width="1"/>${text(338, yLeg + 3, '전단·띠 (B9)', 'start', COLOR.outline)}`);
parts.push(`<circle cx="20" cy="${yLeg + 22}" r="2.2" fill="${COLOR.b10}"/>${text(28, yLeg + 25, '측면 수평 (B10-1 · B10-2)', 'start', COLOR.outline)}`);
parts.push(`<line x1="250" x2="274" y1="${yLeg + 22}" y2="${yLeg + 22}" stroke="${COLOR.b11}" stroke-width="1.2" stroke-dasharray="6 3"/>${text(280, yLeg + 25, '조립 (B11·B12)', 'start', COLOR.outline)}`);
parts.push(text(20, yLeg + 48, '치수 mm · 높이 방향은 실제 비율 · 다리 생략 (B6 다리는 주석) · 기준: 확대기초 하면 0', 'start', COLOR.outline));
+8 -6
View File
@@ -19,10 +19,10 @@ describe('확대기초 교각축 직각 단면 (폭 W) (승인 2026-10-26, 추
it('point and line counts match the rebar table families', () => {
const cross = crossBars(L, W, H, fs);
// B1–B4 run along W: one line per family in this section; B5–B8 run along L: points on the W grid (방향 교환).
for (const name of ['B1', 'B2', 'B3', 'B4']) expect(countMark(svg, name.toLowerCase(), name)).toBe(1);
for (const name of ['B1', 'B2', 'B3', 'B4']) expect(countMark(svg, name.toLowerCase(), name)).toBe(0); // B1–B4 are not drawn in this view (승인 2026-10-27)
for (const name of ['B5', 'B6', 'B7', 'B8']) expect(countMark(svg, name.toLowerCase(), name)).toBe(cross.find((b) => b.name === name)!.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, 'b10', 'B10-1')).toBe(0); // B10-1 is not drawn in this view (승인 2026-10-27)
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);
expect(cross.length).toBe(4);
@@ -35,7 +35,8 @@ describe('확대기초 교각축 직각 단면 (폭 W) (승인 2026-10-26, 추
});
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}"`);
for (const name of ['B5', 'B11']) expect(svg).toContain(`data-bubble="${name}"`);
for (const name of ['B1', 'B2', 'B3', 'B4', 'B10-1']) expect(svg).not.toContain(`data-bubble="${name}"`);
});
it('조립 철근은 격자 가운데에 놓임: 양끝 여유 차이 ≤ 1칸 (B11 n 79, B12 n 61, k 8, 엇갈림 2칸 유지)', () => {
@@ -61,13 +62,14 @@ describe('확대기초 교각축 직각 단면 (폭 W) (승인 2026-10-26, 추
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);
for (const label of ['주철근 (B5–B8)', '전단·띠 (B9)', '조립 (B11·B12)']) expect(svg).toContain(label);
expect(svg).not.toContain('직각·보조 (B1–B4)');
expect(svg).toContain('class="column"');
expect(svg.split('class="pile"').length - 1).toBeGreaterThan(0);
});
it('최외측 열: B1–B4 연장선과 측면 피복 다리선 (승인 2026-10-26)', () => {
expect(svg.split('class="leg"').length - 1).toBe(2);
it('최외측 열: B5–B8 추가 점 표시, B1–B4 다리선은 그림에서 제외 (승인 2026-10-27)', () => {
expect(svg.split('class="leg"').length - 1).toBe(0);
expect(svg.split('class="ext"').length - 1).toBeGreaterThan(0);
});
});