Files
Pier_v1/Code/rebar_pipeline
ahnyongjooandClaude Sonnet 5.5 964a841de1 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>
2026-10-28 11:20:18 +09:00
..

철근 생성·검토·재료표 파이프라인 (대호지교 P1 두부보 작업에서 검증, 2026-10-02)

나중에 "도면(DXF) → 라이노 철근 생성 → 검토 → 재료표 DXF 출력" 프로그램으로 만들기 위한 방법 정리. 모든 Rhino 코드는 rhino_mcp execute_rhino_code (IronPython 2.7) 기준.


0. 환경 제약 (반드시 지킬 것)

  • f-string 금지, walrus 금지, 타입힌트 금지.
  • exec 스코프 문제: 함수 안에서 모듈 전역 변수를 못 본다. 리스트 컴프리헨션·lambda 안에서 바깥 변수 참조 시 name 'x' is not defined 에러.
    • 해결: 루프는 while/for로 풀어 쓰기, 함수가 필요하면 기본인자로 바인딩 def L(x, ents=ents):.
  • 출력은 마지막에 result = "..."; print(result).
  • 무거운 계산(AreaMassProperties.Compute 다수 호출)은 MCP 소켓 타임아웃 → 마크별로 나눠 호출, 면적 대신 isocurve 길이 사용.
  • sc.sticky[...]에 중간 결과를 저장해서 다음 호출에서 이어 쓰기.
  • 이 PC에는 Python/ezdxf 없음 → DXF 파싱은 bash tr -d '\r' | awk, DXF 쓰기는 IronPython으로 UTF-8 저장 후 iconv -t CP949.
  • 라이노 오브젝트 삭제는 사용자 확인 후에만.

1. 도면(DXF) 읽기

DXF는 AC1021(UTF-8 텍스트), $DWGCODEPAGE=ANSI_949. group code/value가 2줄씩 반복.

  • awk/txt.awk : TEXT/MTEXT/ATTRIB → x y 타입 문자열 (좌표 정렬하면 표가 행 단위로 읽힘)
  • awk/geo.awk : LINE / LWPOLYLINE / ARC → 선형 추출 (레이어 포함)
  • awk/ins.awk : INSERT / CIRCLE 등 → 블록 삽입점 (철근 단면 점 = 블록 CSBSEC1)
tr -d '\r' < "철근재료표 및 상세(...).dxf" | awk -f txt.awk | sort -t$'\t' -k2,2nr -k1,1n > mat.tsv
tr -d '\r' < "코핑구조도(...).dxf"      | awk -f geo.awk > cop_geo.tsv

1-1. 재료표 해석 (같은 y = 같은 행)

열 x 경계(원본): 번호|형식|직경|개수|A|B|C|D|E|R|X1|X2|J|길이|총길이|단위중량|총중량|총중량(할증)

  • " = 위 행과 같은 직경.
  • 1000mm 이상은 m(소수 3자리), 미만은 mm 정수로 표기.
  • 단위중량: H16 1.560, H19 2.250, H22 3.040, H25 3.980, H29 5.040 (kg/m).
  • 할증: H22 이상 6%, H19 이하 3%. 별도로 "소계(겹이음 할증 6.80%)" 행 = 소계중량×1.068.
  • 형식 V(⊓뚜껑+⊔바닥 박스) 길이 규칙: L = 2A + 2B + 2C (A=폭, 1250/1005 두 종류면 평균; B=박스 전체높이(바닥 다리); C=뚜껑 다리 510=겹침). 재료표 L은 평균, 총길이=Σ.
  • 형식 VII(C8/C10): L = a+b+c+d, X1/X2 = 꺾임 사잇각.

1-2. 조립도/평면도에서 형상·위치 읽기

  • 레이어 CS-RBAR-MAJR 선 = 철근 중심선. CS-CONC-MAJR = 콘크리트 외곽. CS-CNTL = 중심선.
  • 텍스트 "주철근 조립도(정면도) ①CYCLE / ②CYCLE" 근처 ATTRIB(마크명 + "H25 @ 250")로 어떤 마크가 어느 CYCLE인지 판단.
  • 조립도 좌표 → 코핑 로컬 s: s = x - (코핑 중심 x); 코핑 중심 = 길이 23960 주철근 양 끝 중점 등으로 구함.
  • 평면도에서 폭방향 위치: 수평 RBAR 선들의 y 값 → w = y - 중심선y. 치수 tick(CZDIMA1 블록) 간격(120, 130, 24@125 …)으로 피복·간격 확인.
  • 검증 요령: 도면 선 길이가 재료표 치수와 정확히 같으면(예: 4167.1, 3158.8) 그 도면 선이 철근 중심선임을 확신할 수 있다.

