feat(cast): 기둥–말뚝 겹침이음 · 말뚝 철근망 근입부 기준 (Q-PL3·Q-PL6)

현장타설말뚝철근.md §5–§6 (사용자 결정 2026-11-06: 11-06 겹침 결정이 11-05 커플러 회신을 대체).
- 희생강관 기본 적용, 상단 지반고 + 2500 (그림 값, Q-PL4 가정). 암반 근입부 지름 입력 추가(기본 D − 150, 강관 없으면 D)
- 말뚝 철근망 반지름을 근입부 기준으로 (D 3000: r 1300 / 1268.2)
- 두 철근 원이 다르면 자동 겹침이음: 기둥 주철근이 지반고 아래 l_s(1.3 l_d, S32 2387)까지 내려감,
  지반고 커플러 없음. 원이 같으면(근입부 없음) 지반고 커플러. 저장된 방식은 그대로 둠
- 겹침 구간의 말뚝 띠철근은 바깥 기둥 주철근을 감싸는 반지름
- 겹침 모드에서도 주기 커플러(기둥 지반고 + @3000, 말뚝 지반고 − @3000, 내측 + 150)
- RB-PL07: 두 원 간격 > min(l_s/5, 150)이면 경고
- 이전 '겹침부 미계산' 표시 제거. 기존 커플러 테스트는 희생강관 미적용 입력으로 유지

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Opus 5.5 committed 2026-11-06 14:37:12 +09:00
1 parent 3d0d484524
commit 5fec2743cb
6 files changed
+126 -30

No files matched your search

+16 -5
View File
@@ -1,6 +1,6 @@
import type { PierInput } from './types';
/** EL in metres, lengths in mm. User image and clarifications, 2026-11-05. */
/** EL in metres, lengths in mm. User image and clarifications 2026-11-05; casing default and rock socket per 현장타설말뚝철근.md (2026-11-06). */
export interface CastInPlaceShapeSettings {
betaLengthMm?: number;
weatheredRockEl?: number;
@@ -9,9 +9,18 @@ export interface CastInPlaceShapeSettings {
casingTopEl?: number;
casingBottomEl?: number;
clayBottomEl?: number;
/** 암반 근입부 지름 (mm, 희생강관 아래). Absent = D − 150 with a casing, D without (현장타설말뚝철근.md §1.1, Q-PL3). */
socketDiameterMm?: number;
}
export function castShape(input: Pick<PierInput, 'groundEl' | 'pileLengthMm' | 'castInPlaceShape'>) {
/** Rock-socket diameter (mm): the input, else D − 150 when the casing is on (default on, spec §3 2026-11-06), else D. */
export function castSocketDiameterMm(input: Pick<PierInput, 'castInPlaceShape' | 'columnDiameterMm'>): number {
const s = input.castInPlaceShape ?? {};
const d = input.columnDiameterMm ?? 2000;
return s.socketDiameterMm ?? ((s.casingOn ?? true) ? d - 150 : d);
}
export function castShape(input: Pick<PierInput, 'groundEl' | 'pileLengthMm' | 'castInPlaceShape' | 'columnDiameterMm'>) {
const s = input.castInPlaceShape ?? {};
const pileBottomEl = input.groundEl - input.pileLengthMm / 1000;
const bedrockEl = s.bedrockEl ?? pileBottomEl + 1;
@@ -21,10 +30,12 @@ export function castShape(input: Pick<PierInput, 'groundEl' | 'pileLengthMm' | '
betaLengthMm, betaEl: input.groundEl - betaLengthMm / 1000,
weatheredRockEl: s.weatheredRockEl ?? pileBottomEl + 5,
bedrockEl,
casingOn: s.casingOn ?? false,
casingTopEl: s.casingTopEl ?? input.groundEl + 3,
// 희생강관: 적용, 상단 지반고 + 2500 (그림 값, 엑셀 문구 + 3000 — Q-PL4 가정), 하단 = 기반암 EL.
casingOn: s.casingOn ?? true,
casingTopEl: s.casingTopEl ?? input.groundEl + 2.5,
casingBottomEl: s.casingBottomEl ?? bedrockEl,
clayBottomEl: s.clayBottomEl,
socketDiameterMm: castSocketDiameterMm(input),
};
}
@@ -35,7 +46,7 @@ export function castShapeIssues(value: unknown): string[] {
for (const [key, v] of Object.entries(value)) {
if (v === undefined) continue;
if (key === 'casingOn') { if (typeof v !== 'boolean') out.push('희생강관 적용 여부가 맞지 않습니다.'); }
else if (!['betaLengthMm', 'weatheredRockEl', 'bedrockEl', 'casingTopEl', 'casingBottomEl', 'clayBottomEl'].includes(key) || typeof v !== 'number' || !Number.isFinite(v) || key === 'betaLengthMm' && v <= 0) out.push(`현장타설 형상 ${key} 값이 맞지 않습니다.`);
else if (!['betaLengthMm', 'weatheredRockEl', 'bedrockEl', 'casingTopEl', 'casingBottomEl', 'clayBottomEl', 'socketDiameterMm'].includes(key) || typeof v !== 'number' || !Number.isFinite(v) || (key === 'betaLengthMm' || key === 'socketDiameterMm') && v <= 0) out.push(`현장타설 형상 ${key} 값이 맞지 않습니다.`);
}
return out;
}