fix(abut-rebar): 날개벽 WR10 = 교대 끝면 쪽 ㄱ자 (교대 3,000 · 날개벽 1,000)

- 사용자 도면(2026-11-05): 꺾이는 점 = 날개벽 바깥면(교대 끝면) − 피복 123 선 × 흉벽 배면 + 123 선. 교대 쪽 다리 3,000 (s 방향, 교대 안쪽),
  날개벽 쪽 다리 1,000 (바깥면 − 123, 경사 하단에서는 짧아짐). 단 @s_v · 단 수 그대로 (A1 38)
- 이전 안쪽 모서리 L자 (대각 300 + 양끝 l_d) 폐기
- 테스트: 꺾이는 점 · 다리 길이 · 방향 · 단 수, 콘크리트 안 검사 통과

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-11-05 09:15:46 +09:00
1 parent 7b9de649e5
commit bb2af4bdf5
2 files changed
+30 -12

No files matched your search

+10 -12
View File
@@ -6,7 +6,7 @@
* - 수평: WR3–5 배면 (@s_v), WR13–15 전면 (@2·s_v), 띠 = 등단면 / 변화단면1 / 변화단면2. 맨 위 2단은 상단 경사와 나란히
* (사용자 결정 2026-11-04, Q-WR1), 일반 단은 그 아래 s 이상. 교대 쪽 끝은 교대 단면을 지나 반대쪽 면 − c, 90° 갈고리.
* - WR6 경사 하단 2개, WR7-1 · 7-2 · 7-3 헌치 꺾임 (전면 수평과 같은 단), WR9 저판 상면 헌치 보강 꺾임 (@2·s_h 자동 개수, 사용자 도면),
* WR10 모서리 꺾임 (@s_v), WR20 간격재. 교대 철근과의 간섭은 보지 않는다 (Q-WR2 · Q-WR4 결정).
* WR10 모서리 ㄱ자 (@s_v, 교대 끝면 쪽), WR20 간격재. 교대 철근과의 간섭은 보지 않는다 (Q-WR2 · Q-WR4 결정).
* - 단축형 (QA-14 · §9): WR1 · WR11 · WR6 없음, 연직은 모두 등단면.
* - 좌표: 교대 (s, t, z) — s 교대축 (IP1에서), t 교대축 직각 (전면 +), z 저판 하면에서. 날개벽 거리 d는 교대축 선에서 날개벽 방향.
*/
@@ -41,6 +41,9 @@ export const ABUT_WING_SIZES = {
} as const satisfies Record<string, BarSize>;
export type WingMark = keyof typeof ABUT_WING_SIZES;
/** WR10 ㄱ자 (사용자 도면 2026-11-05): 날개벽 바깥면 피복, 교대 쪽 다리, 날개벽 쪽 다리 (mm). */
export const WR10 = { cover: 123, abutLeg: 3000, wingLeg: 1000 } as const;
type V2 = [number, number];
/** 한 측 날개벽 형상 (mm, 교대 s · t, z는 저판 하면에서). */
@@ -443,18 +446,13 @@ export function abutWingRebar(g: AbutWingGeom, changes?: Partial<AbutWingRebarSe
put('WR9', pts, la9 + Math.hypot(depthLow - (T - c), zTopLeg - zLow) + h16);
}
}
// WR10 (§7): 모서리 L 꺾임 @s_v, 저판 상면 + c ~ 흉벽 상단 − c. 교대 배면 · 날개벽 배면에서 각 120.65 안, 모서리 대각 300, 양끝 l_d.
// WR10 (§7, 사용자 도면 2026-11-05): ㄱ자 @s_v, 저판 상면 + c ~ 흉벽 상단 − c. 꺾이는 점 = 날개벽 바깥면(교대 끝면)에서 피복 123 안쪽 선과
// 흉벽 배면 + 123 선(흉벽 · 벽체 구간 모두 콘크리트 안)이 만나는 곳. 교대 쪽 다리 3,000 (s 방향, 교대 안쪽), 날개벽 쪽 다리 1,000 (바깥면 − 123).
{
const depth10 = c + (d('H16') + d('H25')) / 2;
const r = 300;
const B = lineX(at(0, WR10.cover), wDir, [0, g.parapetBackT + WR10.cover], [1, 0]);
for (let z = g.footTop + c; z <= g.topStart - c + 1e-6; z += sBackV) {
const backT = z > g.bracketTop + 1e-6 ? g.parapetBackT : g.wallBackT;
const wingLine = at(0, T - depth10);
const X = lineX(wingLine, wDir, [0, backT + depth10], [1, 0]);
const X1 = add2(X, uOut, r);
const X2 = add2(X, wDir, r);
const leg = legEnd(X2, z);
put('WR10', [P3(add2(X1, uOut, ld.H25), z), P3(X1, z), P3(X2, z), P3(add2(X2, wDir, leg), z)], ld.H25 + leg + Math.hypot(X2[0] - X1[0], X2[1] - X1[1]));
const leg = Math.min(WR10.wingLeg, legEnd(B, z));
put('WR10', [P3(add2(B, uOut, WR10.abutLeg), z), P3(B, z), P3(add2(B, wDir, leg), z)], WR10.abutLeg + leg);
}
}
// WR20 (§8): 간격재, 수평 @k·s_h × 연직 @k·s_v, 단마다 반 칸 엇갈림, 전면 · 배면 수평철근 사이 + 양끝 갈고리.
@@ -507,7 +505,7 @@ export function abutWingRebar(g: AbutWingGeom, changes?: Partial<AbutWingRebarSe
push({ mark: 'WR7-2', size: SZ['WR7-2'], role: '헌치', spacing: hz2, actual: hz2, shape: wr7Shape('흉벽 전면'), position: '아래 헌치 윗부분 · 교좌면 ~ 브라켓 상면', note: '띠 경계 브라켓 상면 / 교좌면 (Q-WR6)', basis: '규칙', modified: hMod });
push({ mark: 'WR7-3', size: SZ['WR7-3'], role: '헌치', spacing: hz2, actual: hz2, shape: wr7Shape('벽체 전면'), position: '아래 헌치 아랫부분 · 저판 상면 ~ 교좌면', note: 'WR8 결번', basis: '규칙', modified: hMod });
push({ mark: 'WR9', size: SZ.WR9, role: '헌치', spacing: lenText(2 * sBack), actual: lenText(2 * sBack), shape: `꺾임 · 연직 다리 ${lenText(la9)} · 헌치 빗변과 나란한 대각 · 저판 하면망에서 90° 갈고리 ${h16}`, position: '저판 상면 헌치 (날개벽 배면) · 벽체 배면 ~ 뒷굽 끝', note: `연직헌치 보강 (사용자 도면 2026-11-04) · @${lenText(2 * sBack)} 자동 개수 · 연직 다리 = 벽체 W9 · W10 정착장`, basis: '규칙', modified: vMod });
push({ mark: 'WR10', size: SZ.WR10, role: '모서리', spacing: hz1, actual: hz1, shape: `꺾임 · 모서리 대각 300 · 양끝 l_d ${ld.H25}`, position: '벽체 · 흉벽 배면 ↔ 날개벽 배면 모서리 · 저판 상면 ~ 흉벽 상단', note: '헌치 철근과의 간섭은 보지 않음 (Q-WR4)', basis: '규칙', modified: hMod });
push({ mark: 'WR10', size: SZ.WR10, role: '모서리', spacing: hz1, actual: hz1, shape: `ㄱ자 · 교대 쪽 ${WR10.abutLeg} · 날개벽 쪽 ${WR10.wingLeg}`, position: `교대 끝면 · 날개벽 바깥면 − ${WR10.cover} · 흉벽 배면 + ${WR10.cover} · 저판 상면 ~ 흉벽 상단`, note: '사용자 도면 2026-11-05 (교대와 날개벽을 묶는 모서리 보강)', basis: '규칙', modified: hMod });
push({ mark: 'WR20', size: SZ.WR20, role: '간격재', spacing: `${lenText(s.k20 * sBack)} × ${lenText(s.k20 * sBackV)}`, actual: '—', shape: `양끝 90° 갈고리 ${hook(SZ.WR20)}`, position: `내측 간격재 · 두께 ${lenText(T - 2 * (c + (d('H16') + d('H25')) / 2))} 걸침`, note: '철근표 H20은 오기 → H13', basis: '규칙', modified: s.k20 !== 8 });
return { side: g.side, settings: s, vertical, levels, haunchLevels, ld, paths, bars, issues };
+20
View File
@@ -170,3 +170,23 @@ describe('WR7 평면 형상 (사용자 도면 2026-11-05)', () => {
expect(R.haunchLevels['WR7-3']).toBeLessThan(total - R.haunchLevels['WR7-1'] - 6);
});
});
describe('WR10 ㄱ자 (사용자 도면 2026-11-05)', () => {
it('꺾이는 점은 날개벽 바깥면 − 123 · 흉벽 배면 + 123, 교대 쪽 다리 3,000 (s 방향), 날개벽 쪽 다리 1,000; 단 수 38 그대로', () => {
const p = L1.paths.find((q) => q.mark === 'WR10')!;
expect(p.pts.length).toBe(3);
const [a, B, e] = p.pts;
expect(B[1]).toBeCloseTo(left.parapetBackT + 123, 6);
expect(a[1]).toBeCloseTo(B[1], 6); // 교대 쪽 다리는 s 방향
expect(Math.abs(a[0] - B[0])).toBeCloseTo(3000, 6);
expect(Math.hypot(e[0] - B[0], e[1] - B[1])).toBeCloseTo(1000, 6);
const [ws, wt] = left.w;
const iw = left.inward[0] * ws + left.inward[1] * wt;
const nv = [left.inward[0] - iw * ws, left.inward[1] - iw * wt];
const T = Math.hypot(nv[0], nv[1]);
expect(((B[0] - left.p0[0]) * nv[0] + (B[1] - left.p0[1]) * nv[1]) / T).toBeCloseTo(123, 6);
// 교대 쪽 다리는 교대 안쪽 (날개벽에서 반대쪽 날개벽 방향)으로.
expect(Math.sign(a[0] - B[0])).toBe(Math.sign(left.inward[0]));
expect(bar(L1, 'WR10')?.count).toBe(38);
});
});