2. 코핑 로컬 좌표계 & 단면 외곽

ang = math.radians(19.105)   # 코핑 길이방향 (수평 edge 방향 히스토그램으로 구함)
u  = Vector3d(cos, sin, 0)   # 길이방향 s
wv = Vector3d(-sin, cos, 0)  # 폭방향 w
c  = coping.GetBoundingBox(True).Center   # 원점
  • 길이방향 각도: Brep.Edges 중 수평(|dz|<1)·길이>1000 edge들의 atan2 각도 히스토그램.
  • 단면 외곽: Intersection.BrepPlane(brep, Plane(c, u, Z)) → DuplicateSegments() → 각 세그먼트를 (s, z)로 출력.
  • 뷰 정렬(좌표 안 바꾸고 보기만): vp.SetCameraLocations(target, target - dir*1e5); vp.CameraUp = Z (Left: dir=u, Front: dir=u를 90° 회전), ChangeToParallelProjection(True).

3. 철근 중심선 생성 (피복 = 철근 중심 기준 120)

  1. 단면 외곽의 각 면을 안쪽으로 120 오프셋한 직선들로 표현 (점 + 방향 + 안쪽 법선).
  2. 인접 오프셋선끼리 교점 → 꺾임점. 2D (s,z)에서 직접 풀면 됨.
  3. 도면에 고정 길이 구간이 있으면(예: a=630 수직다리, d=2331 끝 연장) 그 길이만큼 연장해 끝점 결정.
  4. 3D 변환: P = c + u*s + wv*w + Z*(z - c.Z); 대칭 마크는 s 부호만 반전.
  5. 폭방향 위치(w)는 도면 평면도 기준. 1CYCLE: ±1630, ±1375 … ±125 (14본) / 2CYCLE: ±1500 … 0 (13본).
  6. 굽힘: KDS 24 14 21 표 4.5-1 최소 내면지름(이형 D16이하 2db, D19이상 3.5db → 내면 반지름 1db/1.75db) 이상의 내면 R + 철근반지름 = 중심선 R. 적용할 R값은 사용자 결정 [미확정]. (기존 모델의 R=3db/4db는 과거 값)
    pc = Polyline(pts).ToPolylineCurve()
    fc = Curve.CreateFilletCornersCurve(pc, Rc, tol, angtol)       # 모든 내부 모서리 한 번에
    brep = Brep.CreatePipe(fc, r, False, PipeCapMode.NONE, False, tol, angtol)[0]
    
    검증: 1/fc.CurvatureAt(t).Length 최소값 == Rc.
  7. 블록에 넣을 때: 인스턴스 Xform 역변환 후 InstanceDefinitions.ModifyGeometry(idx, geoms, attrs) (3인자 형태, 원본 attrs Duplicate — 색상 깨짐 방지). 수정 전 기존 형상은 <마크>_backup_YYYYMMDD 블록정의로 보관.

색상 규칙 (직경별, ACI)

H10/H13=74, H16=5, H19=210, H22 이상 전부 (104,0,25).

  • 얕은 구조(문서인스턴스→leaf): leaf ColorFromLayer, 마크 레이어 색.
  • 깊은 구조(C12~C18: mark→station→box→leaf): station·box·leaf 3단계 모두 ColorFromParent. 하나라도 ColorFromLayer면 엉뚱한 레이어색(코핑 황토색)으로 보임.

4. 검토(감사) 방법

4-1. 파이프 Brep에서 중심선 복원 (빠름)

각 face에서 isocurve 한 방향이 닫힌 원(길이 2πr)이면 파이프 면 → 다른 방향 isocurve를 원주 0과 0.5 위치에서 2개 뽑아 평균:

  • 중심선 길이 = (len(iso@0) + len(iso@0.5)) / 2 (굽힘 토러스에서도 정확)
  • 직선 면이면 양 끝점 평균 = 중심선 선분.
  • 선분들을 끝점 근접으로 체인 연결 → 인접 선분 Intersection.LineLine으로 가상 교점 → **재료표 방식 치수(교점 간 거리)**와 사잇각.
  • 막힌(캡) 파이프: 평면 face 중심 = 열린 끝점. 열린 파이프: DuplicateNakedEdgeCurves 원 중심.

