chore(rebar): Pier_T_rebar 작업 폴더 초기 구성 및 외부 의존 파일 통합

- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환
- Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용
- pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관)
- worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md)
- D:\Rhino-MCP 경로 참조를 새 위치로 치환

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ahnyongjooandClaude Sonnet 5.5 committed 2026-10-28 11:20:18 +09:00
commit 964a841de1
3978 files changed
+58013356

No files matched your search

+105
View File
@@ -0,0 +1,105 @@
"""철근 배치(간격, 수량, 중량) 계산 모듈.
Rhino 없이 실행됩니다. 단위는 mm이고, 중량만 kg입니다.
기준값 출처: docs/design_rules.md, 기존 프로젝트 rebar_pipeline/README.md
"""
import rebar_calc
# 단위중량 kg/m (기존 프로젝트 재료표 값). 아래에 없는 규격은 값을 확인한 뒤 추가하세요.
UNIT_WEIGHT = {
"H16": 1.560,
"H19": 2.250,
"H22": 3.040,
"H25": 3.980,
"H29": 5.040,
}
DEFAULT_GMAX = 25.0 # 굵은골재 최대치수(mm). 가정값이므로 설계서의 값으로 바꿔 쓰세요.
EPS = 1e-9
def center_out_positions(count, spacing):
"""중심(0)에서 바깥으로 spacing 간격으로 놓은 폭방향 위치 목록(작은 값부터).
짝수 개이면 중심에 철근이 없고(±spacing/2부터), 홀수 개이면 중심(0)에 철근이 있습니다.
"""
if count < 0:
raise ValueError("철근 수는 0 이상이어야 합니다: %r" % (count,))
if spacing <= 0:
raise ValueError("간격은 0보다 커야 합니다: %r" % (spacing,))
mid = (count - 1) / 2.0
return [spacing * (i - mid) for i in range(count)]
def snapped_array(count, spacing, width, cover):
"""바깥 철근 2본은 피복에 맞추고, 나머지는 중심에서 바깥으로 배치합니다 (1CYCLE 방식).
바깥 철근 위치 = ±(width/2 - cover). 안쪽 철근은 중심에서 바깥으로 spacing 간격입니다.
안쪽 철근이 바깥 철근 위치를 넘어가면 ValueError.
"""
if count < 2:
raise ValueError("바깥 철근 2본이 필요하므로 count는 2 이상이어야 합니다: %r" % (count,))
outer = width / 2.0 - cover
inner = center_out_positions(count - 2, spacing)
if inner and max(inner) >= outer:
raise ValueError("폭 %r 안에 철근 %r본을 간격 %r로 놓을 수 없습니다" % (width, count, spacing))
return [-outer] + inner + [outer]
def min_horizontal_clear(name, gmax=DEFAULT_GMAX):
"""수평 최소 순간격 = max(1.5db, 1.5Gmax, 40mm) (KDS 24 14 21 4.5.3)."""
db = rebar_calc.nominal_diameter(name)
return max(1.5 * db, 1.5 * gmax, 40.0)
def clear_spacing(center_spacing, name):
"""중심 간격에서 철근 직경을 뺀 순간격."""
return center_spacing - rebar_calc.nominal_diameter(name)
def horizontal_spacing_ok(positions, name, gmax=DEFAULT_GMAX):
"""이웃한 철근 사이 순간격이 모두 수평 최소 순간격 이상이면 True."""
ordered = sorted(positions)
need = min_horizontal_clear(name, gmax)
for a, b in zip(ordered, ordered[1:]):
if clear_spacing(b - a, name) < need - EPS:
return False
return True
def min_vertical_clear(name):
"""다단 배근의 연직 최소 순간격 = max(25mm, db)."""
return max(25.0, rebar_calc.nominal_diameter(name))
def vertical_pitch_ok(name, pitch):
"""단 사이 중심 간격(pitch)의 순간격이 연직 최소 순간격 이상이면 True."""
return clear_spacing(pitch, name) >= min_vertical_clear(name) - EPS
def tier_elevations(top_z, cover, tiers, pitch):
"""맨 위 단은 상면에서 cover만큼 아래, 다음 단부터 pitch씩 아래로 내린 높이 목록."""
return [top_z - cover - i * pitch for i in range(tiers)]
def unit_weight(name):
"""단위중량(kg/m)."""
key = "H%d" % rebar_calc.bar_number(name)
if key not in UNIT_WEIGHT:
raise ValueError("단위중량이 등록되지 않은 규격입니다: %r" % (name,))
return UNIT_WEIGHT[key]
def bar_weight(name, length_mm, count=1):
"""철근 length_mm 길이 count본의 중량(kg)."""
return unit_weight(name) * length_mm / 1000.0 * count
def array_summary(name, length_mm, positions):
"""한 배열의 본수, 총길이(m), 중량(kg)."""
count = len(positions)
return {
"count": count,
"total_length_m": length_mm / 1000.0 * count,
"weight_kg": bar_weight(name, length_mm, count),
}