4-2. 피복

  • 철근 표면을 BrepFace.PointAt 격자(60×24)로 샘플 → coping.ClosestPoint 최소거리 + r = 중심 피복.
  • FastRenderMesh 정점 사용 금지(엉터리 값 91~104 나옴).
  • 수직 레이캐스트(Intersection.RayShoot)는 상·하면까지 거리 참고용. 경사면 근처는 ClosestPoint 사용.
  • 상단 직선 철근: "그 철근이 지나는 구간의 가장 낮은 상면"에서 120 (C26 교훈).

4-3. 개수

  • 단순 마크: 인스턴스 정의 leaf 개수.
  • 박스 마크: mark idef → station 인스턴스 → box 인스턴스 개수(인스턴스 수로 셈, 정의 수 아님).

4-4. 박스(V형) 측정

box 정의의 조각 중 높이가 큰 2개 = 뚜껑/바닥(아래쪽이 높은 것이 뚜껑). 나머지 = 연장 필러.

  • A = 뚜껑 양 끝점 거리, 뚜껑top = bbox.Max.Z − r, 바닥bot = bbox.Min.Z + r
  • 필러가 뚜껑 끝에 닿으면 뚜껑 연장, 바닥 끝에 닿으면 바닥 연장.
  • C = 뚜껑top − 뚜껑끝, B = 바닥끝 − 바닥bot, 겹침 = 바닥끝 − 뚜껑끝 (510 미만이면 결함).
  • 재료표 비교: 재료표 A·높이 = 모델 + 47.6 (= 2×(주철근 r + 스터럽 r)) → 도면은 스터럽이 주철근 바깥을 감쌈.

5. 재료표 DXF 출력

  • 형식: R12 (AC1009), $DWGCODEPAGE=ANSI_949, TABLES에 LTYPE CONTINUOUS / LAYER / STYLE(KOR, malgun.ttf), ENTITIES에 LINE, TEXT(72=1, 73=2 가운데정렬 + 11/21 정렬점).
  • 원본 표 규격: 열 경계 상대 x = 0,1200,2400,3600,4800,6800,8800,10800,12800,14800,16800,18800,20800,22800,24800,26400,28000,29600,31200 (+비고 열 ~40000), 헤더 960(2단), 행 480, 글자 200, 제목 560.
  • 행 순서: [H29 그룹][소계][소계(겹이음 6.80%)] → H25 → H22 → H19 → H16 … → 총계, 총계(겹이음).
  • 소계 행은 세로선을 왼쪽 끝 + 길이 열 이후만 그림(병합셀 흉내).
  • 계산: 중량(t) = 총길이 × 단위중량 / 1000, 할증 = ×1.06 또는 ×1.03, 겹이음 = ×1.068. 총계는 반올림된 소계들의 합(원본과 동일 방식).
  • 저장: IronPython System.IO.File.WriteAllText(p, txt.replace("\n","\r\n"), UTF8Encoding(False)) → bash iconv -f UTF-8 -t CP949.
  • 검증: RhinoDoc.CreateHeadless(None).Import(path)로 별도 문서에 불러와 텍스트/선 개수·한글 확인 후 Dispose (루프 변수 None 처리 필수).
  • 파일명 규칙: YYMMDD_철근재료표 작업중.dxf (도면 폴더에 저장).

5-2. 측면철근/캡타이 (C19~C25, 2026-10-02 검증)

  • 배치 근거: 단면 A-A/B-B/C-C의 철근 점(블록 CSBSEC1) y값 = 측면철근 높이(200 간격), x값 = 폭 위치. 정면도 점 = 폭방향으로 가로지르는 철근(C25)의 (s, z). 정면도 점 개수 합 = 재료표 수량으로 검증.
  • 도면→모델 좌표: 정면도 s = x − (코핑 중심 x), z = 7738 + (y − 기둥위 하면 y). 방향 반전 여부는 비대칭 마크(C12 = s 최소 쪽)로 판단.
  • VI 닫힌 고리: 높이별로 120 오프셋 경계(헌치 대각/끝면) + WRAP(주철근 r + 고리 r, 바깥 감싸기) → 재료표 A와 정확히 일치. 닫힌 폴리라인은 변 중간에서 시작해야 4모서리 모두 필렛됨. 띠철근 R=2db.
  • VIII 갈고리 직선: 135° 갈고리, 중심 R=60 (호 길이 = 재료표 b 141), 연장 c=100, L=A+2(b+c). A = 고리 A − 9. 갈고리는 수평면 안에서, 폭 바깥쪽(w 부호 방향)으로 (사용자 지시 2026-10-02). 위·아래로 꺾지 않음 (아래는 헌치 관통, 위는 잘못된 방향). 안쪽으로 꺾으면 중앙 ±106 철근끼리 갈고리가 겹침.
  • III ⊓ (C25): 윗변 A=3260 폭방향(w ±1630), 다리 300 아래. 점 위치가 하면에 가까우면 다리 관통 → 생성 시 (z−300) − 하면z < 120 자동 검출해서 보고.
  • 생성 방식: 마크별 InstanceDefinition 1개(월드좌표 형상, 기준점 원점) + Identity 인스턴스 1개, leaf ColorFromLayer, 레이어 ..._1CYCLE::C{n}_H16 파랑(0,0,255).
  • 피복 검증: 긴 철근 전체를 Brep.ClosestPoint로 샘플링하면 MCP 타임아웃 → 대표 지점 몇 개를 Brep.ClosestPoint로 재고, 관통 여부는 Edge 점 IsPointInside로.
  • 화면 격리 보기: 다른 레이어 IsVisible=False (인덱스 목록 sticky에 저장) → 파일 저장 전 복구 → 저장 → 다시 숨김.

5-3. 간섭 / 튀어나옴 / 피복 일괄 체크 (2026-10-02 검증, 전체 26마크 ~30초)

  1. 중심선 선분 추출: 각 파이프 면에서 원주 0 위치 isocurve를 ToPolyline(0,0,0.05,0,0,0.3,0,3000,True)로 적응 분할 → 각 정점의 곡선 매개변수 t에서 face.PointAt(t, v0)와 PointAt(t, v0.5)의 중점 = 중심점. 중첩 블록은 Xform을 곱해 내려가며 처리, 같은 leaf 형상은 캐시.
  2. 간섭: 마크별 RTree(선분 bbox를 r만큼 키움) → 마크 bbox가 겹치는 쌍만 RTree.SearchOverlaps(treeA, treeB, 0, System.EventHandler[RTreeEventArgs](cb)) (e.Id, e.IdB) → Intersection.LineLine(..., finite=True), 실패(평행)면 Line.MinimumDistanceTo → 관입 = rA + rB − 거리 > 0.5 이면 기록(철근쌍별 최대).
  3. 피복/튀어나옴: 코핑이 폭방향 압출 형상이므로, 점을 (s,w,z)로 바꿔 2D 단면 다각형 내부 판정 + 변까지 거리, 측면은 1750−|w|. 중심피복 < r 이면 튀어나옴. (Brep.ClosestPoint 대량 호출은 타임아웃, 메시 ClosestPoint는 값이 틀어짐)
  4. 출력: CSV(UTF-8 BOM, 엑셀 한글) + 요약 md + 라이노 체크 레이어(TextDot, PointCloud) — 모델 자체는 건드리지 않음.

5-4. CTC 검사 · 박스 철근 보정 · 갈고리 반전 · 재료표 정렬 (2026-10-06 검증)

CTC(철근 중심 간격) 검사 — rhino/07_ctc_extract.py

  • 마크별 리프 Brep 중심점을 코핑 로컬 (s,t,z)로 뽑아 JSON → 고유값(허용오차 1~2mm) 정렬 → 차이를 도면 @ 표기와 대조.
  • 도면 간격 표기는 코핑구조도 DXF의 CS-DIMT TEXT (24@125=3.000, 11@250=2.750, 평면 스터럽 7@300|14@150|8@300|16@150|19@300|…, 38@600=22.800).
  • 주의: 같은 칸의 뚜껑/바닥 조각은 s가 다를 수 있다. 클러스터의 첫 값만 쓰면 가짜 어긋남이 생긴다(실제로 한 번 오판함) → 칸 안의 모든 리프 s의 min/max를 같이 볼 것.
  • 이 값들은 철근 마크 레이어가 꺼져 있으면 doc.Objects 기본 열거에서 빠진다 → ObjectEnumeratorSettings.HiddenObjects=True.

박스(⊓+⊔) 바닥 조각 보정 — rhino/05_realign_base_pieces.py

  • 증상: 피복 보정 때 바닥 조각을 헌치 법선 방향으로 옮겨서 뚜껑과 s 평면이 1~3mm 어긋남 (C12/C18 2.68, C14/C16 1.95).
  • 보정: 어긋남 −dev 만큼 s 이동 + 헌치 경사 접선 방향으로 dz = (경사)·ds 이동(수직 피복 유지) → 뚜껑 윗변 중심 z에서 Brep.Trim 으로 상단 재절단(겹침 510).
  • 박스 idef는 좌우 대칭 인스턴스가 공유하므로 idef 하나만 고치면 4개 박스에 동시 적용됨(검증은 모든 인스턴스로).
  • ModifyGeometry(idx, geoms, attrs) 3-인자 + attrs=ob.Attributes.Duplicate() 로 ColorFromParent 보존. 백업 idef <이름>_bk1006b.

갈고리 방향 반전 — rhino/06_flip_hooks.py

  • 철근 축을 지나는 s-수직 평면으로 자른 단면 원 중심 = 축 위의 점 → Transform.Mirror(축점, 폭방향 법선) + Brep.Flip(). 길이 불변.
  • 선택은 centroid t (갈고리 때문에 축에서 ~2mm 벗어남) 대역으로 하고, 개수가 예상과 다르면 수정하지 않고 보고.

재료표 DXF 텍스트 정렬 — dxf/leftalign.ps1

  • R12/CP949 DXF에서 표 칸 왼쪽 경계(세로선) + 200 위치로 TEXT 왼쪽 정렬(72=0, 73=2). powershell -File leftalign.ps1 -In 원본.dxf -Out 새파일.dxf -Pad 200.
  • 원본 재료표는 가운데(72=1) 242개 / 오른쪽(72=2) 58개 정렬 — 이 파이프라인의 표는 왼쪽 정렬 규칙을 쓴다(사용자 지시).

화면/레이어 함정

  • 블록 안쪽 리프가 다른 레이어(예: P1_두부(코핑))에 있으면, 마크 레이어를 켜도 그 레이어가 꺼져 있으면 안 그려진다. C12~C18 스터럽 리프가 코핑 레이어에 있음 → 철근만 보려면 코핑 레이어는 켜 두고 솔리드/보조선만 객체 단위로 숨긴다.
  • 화면 격리 후 저장할 때는: 현재 표시 상태 저장 → 원래 상태 복구 + 숨긴 객체 Show → doc.Save() → 격리 상태 재적용. (저장은 127MB라 MCP 소켓 타임아웃이 나지만 Rhino 안에서는 계속 진행됨 → 결과 파일 생길 때까지 until-loop로 대기.)
  • Left 뷰 정렬: SetCameraLocations(target, target - dir*60000), dir=(cos a, sin a, 0), CameraUp=Z, 그 뒤 ZoomBoundingBox.

6. 프로그램화 시 모듈 구성 제안

  1. dxf_reader – txt/geo/ins 추출, 재료표 행 파서, CYCLE별 마크 목록, 조립도 철근 polyline.
  2. section – 콘크리트 Brep → 로컬 프레임(u,w,원점) → 단면 외곽 (s,z) 세그먼트.
  3. rebar_builder – 형식(I~VIII)별 중심선 생성기(오프셋선 교점 + 고정길이), 폭방향 배열, KDS R 필렛, 파이프, 블록/레이어/색.
  4. auditor – isocurve 중심선 복원, 치수/각도/개수/피복/겹침 비교 → 차이 리포트.
  5. table_writer – R12 CP949 재료표 DXF (원본 규격 + 비고 열).

5-5. 간섭 재검사 스크립트 (2026-10-06) — rhino/08_clash_check.py

  • 읽기 전용. 철근별 단면 원 중심 → 중심선 선분 → RTree → 선분 최단거리, 관입 = rA+rB−거리 > 0.5. 박스(뚜껑·바닥·연장 조각) 내부와 같은 철근은 제외, P1 레이어만 (P2/P10/P12 숨김 레이어 복사본 제외).
  • 함정: ① BoundingBox(p0, p1) 는 점이 min→max 순서가 아니면 무효 상자 → 큰 교차가 통째로 누락됨. BoundingBox([p0, p1]) 사용. ② 숨김 레이어 객체는 ObjectEnumeratorSettings.HiddenObjects=True 로 열거해야 함. ③ NURBS 파라미터 0.5 지점은 반대편 점이 아님 → 단면 원 TryGetCircle 중심 사용. ④ 실행이 길어 소켓 타임아웃이 나도 Rhino 안에서는 계속 돈다 → 결과 파일 갱신을 until-루프로 대기.