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

@@ -0,0 +1,121 @@
# Drawing Model Studio — 에이전트 작업 지침
사용자가 이 프로그램을 개발하며 정한 기준과 기존 정책문서를 통합한 저장소 지침이다. 저장소 전체의 코드 수정·모델 생성·검증·뷰어·캐시·보고서·배포 작업에 적용한다. 정리일: 2026-10-06.
## 목적과 우선순위
- 목표는 입력 도면에 대응하는 범용 공통 코드다. 도면명·시트 수·과거 모델에 의존하지 않고 현재 도면의 객체·치수·상세·배근 근거로 생성하며, 새 도면을 지원하도록 수정한 코드로 기존 검증 모델도 재현해야 한다.
- 사용자는 엔지니어다. 원도면과 사용자가 정한 기준을 결과에 맞춰 임의로 변경하지 않는다. 기존에 되는 코드를 먼저 확인하고, 안 되는 부분의 원인을 고친다.
- 현재 사용자의 명시적 지시가 기존 프로젝트 문서보다 우선한다. 개별 도면·제작행에 허용한 예외를 다른 객체나 새 도면에 확대하지 않는다.
- 기준 충돌은 적용 대상과 근거를 확인해 해결한다. 과거 문서의 작업 한정 제외·중단 조건을 전체 기능의 영구 제한으로 옮기지 않는다.
- 문서 작성, 코드 반영, 모델 생성, 화면 표시, 자동 검사 통과, 사용자 확정은 각각 실제 수행 여부를 구분해 보고한다.
## 작업 전 읽을 문서
코드 위치와 실행 방법은 [README.md](../README.md)를 확인한다. 작업에 해당하는 아래 문서는 수정 전에 끝까지 읽는다.
- 형상·철근 생성 또는 검증: [DRAWING_MODELING_RULES.md](../src/backend/DRAWING_MODELING_RULES.md).
- 객체 귀속·부분 병합·공통 생성: [OBJECT_MODEL_CONTRACT.md](OBJECT_MODEL_CONTRACT.md), [객체별 역할 및 모델링 적용 기준](OBJECT_MODELING_DEFINITIONS_AND_CRITERIA.md).
- 본체 사이클·일반부/경사부·배근 분류: [기존 배근 알고리즘 기준](../src/backend/BLOCK1_ALGORITHM_RULES.md). 문서의 특정 모델 본수·피치와 작업 한정 날개벽 제외를 범용 상수·제외 규칙으로 사용하지 않는다.
- 개별 작업에 별도 검증 기준이 있으면 그 작업에서만 읽고 적용한다. 전용 객체 수·철근 치수·본수를 공통 생성 기준으로 복사하지 않는다.
- 콘크리트 공제·산식: 저장소의 수량 산출 기준 문서와 실제 보고서 계산 코드. 외부 기준을 변경하거나 최신 기준이라고 설명할 때는 적용 문서·판본·조항을 다시 확인한다. 기준 문서가 없으면 확인한 출처와 적용 범위를 기록한다.
- 이전 검증을 참고할 때: 해당 브랜치에 보관된 공통 코드 검증 기록. 기록이 없는 검사를 통과했다고 가정하지 않으며 부분 검사 결과를 전체 모델 검증으로 확대하지 않는다.
## 도면 일치와 수정 완료 기준
**모든 형상은 객체별로 원도면의 평면·종단·정면·단면·상세와 일치해야 한다. 불일치하면 원인을 확인하고 생성 코드 또는 도면 연결을 수정한 뒤 재생성·재검증한다. 도면과 맞지 않는 형상을 완료 결과로 내보내지 않는다.**
- 불일치는 작업 종료 이유가 아니다. 기존 정상 결과를 유지하면서 원도면 확인 → 원인 수정 → 재생성 → 재검증을 이어간다. 실제 근거 충돌이나 외부 장애는 구체적으로 보고하고, 독립적으로 진행할 수 있는 범위는 계속 처리한다.
- 결과가 나오게 하려고 도면 치수·좌표·수량, 검증 기준, 허용오차, 통과 조건을 바꾸지 않는다. 누락 검사를 건너뛰거나 상태 플래그만 바꿔 통과시키지 않는다.
- 정확도는 객체·절점·면·투영·치수·수량별 검사 근거로 확인한다. 화면이 비슷하거나 기존 캐시와 같다는 이유만으로 전체 일치를 선언하지 않는다. 수치 연산 오차와 실제 도면 불일치를 구분하고 오차를 숨기지 않는다.
- 근거가 부족하면 해당 원도면 영역·치수선·리더·설치면을 다시 확인한다. 카테고리 상식이나 이전 모델의 좌표로 빈 부분을 임의 완성하지 않는다.
## 객체별 정보와 부분 수정
- 상·하부 슬래브, 좌·우 벽체, 헌치, 날개벽, 난간벽, 접속슬래브, 브래킷 등 실제 물리 객체를 각각 유지한다. 여러 부재를 하나의 덩어리로 대체하지 않는다.
- 객체별 ID, 역할, 블럭, 좌우·시종점, 위치·표고, 사용한 도면 뷰, 접합 객체, 형상, 소속 철근, 물량, 검사 결과를 연결한다. 이름이 같아도 다른 물리 발생 객체는 독립적으로 남긴다.
- 설치 구역과 실제 분할 객체 수를 구분한다. 도면에 있는 이음으로 나뉜 객체를 임의로 합치거나, 발생 수를 문자 출현 횟수로 정하지 않는다.
- 철근은 그룹 호스트 목록과 별도로 한 본마다 소속 객체(`occurrence_instance_ids`)를 유지한다. 조회·이동·공제도 해당 한 본의 귀속을 사용한다.
- 검증된 객체는 보존한다. 수정 대상과 직접 연결된 범위만 다시 처리하고, 부분 결과로 전체 모델·본체·다른 블럭을 덮어쓰지 않는다.
- 객체별 구조는 향후 WBS·OBS·공정·자원·비용과 연결해 4D·5D BIM으로 확장할 기반이다. 이 연결을 위해 물리 ID·소속·물량을 보존하되, 아직 구현하지 않은 기능을 완료로 설명하지 않는다.
## 콘크리트 형상과 뷰어 방향
- 평면도는 위에서 본 도면이다. 평면에서 위치·방향·스큐·슬래브 절단 방향·날개벽 방향을 결정하고, 정면·종단·상세에서 높이·두께·구배·표고를 연결한다.
- 블럭별 종단 경사와 접속슬래브·브래킷 받침 높이를 함께 확인한다. 상·하부 슬래브와 접속슬래브의 두께·높이는 현재 도면에서 확인하며 특정 모델의 값을 범용 기본값으로 고정하지 않는다.
- 내부 헌치는 실제 삼각 단면을, 날개벽 접합 헌치는 실제 접촉 범위와 높이를 사용한다. 사각 덩어리나 본체 전체 길이로 대체하지 않는다.
- Top/Bottom, 축, 카메라 및 회전 조작 방향을 실제 투영으로 검사한다. 이미지를 맞추려고 모델 좌표·방향을 뒤집지 않는다. 치수보기 이미지 방향 수정과 모델 변경을 구분한다.
- 기본 뷰어에는 실제 형상 외곽과 물리 경계선을 표시한다. 평면 메시 삼각분할선은 숨기되 실제 절단·굴곡·객체 경계는 남긴다.
- 모델과 철근은 기존 뷰어에서 보여준다. 별도 형상검토창을 임의로 추가하지 않는다. 기존 톤·명칭·조작을 유지하고 화면을 바꾸면 실제 브라우저에서 확인한다.
## 철근 생성과 체결
- 형상을 먼저 확인하고 기존 생성 규칙으로 철근을 만든다. 일반부와 경사부의 설치 범위를 현재 도면에서 분리하며 경계 중복·누락·잘못된 연장을 허용하지 않는다.
- 사이클, 헌치근, 연결근은 도면에서 정한 소유 관계와 공통 station을 따른다. 임의 중앙정렬·독립 재분배·수량 맞추기용 간격 압축을 하지 않는다.
- 한 본 상세의 절점·절곡 순서·각도·반지름·직경·구간 길이·정착 방향을 유지한다. 외곽에 맞추려고 자르거나 늘이거나 축척하지 않는다.
- 제작 역할의 대응은 상세 형상과 설치면·객체 관계로 판단한다. 마크는 제작행 추적과 사용자가 지정한 이동 대상 식별에 사용하며, 같은 마크라는 이유만으로 다른 상세를 같게 생성하지 않는다.
- 피복은 객체·면별 도면값이다. `100(상면)`, `100(하면)` 같은 표기를 연결하고 명목 피복과 철근 반지름을 구분한다. 임의 공통 피복으로 대체하지 않는다.
- 본체·날개벽·접속슬래브의 수평근·수직근 등 체결 대상 철근을 먼저 생성한 후 체결근을 배치한다. 콘크리트 안에 있다는 것만으로 체결로 판정하지 않고 실제 대상 철근을 감싸고 연결하는지 확인한다.
- 날개벽의 전면·배면·상부 수평근·수직근·단부근·연결근·체결근 등 현재 도면 제작행을 전수 확인한다. 특정 철근명을 전제로 생성하거나 도면에 존재하는 행을 누락하지 않는다.
- 연결철근의 긴 구간·경사 구간을 평면과 상세로 확인한다. 한쪽을 중복시키고 반대쪽 긴 부분을 비우지 않는다. 브래킷 철근도 현재 도면의 상세와 실제 각 발생 객체에 연결한다.
- 직경을 포함한 관 형상, 설치면, 정착 구간, 피복·외곽 이탈을 검사한다. 도면상 의도된 연결 틈·정착을 잘못된 돌출과 구분하며, 특정 마크의 검사 전체를 면제하지 않는다.
- 제작 상세 길이 합, 한 본 길이, 물리 본수, 총연장을 독립 대조한다. 도면 배근과 재료표가 실제로 충돌하면 둘의 값을 보존한다. 사용자가 도면 형상 우선으로 수량 차이를 허용한 범위는 그 허용을 기록하고 해당 수량 차이를 통과로 조작하지 않는다.
- 기존 철근 구분명과 블럭별 조회 순서를 유지한다. 역할 장부·화면 필터·물리 객체 귀속을 혼동하여 분류를 늘리거나 중복 집계하지 않는다.
## 사용자 피드백과 수정본
- 사용자가 지정한 객체·철근 번호·축·거리를 유지하고, 불확실한 항목만 채팅 안에서 실제 모델의 후보로 선택하게 한다. 이해하지 못했다는 이유로 포괄적인 제한이나 불필요한 기능 확장을 추가하지 않는다.
- 선택 전에는 변경하지 않으며, 선택하지 않은 객체와 철근은 보존한다. 모델이 바뀌면 이전 모델의 선택을 새 모델에 적용하지 않는다.
- 현재 철근 채팅의 범위는 번호 하나의 전체 또는 한 객체 소속 전체의 위치 이동이다. 이어지는 거리 입력을 같은 요청에 연결하며 회전·복사·새 철근 생성까지 임의 확대하지 않는다.
- 사용자가 요청한 도면 없는 기본 도형 생성과 후속 치수 변경을 지원하는 경로는 도면 근거 필수 규칙으로 막지 않는다. 이 경로의 입력 단위·치수와 기존 도면 모델을 구분한다.
- 사용자 요청에 따른 이동 미리보기·치수 수정·사용자 확정은 도면 자동 검사 승인과 구분한다. 새 좌표가 이전 좌표의 검사 결과를 상속하지 않는다.
- 철근 수정 후 OBJ는 수정 전 원본과 현재 수정된 모델을 선택해 내보낸다. 사용자에게 허용된 검토용 수정본도 실제 수정 좌표·철근을 포함하되 자동 승인본으로 바꾸지 않는다. 현재 각도 반영 선택과 mm 단위를 일관되게 반영한다.
## 캐시·JSON·수량·보고서
- 동일 도면의 원본 바이트 해시와 도면 묶음으로 저장 결과를 먼저 조회한다. 이름만 같다는 이유로 다른 모델을 재사용하지 않는다. HTTP 환경에서도 서버 해시 조회가 작동해야 한다.
- 기존 캐시가 있는데 전체 도면 분석을 다시 시작하는 문제를 조사할 때 파일명 정규화·도면 묶음·해시·저장 경로·검증 버전을 확인한다. 캐시를 통과시키려고 근거와 검사 상태를 바꾸지 않는다.
- 원도면 추출·근거·잠긴 형상을 재사용하고 수정 범위만 다시 해석한다. 반복 배치·좌표·길이·체적·수량 계산은 코드로 수행한다. 필요 없는 AI 호출을 추가하지 않는다.
- 같은 서버를 여는 다른 PC에서도 저장 모델을 조회할 수 있도록 서버의 영구 저장소를 사용한다. 다른 PC에 Git을 클론하는 것과 캐시를 이전하는 것은 다르므로 배포용 데이터 전달·설치 경로를 확인한다.
- 사용자가 보존하도록 지정한 도면 묶음·모델 캐시·관련 JSON을 유지한다. 보존 대상을 특정 도면명이나 고정 개수로 제한하지 않는다. 기타 파일·백업 정리는 실제 대상과 복구 여부를 확인한 뒤 수행하며 작업 캐시·필수 실행 파일을 임의 삭제하지 않는다.
- JSON 불러오기 후 콘크리트·철근·객체 귀속·수정 상태를 복원하고, 저장·내보내기와 왕복 확인한다. 캐시 조회·불러오기만으로 분석이나 수정을 자동 재개하지 않는다.
- 모델제작순서 안내는 처음 한 번만 표시하고 도면 입력 때 반복 표시하지 않는다. 보고서와 검사 기능은 저장 모델에서도 연결한다. 특정 모델의 느림은 불필요한 메시 분할·반복 계산·검사 캐시부터 확인한다.
- 수량은 콘크리트와 철근을 나눠 표시한다. 콘크리트는 `길이 × 폭 × 두께`, `사다리꼴 넓이 × 두께`, `삼각 단면 넓이 × 길이` 등 실제 형상에 맞는 치수 산식을 표시한다. 계산 완료 문구나 체적을 역산한 가짜 식으로 대체하지 않는다.
- 철근 미공제와 공제, 적용 가능한 LH 설비 공제·할증을 사용자가 선택할 수 있게 유지한다. 기준·판본·적용 범위·산식·타설량과 재료량을 함께 관리하며 특정 발주처 기준을 모든 공사에 강제하지 않는다.
- 철근 공제는 직경과 각 객체 내부의 실제 철근 구간을 사용한다. 여러 객체를 지나는 구간과 겹침은 중복 공제하지 않으며 외부 구간은 제외한다. 미확인 입력을 0으로 간주하거나 전체 중량을 객체별로 임의 비례 배분하지 않는다.
## 공통 코드·서비스·배포
- 운영 기준은 8097과 공통 소스다. 8098은 검증용이었던 페이지이며 별도 생성 규칙으로 분기하지 않는다. 현재 사용자가 요청하지 않으면 8098 서비스를 다시 만들거나 실행하지 않는다.
- 기본 8097에는 시공 미리보기를 숨기고 `/-1`에서 표시한다. 선택한 분리 타설 시나리오의 날개벽은 벽체 단계에 연결한다. 새로운 시공 순서는 근거 확인 후 사용자 선택을 반영한다.
- 로컬 주소 `10.13.36.102:8097`과 배포 주소 `http://10.14.12.22/box-sample/`, 배포 포트 5092의 역할을 구분한다. 배포 서버는 로컬 8097이나 VS Code 종료에 의존하지 않아야 한다.
- 배포 배치는 서버에서 다운로드 → 이미지 로드/빌드 → 실행 → 서비스 주소 확인을 연결한다. 기존 데이터·프록시 설정을 보존하고 서버 재부팅 후 자동 시작을 실제 환경에서 검증한다. 접근할 수 없는 서버까지 확인했다고 말하지 않는다.
- 지정된 사내 공유·AI 사용 승인은 해당 범위에 유지한다. 토큰·로그인 비밀을 코드·Git·보고서에 넣지 않는다. 페이지 AI의 모델 설정은 사용자의 최신 요청과 실제 지원 여부를 확인한다.
- Git 게시 요청 시 지정 브랜치 `Hyein`을 확인하고 요청 범위만 커밋한다. 관련 기능 설명은 README에 반영하며 사용자 작업을 덮어쓰지 않는다. push 후 원격 커밋을 확인한다.
## 실행과 검증
저장소 루트에서 실행한다. 지원 환경은 README의 Python 3.14 및 Node 환경을 따른다. `NODE_BINARY`는 실제 설치 경로로 지정하며 VS Code 버전 폴더의 오래된 경로를 고정하지 않는다.
```bash
python src/backend/serve.py # 기본 8097
node --check src/frontend/src/app.js # 프런트엔드 문법
python -m unittest discover -s src/backend -p 'test_frontend_asset_paths.py'
git diff --check
```
- 변경한 생성·표시·이동·수량 경로에 해당하는 기존 회귀 검사를 실행한다. 서버 시작 전 검사를 삭제하거나 우회하지 않는다. 원본 자료가 필요한 검사와 저장소만으로 실행 가능한 검사를 구분한다.
- 생성 코드가 바뀌면 현재 모델을 완료한 뒤 변경한 공통 코드로 기존 검증 도면과 새 입력 도면을 재생성하고 형상·방향·객체 목록·철근 상세·소속·본수·길이·체결·보고서를 대조한다. 도면의 유형·상세·객체 구성이 늘어나면 회귀 대상을 함께 확장한다. 캐시 표시나 일부 사이클 검사만으로 전수 재생성 통과를 선언하지 않는다.
- 브라우저에서 실제 대상 작업을 열어 Top 및 관련 뷰, 객체 필터, 캐시·JSON, 보고서, OBJ 결과를 변경 범위에 맞게 확인한다.
- 결과 보고에는 실제 검사 범위·실패·원인·수정·미완료 사항을 정확하게 적는다. 이미 알려준 조건을 다시 묻지 말고 승인된 작업을 이어가며, 필요한 선택은 좁은 항목으로 제시한다.
## Code Review Rules
- 원도면 불일치를 숨기기 위해 생성 기준·검사 게이트·수량·허용오차를 완화한 변경을 지적한다.
- 파일명·job ID·특정 모델 좌표·마크만으로 생성 분기하거나 이전 경로를 새 도면 입력으로 복사한 변경을 지적한다.
- 부분 수정으로 다른 객체를 삭제하거나 다른 occurrence의 철근을 이동·중복 집계하는 변경을 지적한다.
- 카메라·치수 이미지 문제를 모델 좌표 반전으로 해결하거나 실제 외곽을 바꾸는 변경을 지적한다.
- 검사되지 않은 수정본에 과거 승인 결과를 복사하거나 사용자 확정을 자동 검사 통과로 처리하는 변경을 지적한다.
- 캐시·JSON·보고서·내보내기 연결이 끊긴 변경과 운영·배포 서버를 개인 PC 실행에 종속시킨 변경을 지적한다.
파일 배치와 지침 적용 방식은 [OpenAI 공식 AGENTS.md 안내](https://learn.chatgpt.com/docs/agent-configuration/agents-md)를 따른다. 이 파일은 에이전트 작업 지침이며 런타임 검증을 대신하지 않는다.
@@ -0,0 +1,60 @@
# 공통 철근 판독 코드 재검증
## 후속 반영 상태
사용자 지시: 모델별 예외를 두지 않고 공통 코드 결과로 반영.
- 최초 보류한 슬래브 12개 행을 포함해 5개 작업의 슬래브 48개 행을 반영했다.
- 벽체 내측 수직근도 같은 도면 치수열 판독 코드로 5개 작업에서 재생성했다.
- dc0 W1은 블럭1 124본, 블럭2 116본으로 반영했다. 재료표 123본·115본은 원본값을 유지한다.
- `innerWallStationReviews` 및 실행 바인딩의 단부 제외값을 제거했다. 원본 백업에는 이력이 보존된다.
- 객체 치수창의 한글 명칭, 벽체 철근 소속 필터, 실제 철근 목록을 공통으로 수정했다.
- 날개벽 접합 철근은 소유 날개벽의 전체 연결 경로와 원본 반복 간격을 표시한다. 접합 관계를 안전하게 편집할 수 없는 치수는 조회 전용이다.
- 수량 차이를 없애기 위한 임의 생성·삭제나 원본 재료표 변경은 하지 않았다. 전체 도면 일치·제작 승인으로 간주하지 않는다.
아래는 최초 검사 당시의 보류 이력이다. 현재 반영 상태는 위 내용을 따른다.
## 반영 범위
현재 작업 중인 5개 모델의 원본 CAD를 같은 단면 판독 코드로 재검증했다.
작업 ID·고정 철근명·목표 수량으로 추가 철근을 지정하는 분기는 사용하지 않는다.
도면별 치수, 원본 엔티티, 물리 블럭 및 면 구분은 입력 근거이며 예외 규칙이 아니다.
| 작업 | 반영한 슬래브 행 | 보류한 슬래브 행 | 미해결 사항 |
| --- | ---: | ---: | --- |
| 03dd556bb61ab4adec0b670d | 9 | 3 | 블럭1–3 D2: 원본 판독 27 / 재료표 28 |
| 2120ce4675c6c0e6340aaac8 | 8 | 0 | 이번 슬래브 수량 검사 보류 없음 |
| c37ca61ba994edf2547dcd78 | 9 | 3 | 블럭1–3 D2: 원본 판독 26 / 재료표 28 |
| dc0a31e7e7d7fda5afb703bd | 6 | 2 | 블럭1–2 D2: 원본 판독 29 / 재료표 31 |
| f37b4289c97298fed715a88d | 4 | 4 | 블럭1 D1–4 보류; 블럭2 4개 행 반영 |
반영 행 수는 재검증된 행의 교체 수다. 모든 행의 형상이나 본수가 바뀌었다는 뜻은 아니다.
수량·소속·단면 내부 검사를 통과하지 못한 행은 기존 결과를 유지했다.
콘크리트, 사이클, 체결근, 연결근 및 이번 범위 밖 객체는 교체하지 않았다.
이 결과는 전체 모델 완료나 제작·설계 승인이 아니다.
## 공통 판독 수정
- 내측 주 배근열의 한쪽에서만 추가 기호를 찾던 조건을 수정했다.
- 다른 면의 치수로 소속이 확인된 기호를 추가 기호로 다시 배정하지 않는다.
- 저장된 W1 단부 제외 목록을 실행 경로에서 제거하고 직접 제외 요청도 거부한다.
- 원본 판독 본수와 재료표 본수가 다르면 슬래브 자동 교체를 보류한다.
## W1: 미해결 원본 대조
dc0 작업에서 예외 없이 치수열을 전개하면 블럭1 124본 / 재료표 123본,
블럭2 116본 / 재료표 115본이다. 이 결과는 게시하지 않았다.
블럭2 좌측벽체 원본의 단부 수직선 `301D`에는 W1 지시선 표시가 연결되어 있다.
인접 수직선 `301C` 및 치수선 `39A9`, `39AB`를 함께 확인했다.
따라서 기존 한 본 제외를 단순히 공통 규칙으로 바꾸는 것은 근거가 부족하다.
배근선·치수열·제작행의 귀속을 추가로 해결해야 하며, 간격 판독 수정 완료로 처리하지 않는다.
원본 SHA-256: `aa252d8f6fe029d52e025a5708bc7fe44fa52557233d439bb7a8c5f4c360e9df`.
## 검증
- 관련 단위 테스트 59개 통과.
- 다섯 모델 모두 상·하면 중복 경로 및 단면 배치 검사 재실행.
- 해시가 일치하는 원본 CAD 판독 장부에서 경로를 재생성했으며 과거 모델 경로를 입력으로 쓰지 않음.
- 저장 전 원본 작업 해시 및 CAD 해시 확인, 백업 후 부분 교체.
@@ -0,0 +1,45 @@
# 공통 생성 코드 점검 — 2026-09-11
## 판정
전체 완료가 아니다. 코드 회귀 오류와 일부 생성 차단 원인은 수정했지만, 원본 CAD 재생성에서 미연결 상세와 접촉 불일치가 남았다. 기존 화면 모델은 이번 점검 결과로 교체하지 않았다.
## 수정한 원인
- 체결근이 이전 저장 면철근을 참조하던 순서를 변경했다. 이번 실행의 면철근을 생성한 후 같은 실행의 체결근을 연결한다.
- 경사부 결속 실패가 독립적으로 판독된 일반부 사이클까지 누락시키지 않도록 분리했다. 불명확한 경사부를 임의 생성하지 않는다.
- 공통 배근 분기와 장부 보완에서 철근명 접두사로 역할·블럭·치수를 추정하는 경로를 제거했다. 도면 내 철근명은 원본 상세 행을 연결하는 식별자로만 사용할 수 있다.
- 콘크리트 생성 시 특정 철근명과 시트 전체의 숫자로 접속슬래브 두께·난간벽 높이를 덮어쓰던 보정을 제거했다. 콘크리트 원본에 연결된 높이 근거는 유지한다.
- 저장 함수와 검증 실패 경로의 입력 변경을 제거하고, 작업 JSON의 심볼릭 링크를 보존한다.
- 이미 생성된 항목과 미연결 장부 행의 대조는 원본 해시·CAD 엔티티·물리 블럭으로 수행한다.
- 벽체 체결근 상세 길이와 실제 접촉에 필요한 길이 차이를 기록한다. 경고를 지우기 위한 길이 늘림은 하지 않는다.
## 원본 CAD 재생성 결과
최종 수정 후 전체 로컬 테스트: 983건 실행, 실패 0, 오류 0, 미실행 9항목(보관 도면·작업 파일 또는 Node 환경 부재). 단위 테스트 통과와 아래 실제 모델의 전체 도면 일치는 별개의 판정이다.
저장된 연결선을 재사용하지 않고 현재 CAD 판독기를 실행했다. 이 검사는 비날개벽 생성기의 진단 실행이며, 전체 철근 완성이나 콘크리트 재생성 검증을 뜻하지 않는다.
| 작업 | 생성 그룹 | 생성 본수 | 기존 콘크리트 유지 | 저장 작업 파일 유지 |
| --- | ---: | ---: | --- | --- |
| dc0 | 106 | 5,217 | 확인 | 확인 |
| c37 | 71 | 5,820 | 확인 | 확인 |
| f37 | 98 | 4,936 | 확인 | 확인 |
| 2120 | 84 | 6,924 | 확인 | 확인 |
| 03dd | 89 | 5,582 | 확인 | 확인 |
dc0는 일반부 보존 수정 후 재실행했다. 나머지 네 결과는 그 수정 직전 공통 코드 실행이다. 이후 콘크리트 보정 제거는 이 비날개벽 재생성 도구의 호출 범위 밖이다. 따라서 다섯 모델 전체가 최종 코드로 완전 재생성·검증되었다고 간주하지 않는다.
외부 분석 서비스 전송과 작업 결과 게시 없이 실행했다. 원시 진단 결과:
- `/tmp/common-regeneration-v2-20260911.json`
- `/tmp/common-regeneration-v3-dc0-20260911.json`
## 남은 사항
- 일부 일반부·경사부 상세, 가변 브라켓 및 다웰 상세의 설치 결속이 미완료다. 생성 그룹 수가 전체 장부 충족을 뜻하지 않는다.
- f37 블럭1 벽체 체결근은 원본 상세 a=94mm와 현재 면철근 접촉에 필요한 114mm가 다르다. 2120은 원본 a=138mm와 접촉 필요 141mm가 다르다. 원본 치수를 다시 읽었지만, 면철근 위치까지 맞다는 결론이나 도면 오류라는 결론은 내리지 않았다.
- 03dd의 일부 벽체 접촉 검사도 통과하지 않았다. 저장 결과에 ID 없는 16항목이 있어 재생성 대조 도구가 중단되던 문제는 수정했지만, 해당 저장 항목을 임의로 지우지 않았다.
- 일부 브라켓의 도면 간격에 따른 수량과 장부 수량이 다르다. 임의 등분으로 수량을 맞추지 않았다.
다음 검증은 미연결 상세의 투영·치수·설치선 연결과 면철근 위치의 원본 대조다. 경고 삭제나 기존 결과 복사로 완료 처리해서는 안 된다.
@@ -0,0 +1,207 @@
# 도면에서 모델·보고서까지 — 전체 흐름과 ERD
현재 코드 확인 기준: 2026-09-11
**도면 입력 → 도면 정보 추출 → 객체·형상 생성 → 철근 배치 → 검사·보고서**
전체 그림과 아래 설명을 같은 **①~⑤ 순서**로 구성했습니다. 그림은 왼쪽에서 오른쪽으로, 각 단계 안에서는 위에서 아래로 읽습니다.
## 전체 그림
```mermaid
flowchart LR
subgraph S1["① 도면 입력"]
direction TB
A1["DWG · DXF"]
A2["원본 식별<br/>도면명 · SHA-256"]
A1 --> A2
end
subgraph S2["② 도면 정보 추출"]
direction TB
B1["문자 · 선분 · 치수"]
B2["평면 · 입면 · 단면<br/>상세 · 배근도 · 재료표"]
B1 --> B2
end
subgraph S3["③ 객체·형상 생성"]
direction TB
C1["객체 구분<br/>블럭 · 부재 · 좌우"]
C2["콘크리트 생성<br/>외곽 · 두께 · 표고"]
C1 --> C2
end
subgraph S4["④ 철근 배치"]
direction TB
D1["한 본 형상 + 설치기준<br/>시작 · 끝 · 간격"]
D2["객체에 귀속<br/>본별 3D 경로"]
D1 --> D2
end
subgraph S5["⑤ 검사·보고서"]
direction TB
E1["전체 콘크리트<br/>합집합 이탈 검사"]
E2["객체별 이미지<br/>위치 · 철근명"]
E3["PDF · 작업 JSON"]
E1 --> E2 --> E3
end
S1 --> S2 --> S3 --> S4 --> S5
classDef input fill:#edf4fc,stroke:#6689af,color:#17324d;
classDef evidence fill:#eef6f8,stroke:#679ba8,color:#173c46;
classDef concrete fill:#eef5ef,stroke:#739b7b,color:#23412b;
classDef rebar fill:#eef2ff,stroke:#7c8ac4,color:#2c3861;
classDef report fill:#fff3eb,stroke:#c69c79,color:#634127;
class A1,A2 input;
class B1,B2 evidence;
class C1,C2 concrete;
class D1,D2 rebar;
class E1,E2,E3 report;
```
| 순서 | 들어오는 정보 | 코드가 하는 일 | 다음 단계로 전달 |
|---|---|---|---|
| ① 입력 | DWG·DXF 원본 | 원본 식별, DWG 변환 경로 처리 | 읽을 수 있는 CAD 원본 |
| ② 추출 | CAD 원본 | 문자·벡터·치수·도면 뷰·재료표 판독 | 도면 근거 |
| ③ 형상 | 도면 근거 | 실제 객체 구분, 외곽·두께·표고 연결 | 콘크리트 객체 |
| ④ 철근 | 콘크리트 + 철근 근거 | 한 본 형상과 설치선 연결, 객체별 배치 | 실제 철근 경로 |
| ⑤ 보고서 | 콘크리트 + 철근 경로 | 구조물 이탈 검사, 객체별 이미지 구성 | 모델·보고서·저장 파일 |
작업의 기본 순서는 **도면 → 형상 확인 → 철근 → 결과 확인**입니다. 위 그림은 그 내부 처리를 다섯 단계로 펼친 것입니다.
## ① 도면 입력
DWG는 변환 경로를 거쳐 DXF로 읽습니다. 도면명·원본 내용 식별값은 원본 추적과 캐시 판단에 사용합니다.
| 정보 | 필드 예시 |
|---|---|
| 도면명 | `filename` |
| 원본 내용 식별 | `sha256` |
| 원본 접근 | `uploadId` |
**저장된 결과를 여는 것과 원본에서 다시 생성하는 것은 다른 동작**입니다.
## ② 도면 정보 추출
DXF 문자, BLOCK/INSERT, 벡터 좌표, 철근 표기와 재료표를 읽습니다. 초기 예비 치수와 최종 형상 근거를 구별합니다.
```mermaid
erDiagram
direction LR
DRAWING ||--o{ EVIDENCE : "도면 근거 추출"
```
| 구분 | 의미 | 주요 데이터 |
|---|---|---|
| DRAWING | 입력 도면 | 원본·도면명·내용 식별값 |
| EVIDENCE | 도면에서 읽은 근거 | 문자·치수·선분·뷰·재료표 |
도면 판독에는 로컬 CAD 추출·결정론적 연결 함수뿐 아니라 `call_model_plan`의 Codex 판독 경로도 존재합니다. 모든 정보를 순수 수식으로만 판독하는 구조는 아닙니다.
## ③ 객체 구분과 콘크리트 형상 생성
평면의 외곽·위치, 입면·종단의 높이·경사, 단면·상세의 두께를 실제 부재와 연결합니다. 같은 날개벽 이름이라도 블럭·좌우·시종점이 다르면 별도 객체입니다.
```mermaid
erDiagram
direction LR
EVIDENCE }o--o{ COMPONENT : "형상 근거 연결"
```
| 구분 | 의미 | 주요 데이터 |
|---|---|---|
| EVIDENCE | 여러 도면 뷰의 근거 | 외곽·치수·표고·접합 근거 |
| COMPONENT | 실제 콘크리트 부재 | `concrete_components[].id`, 종류, 외곽·표고 또는 메시 |
예: **날개벽 평면 + 입면 + 단면 → 블럭1 · 좌측 날개벽**
객체별로 생성하되 **접합부는 인접 객체와 함께** 확인합니다.
## ④ 객체별 철근 배치
콘크리트와 철근은 별도 데이터로 관리합니다. 철근 그룹에 상세·설치기준을 연결하고, 실제 철근 한 본마다 귀속 객체와 3D 경로를 저장합니다.
```mermaid
erDiagram
direction LR
COMPONENT }|--o{ REBAR_GROUP : "호스트 연결"
REBAR_GROUP ||--o{ REBAR_INSTANCE : "본별 배치"
```
| 도면 정보 | 배치에 사용하는 내용 |
|---|---|
| 철근 상세 | 한 본의 절곡 형상·구간 치수 |
| 배근도·치수선 | 시작·끝·간격·설치선 배열 |
| 재료표 | 직경·본수·길이 대조 |
| 데이터 | 연결 필드 |
|---|---|
| 콘크리트 객체 | `concrete_components[].id` |
| 철근 그룹 | `mark`, `host_component_ids`, `rebar_assembly_id` |
| 한 본의 경로와 귀속 | `instance_paths_m[i]` ↔ `occurrence_instance_ids[i]` |
| 도면 설치기준 | `source_station_contract` |
`REBAR_INSTANCE`는 별도 테이블이 아니라 그룹 안의 두 배열을 같은 인덱스로 연결한 개념입니다. 정착·접합 철근은 도면 근거에 따라 복수 객체에 걸칠 수 있습니다.
**객체별 공통 구조**이지 모든 부재를 동일한 함수 하나로 생성한다는 뜻은 아닙니다. 부재 종류별 생성 함수와 공통 연결·검사 규칙이 함께 사용됩니다.
부분 처리의 기준은 **실패한 항목만 건너뛰고 독립적으로 생성 가능한 항목을 계속 처리하며, 기존 결과를 보존하는 것**입니다. 관련 예외 분리 수정과 회귀테스트는 진행했으나, 이 문서 작성 시 실행 중인 형상 작업을 보호하기 위해 8097 서버 재시작 적용은 대기 중입니다.
## ⑤ 검사·보고서·저장
보고서는 객체별로 정리하지만, 이탈 판정 범위는 **전체 콘크리트 합집합**입니다. 다른 부재 내부에 정착된 구간을 원래 호스트 밖이라는 이유만으로 이탈 처리하지 않습니다.
```mermaid
erDiagram
direction LR
REPORT ||--o{ REPORT_ROW : "객체별 결과"
REPORT_ROW ||--o{ EXPOSURE_SEGMENT : "이탈 구간"
```
| 데이터 | 의미 | 표시·저장 내용 |
|---|---|---|
| REPORT | 현재 모델의 검사 스냅샷 | 입력 확인값·검사 버전·완료 여부 |
| REPORT_ROW | 객체·철근별 결과 | 위치·철근명·이미지 재구성 데이터 |
| EXPOSURE_SEGMENT | 검출된 구조물 밖 구간 | `airSegments` → 빨간 선·점 |
PDF는 이탈 항목을 **객체별 작은 이미지 + 위치·철근명**으로 구성합니다. 작업 JSON을 복원하면 저장된 모델·검사 좌표로 이미지를 다시 구성합니다.
### 작업 저장 구조
`JOB`은 전 단계의 도면·생성 결과를 묶는 작업 단위입니다. 작업 저장과 출력 흐름을 혼동하지 않도록 전체 그림의 교차 연결선에서는 생략했습니다.
| 저장 위치 | 담기는 내용 |
|---|---|
| `result` | 현재 생성 모델 |
| `partialResult` | 생성 중 누적된 부분 결과 |
| 작업 JSON의 `modelPlan` | 콘크리트·철근 모델 |
| 작업 JSON의 `modelReport` | 검사 결과·이탈 좌표·인쇄 구성 |
## 같은 순서로 보는 예시 — 블럭1 · 좌측 날개벽 WR2
| 순서 | 예시 |
|---|---|
| ① 입력 | 해당 날개벽이 있는 원본 도면 입력 |
| ② 추출 | 날개벽 평면·입면·단면 및 WR2 상세·배근도·재료표 판독 |
| ③ 형상 | 블럭1 · 좌측 날개벽 콘크리트 생성 |
| ④ 철근 | WR2 설치선과 한 본 형상을 해당 날개벽에 연결 |
| ⑤ 보고서 | 전체 콘크리트와 대조 → 이탈 선·점 → 객체별 이미지 출력 |
## 해석 범위와 한계
- 위 ERD는 실제 DB 테이블이 아니라 **현재 JSON·코드의 논리 관계**입니다.
- ERD에서 `||`는 하나, `o{`는 0개 이상, `}|`는 1개 이상입니다. 연결되지 않은 후보는 별도 보류 항목입니다.
- 객체별 공통 구조만으로 모델별 예외나 과거 보정 경로가 모두 제거됐다고 단정할 수 없습니다. 이 문서는 전체 하드코딩 감사 결과가 아닙니다.
- 파란색 표시는 승인 판정이 아닙니다. 사용자 확인 기록과 계산 결과는 분리합니다.
- `auditComplete`는 검사 계산 종료이지, 모든 철근의 도면 일치·시공 적합성 보증이 아닙니다.
- 현재 보고서는 원주 샘플 기반 검사이므로 미지원 형상과 샘플 사이 미세 노출의 한계가 있습니다.
## 코드 위치 — 위 순서와 동일
| 순서 | 코드 |
|---|---|
| ① 입력·변환 | `server.py` 업로드 처리, `dwg_conversion.py` |
| ② 문자·벡터·재료표 | `server.py`: `build_analysis`, `drawing_evidence_schema` |
| ③ 형상·단계 관리 | `server.py`: `call_model_plan`, `run_model_job` |
| ④ 객체별 누적 생성 | `progressive_rebar.py`: `stream_current_source` |
| ④ 그룹·본별 귀속 | `server.py`: `enforce_object_local_rebar_geometry_contract` |
| ④ 화면 표시 대상 | `rebar_review_visibility.js`: `isCurrentSourceDrawable` |
| ③·④ 화면 형상 | `model_kernel.js`, `app.js` |
| ⑤ 전체 합집합 검사 | `air_exposure.js`: `prepare`, `inspect`, `segment` |
| ⑤ 보고서·JSON | `model_report.js`, `app.js` |
Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

@@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1800" height="740" viewBox="0 0 1800 740" role="img" aria-labelledby="title desc">
<title id="title">도면에서 모델·보고서까지 전체 흐름</title><desc id="desc">왼쪽부터 도면 입력, 도면 정보 추출, 객체와 콘크리트 형상 생성, 객체별 철근 배치, 전체 콘크리트 합집합 이탈 검사와 보고서 출력 순서입니다.</desc>
<defs><marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto"><path d="M0 0 L9 5 L0 10" fill="none" stroke="#687b8e" stroke-width="1.5"/></marker></defs>
<rect width="1800" height="740" fill="#ffffff"/>
<g font-family="'Malgun Gothic','Noto Sans CJK KR',Arial,sans-serif">
<text x="60" y="82" font-size="38" font-weight="700" fill="#183046">도면에서 모델·보고서까지</text>
<text x="60" y="128" font-size="22" fill="#627588">도면 → 형상 확인 → 철근 → 결과 확인 | 왼쪽에서 오른쪽으로 읽습니다</text>
<rect x="60" y="190" width="300" height="354" rx="16" fill="#edf4fc" stroke="#6689af" stroke-width="2"/>
<text x="84" y="238" font-size="25" font-weight="700" fill="#183046">① 도면 입력</text>
<line x1="84" y1="262" x2="336" y2="262" stroke="#6689af" opacity=".5"/>
<circle cx="88" cy="309" r="4" fill="#6689af"/><text x="104" y="317" font-size="19" fill="#263e52">DWG · DXF</text><circle cx="88" cy="371" r="4" fill="#6689af"/><text x="104" y="379" font-size="19" fill="#263e52">원본 식별</text><circle cx="88" cy="433" r="4" fill="#6689af"/><text x="104" y="441" font-size="19" fill="#263e52">도면명 · SHA-256</text><rect x="78" y="478" width="264" height="44" rx="8" fill="#ffffff" opacity=".8"/><text x="210" y="506" text-anchor="middle" font-size="18" fill="#40566c">원본 CAD</text><line x1="367" y1="362" x2="392" y2="362" stroke="#687b8e" stroke-width="2.5" marker-end="url(#arrow)"/><rect x="402" y="190" width="300" height="354" rx="16" fill="#eef6f8" stroke="#679ba8" stroke-width="2"/>
<text x="426" y="238" font-size="25" font-weight="700" fill="#183046">② 도면 정보 추출</text>
<line x1="426" y1="262" x2="678" y2="262" stroke="#679ba8" opacity=".5"/>
<circle cx="430" cy="309" r="4" fill="#679ba8"/><text x="446" y="317" font-size="19" fill="#263e52">문자 · 선분 · 치수</text><circle cx="430" cy="371" r="4" fill="#679ba8"/><text x="446" y="379" font-size="19" fill="#263e52">평면 · 입면 · 단면</text><circle cx="430" cy="433" r="4" fill="#679ba8"/><text x="446" y="441" font-size="19" fill="#263e52">상세 · 배근도 · 재료표</text><rect x="420" y="478" width="264" height="44" rx="8" fill="#ffffff" opacity=".8"/><text x="552" y="506" text-anchor="middle" font-size="18" fill="#40566c">도면 근거</text><line x1="709" y1="362" x2="734" y2="362" stroke="#687b8e" stroke-width="2.5" marker-end="url(#arrow)"/><rect x="744" y="190" width="300" height="354" rx="16" fill="#eef5ef" stroke="#739b7b" stroke-width="2"/>
<text x="768" y="238" font-size="25" font-weight="700" fill="#183046">③ 객체·형상 생성</text>
<line x1="768" y1="262" x2="1020" y2="262" stroke="#739b7b" opacity=".5"/>
<circle cx="772" cy="309" r="4" fill="#739b7b"/><text x="788" y="317" font-size="19" fill="#263e52">블럭 · 부재 · 좌우 구분</text><circle cx="772" cy="371" r="4" fill="#739b7b"/><text x="788" y="379" font-size="19" fill="#263e52">외곽 · 두께 · 표고 연결</text><circle cx="772" cy="433" r="4" fill="#739b7b"/><text x="788" y="441" font-size="19" fill="#263e52">콘크리트 객체 생성</text><rect x="762" y="478" width="264" height="44" rx="8" fill="#ffffff" opacity=".8"/><text x="894" y="506" text-anchor="middle" font-size="18" fill="#40566c">concrete_components</text><line x1="1051" y1="362" x2="1076" y2="362" stroke="#687b8e" stroke-width="2.5" marker-end="url(#arrow)"/><rect x="1086" y="190" width="300" height="354" rx="16" fill="#eef2ff" stroke="#7c8ac4" stroke-width="2"/>
<text x="1110" y="238" font-size="25" font-weight="700" fill="#183046">④ 철근 배치</text>
<line x1="1110" y1="262" x2="1362" y2="262" stroke="#7c8ac4" opacity=".5"/>
<circle cx="1114" cy="309" r="4" fill="#7c8ac4"/><text x="1130" y="317" font-size="19" fill="#263e52">한 본 형상 + 설치기준</text><circle cx="1114" cy="371" r="4" fill="#7c8ac4"/><text x="1130" y="379" font-size="19" fill="#263e52">시작 · 끝 · 간격 연결</text><circle cx="1114" cy="433" r="4" fill="#7c8ac4"/><text x="1130" y="441" font-size="19" fill="#263e52">객체 귀속 · 본별 3D 경로</text><rect x="1104" y="478" width="264" height="44" rx="8" fill="#ffffff" opacity=".8"/><text x="1236" y="506" text-anchor="middle" font-size="18" fill="#40566c">rebar_groups</text><line x1="1393" y1="362" x2="1418" y2="362" stroke="#687b8e" stroke-width="2.5" marker-end="url(#arrow)"/><rect x="1428" y="190" width="300" height="354" rx="16" fill="#fff3eb" stroke="#c69c79" stroke-width="2"/>
<text x="1452" y="238" font-size="25" font-weight="700" fill="#183046">⑤ 검사·보고서</text>
<line x1="1452" y1="262" x2="1704" y2="262" stroke="#c69c79" opacity=".5"/>
<circle cx="1456" cy="309" r="4" fill="#c69c79"/><text x="1472" y="317" font-size="17" fill="#263e52">전체 콘크리트 합집합 검사</text><circle cx="1456" cy="371" r="4" fill="#c69c79"/><text x="1472" y="379" font-size="17" fill="#263e52">객체별 이미지 · 위치 · 철근명</text><circle cx="1456" cy="433" r="4" fill="#c69c79"/><text x="1472" y="441" font-size="17" fill="#263e52">PDF · 작업 JSON</text><rect x="1446" y="478" width="264" height="44" rx="8" fill="#ffffff" opacity=".8"/><text x="1578" y="506" text-anchor="middle" font-size="18" fill="#40566c">modelReport</text><line x1="60" y1="591" x2="1728" y2="591" stroke="#dbe3eb"/>
<text x="60" y="634" font-size="21" fill="#354c61">객체별 연결: 콘크리트 객체 ↔ 철근 그룹 ↔ 철근 한 본</text>
<text x="60" y="674" font-size="18" fill="#64788a">검사 범위는 전체 콘크리트 합집합입니다. 검사 계산 완료는 시공 승인을 뜻하지 않습니다.</text>
<text x="1728" y="704" text-anchor="end" font-size="15" fill="#8a9aa8">DRAWING TO MODEL · 2026-09-11</text>
</g></svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

@@ -0,0 +1,17 @@
# DWG deployment runtime
The Linux/amd64 image includes LibreDWG **0.11.3876**, the same decoder
version/package as the local host. Geometry/rebar generation code is unchanged.
The build downloads a fixed conda-forge artifact and verifies its SHA-256 before
installing only dwg2dxf, its shared library, GPL license and source metadata.
The runtime does not depend on a host PC path or install Conda/Python bindings.
- License: GPL-3.0-or-later, installed at `/opt/libredwg/licenses/COPYING`.
- Corresponding upstream source: https://github.com/LibreDWG/libredwg/releases/download/0.11.3876/libredwg-0.11.3876.tar.gz
- Source SHA-256: `ba65e77adb3099bec9f8f6c2ec2c6d97457a148be0a485d7fd3c00679f332e52`.
- Package recipe and source references: `/opt/libredwg/licenses/package-source.yaml`.
Run the existing private `deploy-server.bat` on the deployment server again.
It fast-forwards the clean clone and rebuilds the image. Existing named model
and AI-auth volumes remain in place. This is not automatic deployment on push.
DWG conversion success is not full drawing/model approval.
@@ -0,0 +1,31 @@
# 보고서의 철근 수량·형상·길이 정리
이미 반영된 보고서 수량 집계와 철근 형상 상세 기능을 정리한 이슈입니다.
## 수량 보고서
- 블럭별 재료표와 날개벽·접속슬래브 재료표를 구분하고 총계를 별도로 제공합니다.
- 객체별 수량뿐 아니라 철근명별 총괄을 확인할 수 있습니다.
- 철근 지름, 수량, 한 본 길이, 총길이를 정리합니다.
- 실제 배치 객체를 기준으로 집계하며, 공유 접합부 철근을 중복 집계하지 않습니다.
- 화면과 보고서에서 공통 객체명과 동일한 집계 형식을 사용합니다.
## 철근 형상 및 길이
- 수량과 함께 철근 형상 상세 및 도면 치수를 표시합니다.
- 같은 형상·같은 치수는 상세 그림을 한 번만 표시합니다. 치수가 다른 형상은 구분하며, 그림을 묶어도 실제 수량은 유지됩니다.
- 도면 상세의 a/b/c 등 치수, 이음 j, 제작 길이 L을 구분합니다.
- 이음 길이는 제작 길이와 총길이에 한 번만 반영합니다.
- 도면 치수는 정수 mm로 표시합니다.
- 굽힘이 있는 철근은 원길이와 곡선길이를 구분하고 차이의 의미를 주석으로 안내합니다. 직선에는 불필요한 곡선길이 괄호를 표시하지 않습니다.
## 확인 및 관련 코드
객체별 귀속, 공유 철근 집계, 철근명 총괄, 형상·치수 구분, 이음·굽힘 길이, 상세 중복 제거 및 JSON 재불러오기 회귀 테스트를 통과했습니다.
이 이슈는 보고서에 반영된 기능을 설명합니다. 모델 수량과 원본 도면 간 대조 결과 및 잔여 불일치는 `docs/COMMON_REBAR_AUDIT_20260915.md`에서 별도로 관리합니다.
- 반영 커밋: `ebf251f`
- `src/frontend/src/model_report.js`
- `src/frontend/model-report.html`
- `src/frontend/src/test_quantity_report.js`
@@ -0,0 +1,30 @@
# 객체별 철근 간격·피복 숫자 변경을 통한 모델 수정
이미 반영된 객체별 철근 치수 조회·편집 기능을 정리한 이슈입니다.
## 사용 방법
1. 객체별 피복·간격 창을 엽니다.
2. 수정할 객체와 철근을 선택합니다.
3. 도면처럼 표시된 피복, 단부 간격, 반복 간격 숫자를 변경합니다.
4. 적용하면 선택 객체의 실제 철근 배치가 변경됩니다.
## 반영 내용
- 객체에 속한 철근을 선택해 피복과 간격을 조회하고, 편집 가능한 숫자를 변경해 모델에 적용합니다.
- 반복 간격은 `개수 @ 간격 = 합계`로 묶어서 표시합니다.
- 총길이와 반복 개수를 유지하면서 잔여 길이를 계산합니다. 가장 오른쪽 숫자를 바꾸면 왼쪽 끝이, 그 외 숫자를 바꾸면 오른쪽 끝이 자동 계산됩니다.
- 숫자 표시만 바꾸는 것이 아니라 실제 철근 좌표를 변경하며, 다른 객체의 배치는 보존합니다.
- 초기화로 편집 시작 기준으로 복원할 수 있습니다.
- 객체명은 한글로 통일하고 철근 목록은 번호순으로 표시합니다.
- 헌치 등 불필요한 편집 객체를 제외하고 철근 배치가 보이는 뷰를 제공합니다. 접속슬래브는 Top으로 확인합니다.
- 모델별 별도 화면 코드를 두지 않고 공통 편집 코드를 사용합니다.
## 확인 및 관련 코드
피복·간격 변경, 양끝 자동 계산, 객체별 배치 보존, 도면 정수 치수 및 뷰 선택 회귀 테스트를 통과했습니다. 편집이 지원되지 않는 항목은 비활성 상태로 구분됩니다.
- 반영 커밋: `ebf251f`
- `src/frontend/src/app.js`
- `src/frontend/src/model_kernel.js`
- `src/frontend/src/test_placement_editor.js`
@@ -0,0 +1,220 @@
# 객체별 역할 및 모델링 적용 기준
콘크리트 객체를 상위 구분으로 하고, 해당 객체의 하위 구성과 철근을 함께 정리합니다. **사이클 철근과 본체 체결근은 본체에, 날개벽의 수직근·연결근·체결근은 날개벽에 포함**합니다.
치수는 고정 수치가 아니라 해당 객체의 폭·높이·설치면·접합 관계를 기준으로 결정합니다.
## 1. 본체
**객체의 역할:** 상·하부 슬래브와 벽체로 구조물의 주 단면을 구성합니다.
<table width="100%" cellpadding="10" cellspacing="0" style="width:100%; table-layout:fixed; border-collapse:collapse;">
<colgroup>
<col width="14%" style="width:14%;">
<col width="22%" style="width:22%;">
<col width="34%" style="width:34%;">
<col width="30%" style="width:30%;">
</colgroup>
<thead>
<tr>
<th width="14%" align="left" valign="top" style="width:14%; padding:10px 12px; border:1px solid #b8c2cc;">하위 구성</th>
<th width="22%" align="left" valign="top" style="width:22%; padding:10px 12px; border:1px solid #b8c2cc;">역할</th>
<th width="34%" align="left" valign="top" style="width:34%; padding:10px 12px; border:1px solid #b8c2cc;">모델링 적용 기준</th>
<th width="30%" align="left" valign="top" style="width:30%; padding:10px 12px; border:1px solid #b8c2cc;">적용 시 구분 사항</th>
</tr>
</thead>
<tbody>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>전체 구성</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">상·하부 슬래브와 벽체로 구조물의 주 단면을 구성</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 도면의 형상과 구간 구분에 따라 일반부·경사부를 나누고, 각 철근을 해당 구간과 부재에 연결합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 구간 길이·경계·부재 수·좌표는 도면마다 결정합니다.<br>• 기존 모델의 구간이나 좌표를 고정 적용하지 않습니다.</td>
</tr>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>상·하부 슬래브</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">본체의 상부·하부 판형 부재를 구성하고 벽체와 연결</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 도면에서 대응하는 상면·하면 철근은 공통 설치 기준선으로 연결하여, Top에서 일치해야 하는 배치선이 임의로 어긋나지 않도록 합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 시작·끝 위치, 간격, 단부·헌치 주변 추가 철근은 배근도·치수선·단면도에 따라 결정합니다.<br>• 동일 수량이나 동일 간격을 모든 슬래브에 강제하지 않습니다.</td>
</tr>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>벽체</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">본체의 측면을 구성하고 상부·하부 슬래브를 연결</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 철근의 설치면과 역할을 기준으로 벽체 배근을 구분합니다.<br>• 같은 철근명이 슬래브와 벽체에 등장하더라도 실제 설치 대상에 각각 연결합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 배근 시작 높이·단부 범위·경사는 해당 도면에서 결정합니다.<br>• 벽체 최상단을 고정 시작점으로 사용하지 않습니다.</td>
</tr>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>사이클 철근</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">본체 단면의 관련 철근을 하나의 반복 배근 단위로 구성</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 도면에서 함께 반복되는 철근을 조립 단위로 연결하고, 관련 철근이 해당 단위의 설치 기준을 공유하도록 합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 반복 범위·간격·본수·일반부와 경사부의 구분은 도면마다 결정합니다.<br>• 개별 철근을 독립적으로 중앙 정렬하거나 재분배하지 않습니다.</td>
</tr>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>체결근</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">슬래브·벽체의 대응 철근을 감싸고 서로 연결</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 콘크리트 안의 임의 위치가 아니라, <strong>대상 철근을 감싸고 묶는 관계</strong>를 기준으로 배치합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 슬래브의 상·하면 철근 또는 벽체의 대응 양면 철근 위치와 상세 형상에 따라 방향·정착 위치를 결정합니다.<br>• 철근명에 특정 방향을 고정하지 않습니다.</td>
</tr>
</tbody>
</table>
---
## 2. 날개벽
**객체의 역할:** 본체 단부에서 외측으로 이어지는 벽체와 본체 접합부를 구성합니다.
<table width="100%" cellpadding="10" cellspacing="0" style="width:100%; table-layout:fixed; border-collapse:collapse;">
<colgroup>
<col width="14%" style="width:14%;">
<col width="22%" style="width:22%;">
<col width="34%" style="width:34%;">
<col width="30%" style="width:30%;">
</colgroup>
<thead>
<tr>
<th width="14%" align="left" valign="top" style="width:14%; padding:10px 12px; border:1px solid #b8c2cc;">하위 구성</th>
<th width="22%" align="left" valign="top" style="width:22%; padding:10px 12px; border:1px solid #b8c2cc;">역할</th>
<th width="34%" align="left" valign="top" style="width:34%; padding:10px 12px; border:1px solid #b8c2cc;">모델링 적용 기준</th>
<th width="30%" align="left" valign="top" style="width:30%; padding:10px 12px; border:1px solid #b8c2cc;">적용 시 구분 사항</th>
</tr>
</thead>
<tbody>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>전체 구성</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">본체 단부에서 외측으로 이어지는 벽체를 구성</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 위치와 본체 접합 관계로 물리 객체를 구분하고, 표시 명칭은 <strong>블럭 번호 · 좌측/우측 날개벽</strong> 형식으로 구성합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 블럭 번호·발생 수·좌우 구분은 해당 모델의 객체 정보로 결정합니다.<br>• 표시 이름 자체를 형상이나 배치의 판정 근거로 사용하지 않습니다.</td>
</tr>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>헌치</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">날개벽과 본체 벽체 사이의 접합부를 구성</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• <strong>날개벽과 본체 벽체를 연결하는 접합부 객체</strong>로 정의하고, 실제 날개벽 접합 형상에 맞춰 구성합니다.<br>• 높이는 <strong>날개벽과 벽체가 만나는 부분</strong>을 기준으로 결정합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 고정하는 것은 접합 관계이며 길이·높이·좌표가 아닙니다.<br>• 본체 벽체 길이를 그대로 적용하거나 기존 모델의 헌치 치수를 복사하지 않습니다.</td>
</tr>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>수직근</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">날개벽 전면·배면의 수직 배근과 상단 정착부를 구성</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 상단 정착 구간은 <strong>날개벽의 폭</strong>을 기준으로 구성합니다.<br>• 대응하는 전면·배면 철근에 임의의 길이 차이나 위치 차이를 두지 않습니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 실제 객체의 폭과 도면의 피복·정착 상세를 연결하여 적용합니다.<br>• 특정 도면에서 확인한 길이를 공통 고정값으로 사용하지 않습니다.</td>
</tr>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>연결근·각도 처리</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">날개벽과 인접 부재의 철근 연결·정착 관계를 구성</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 기본 배치는 도면 상세각을 적용하고, 각도반영 대상은 실제 날개벽 접합 각도에 따른 배치를 별도 선택 상태로 제공합니다.<br>• OBJ도 선택 상태를 따릅니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 적용 대상은 철근명이 아니라 연결 역할과 상세 형상으로 구분합니다.<br>• 각도와 방향은 해당 객체의 접합 관계에 따라 결정하며 특정 모델의 방향을 고정 적용하지 않습니다.</td>
</tr>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>체결근</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">날개벽 전면·배면 철근망을 서로 연결</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 엇갈림 배치 대상 철근은 해당 철근망에 연결하여 배치합니다.<br>• 도면에서 시작 줄을 지정하지 않은 경우에는 일관된 시작 줄 처리 규칙을 적용합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 엇갈림 적용 여부·간격·범위는 해당 배근 조건을 확인합니다.<br>• 공통 처리 대상은 미지정 시작 줄의 선택 방식이며, 특정 철근명이나 좌표가 아닙니다.</td>
</tr>
</tbody>
</table>
\* **날개벽 · 헌치 범위와 높이:** 별도 치수가 없는 부분은 **날개벽과 본체 벽체가 실제로 만나는 접합부**를 기준으로 구성했습니다. 본체 벽체 전체 길이를 그대로 따르지 않고, 날개벽과의 접합 범위 및 만나는 높이에 맞춥니다. 다른 모델의 헌치 치수를 고정 적용하지 않습니다.
\* **날개벽 · 체결근의 엇갈림 시작 줄:** 엇갈림 배치는 유지하되, 시작 줄이 지정되지 않은 경우에는 모든 도면에서 일관된 선택 방식을 적용하도록 했습니다. 이는 시작 줄 선택에 대한 보완이며, 철근 간격·수량·배치 범위를 임의로 바꾸는 기준은 아닙니다.
---
## 3. 난간벽
**객체의 역할:** 본체 상부 단부의 난간 벽체를 구성합니다.
<table width="100%" cellpadding="10" cellspacing="0" style="width:100%; table-layout:fixed; border-collapse:collapse;">
<colgroup>
<col width="14%" style="width:14%;">
<col width="22%" style="width:22%;">
<col width="34%" style="width:34%;">
<col width="30%" style="width:30%;">
</colgroup>
<thead>
<tr>
<th width="14%" align="left" valign="top" style="width:14%; padding:10px 12px; border:1px solid #b8c2cc;">하위 구성</th>
<th width="22%" align="left" valign="top" style="width:22%; padding:10px 12px; border:1px solid #b8c2cc;">역할</th>
<th width="34%" align="left" valign="top" style="width:34%; padding:10px 12px; border:1px solid #b8c2cc;">모델링 적용 기준</th>
<th width="30%" align="left" valign="top" style="width:30%; padding:10px 12px; border:1px solid #b8c2cc;">적용 시 구분 사항</th>
</tr>
</thead>
<tbody>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>철근 배치</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">본체 상부 단부의 난간 벽체를 구성</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 반복 간격이 표시된 경우에는 도면 간격을 적용합니다.<br>• 간격을 확정하지 못하고 수량 기준 배치가 허용된 경우에는 본수와 해당 객체의 배치 가능 길이로 간격을 산정합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 적용 여부는 철근명이 아니라 간격 정보의 유무와 배치 조건으로 결정합니다.<br>• 산정한 간격은 <strong>수량 기준 등간격 적용</strong>으로 기록하고 도면 명시값과 구분합니다.</td>
</tr>
</tbody>
</table>
\* **난간벽 · 철근 간격:** 반복 간격이 표시되지 않은 철근은 재료표 본수와 양단 피복을 고려한 배치 가능 길이를 기준으로 **등간격 배치**했습니다. 계산한 간격은 도면 명시값이 아니므로 보고서에 ‘수량 기준 등간격 적용’으로 남깁니다.
---
## 4. 브라켓
**객체의 역할:** 접속슬래브를 지지하는 받침부를 구성합니다.
<table width="100%" cellpadding="10" cellspacing="0" style="width:100%; table-layout:fixed; border-collapse:collapse;">
<colgroup>
<col width="14%" style="width:14%;">
<col width="22%" style="width:22%;">
<col width="34%" style="width:34%;">
<col width="30%" style="width:30%;">
</colgroup>
<thead>
<tr>
<th width="14%" align="left" valign="top" style="width:14%; padding:10px 12px; border:1px solid #b8c2cc;">하위 구성</th>
<th width="22%" align="left" valign="top" style="width:22%; padding:10px 12px; border:1px solid #b8c2cc;">역할</th>
<th width="34%" align="left" valign="top" style="width:34%; padding:10px 12px; border:1px solid #b8c2cc;">모델링 적용 기준</th>
<th width="30%" align="left" valign="top" style="width:30%; padding:10px 12px; border:1px solid #b8c2cc;">적용 시 구분 사항</th>
</tr>
</thead>
<tbody>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>형상·철근 배치</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">접속슬래브를 지지하는 받침부를 구성</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 해당 브라켓의 사각과 배치 방향에 철근을 연결합니다.<br>• 피복은 객체 간 동일 적용 기준을 사용하되, 양단 치수가 명시된 경우 해당 도면 치수를 우선합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 사각·피복 수치·양단 여유를 고정 상수로 사용하지 않습니다.<br>• 양단 미표기 시 동일 피복 기준을 적용하며, 횡단면 치수를 길이방향 양단 치수로 자동 전용하지 않습니다.</td>
</tr>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>접속슬래브 연결부·다웰바</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">접합 틈을 사이에 둔 브라켓과 접속슬래브를 연결</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 도면에 의도된 접합 틈을 통과하는 구간과 구조물 외부로 잘못 돌출된 구간을 구분합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 제외 여부는 철근명이나 일정 틈 크기로 고정하지 않습니다.<br>• 해당 상세의 연결 관계와 실제 통과 위치를 확인하며, 모든 틈을 일괄적으로 이탈 검사에서 제외하지 않습니다.</td>
</tr>
</tbody>
</table>
\* **브라켓 · 피복과 양단 여유:** 브라켓 객체 간에는 동일한 피복 기준을 적용하고, 길이방향 양단 치수가 별도로 없으면 동일 피복 기준을 적용하도록 했습니다. 양단 치수가 명시되어 있으면 해당 치수를 우선하며, 횡단면의 치수를 길이방향 여유로 그대로 옮기지 않습니다.
---
## 5. 접속슬래브
**객체의 역할:** 본체와 외부 구간을 연결하며 브라켓에 지지됩니다.
<table width="100%" cellpadding="10" cellspacing="0" style="width:100%; table-layout:fixed; border-collapse:collapse;">
<colgroup>
<col width="14%" style="width:14%;">
<col width="22%" style="width:22%;">
<col width="34%" style="width:34%;">
<col width="30%" style="width:30%;">
</colgroup>
<thead>
<tr>
<th width="14%" align="left" valign="top" style="width:14%; padding:10px 12px; border:1px solid #b8c2cc;">하위 구성</th>
<th width="22%" align="left" valign="top" style="width:22%; padding:10px 12px; border:1px solid #b8c2cc;">역할</th>
<th width="34%" align="left" valign="top" style="width:34%; padding:10px 12px; border:1px solid #b8c2cc;">모델링 적용 기준</th>
<th width="30%" align="left" valign="top" style="width:30%; padding:10px 12px; border:1px solid #b8c2cc;">적용 시 구분 사항</th>
</tr>
</thead>
<tbody>
<tr>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;"><strong>형상·받침 관계</strong></td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">본체와 외부 구간을 연결하며 브라켓에 지지되는 슬래브를 구성</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 접속슬래브의 두께·경사와 브라켓의 받침 관계를 연결합니다.<br>• 관련 치수가 바뀌면 접합된 객체의 받침 높이도 함께 확인합니다.</td>
<td valign="top" style="padding:10px 12px; border:1px solid #b8c2cc; line-height:1.65; overflow-wrap:anywhere;">• 두께·경사·받침 높이는 해당 도면과 접합 형상으로 결정합니다.<br>• 상세 길이와 설치선 길이의 차이는 임의 보정하지 않고, 검토용 표시 여부와 함께 구분합니다.</td>
</tr>
</tbody>
</table>
@@ -0,0 +1,46 @@
# 객체별 형상·철근 처리 계약
## 공통 순서
원본 도면 → 물리 객체 식별 → 콘크리트 형상 확정 → 객체별 배근 근거 판독 → 철근 배치 → 검증된 부분 표시.
- 기존 모델의 철근 좌표는 회귀 비교 대상이지 생성 입력이 아니다.
- 원본의 도면 영역, 치수 문자, 치수선, 리더, 철근상세, 재료표를 함께 기록한다.
- 생성기는 작업 ID나 파일명에 따라 분기하지 않는다.
## 명칭과 물리 객체
브라켓의 저장 형식은 `bracket` 하나다. 예전 `approach_bracket` 값은 입력/저장 경계에서 단방향 변환한다. 형상·철근 생성기가 두 종류로 취급하지 않는다. 변환은 ID, 좌표, 메시, 철근 경로를 변경하지 않는다.
블럭, 좌·우, 시·종점은 물리 occurrence를 식별하는 정보다. 동일 마크가 여러 객체에 있어도 하나로 합치지 않는다. 인식하지 못한 종류와 소유 객체는 장부에 명시하며 다른 객체에 임의 귀속하지 않는다.
## 형상과 철근 분리
`memberModel.objects[물리 ID]`에 두 항목을 분리한다.
- `geometry`: 원본 콘크리트 객체 ID와 사용한 뷰. 좌표의 사본을 별도로 만들어 원본과 어긋나게 하지 않는다.
- `reinforcement`: 해당 객체에 속한 그룹 ID와 그룹 내 실제 경로 인덱스. 그룹 마크가 아니라 `occurrence_instance_ids`로 연결한다.
이 장부는 검증 승인서가 아니다. 제작 상세, 피복, 길이, 수량 및 접합 검사는 따로 실행한다.
## 벽체와 슬래브 독립
슬래브 평면이 경사라는 이유로 벽체 배치를 중단하지 않는다. 벽체 자체의 형상에서 양 면의 설치 범위를 구하고, 벽체도의 좌·우 객체 제목과 양단 치수를 판독한다.
내·외측이 나뉜 벽체도는 실제 공유 분할선을 사용한다. 이를 도면의 기하학적 중점이라고 가정하지 않는다. 반대 면에 표시한 양단 치수는 동일 벽체의 투영 범위와 양 치수 지시점의 동일 변위를 확인한 뒤 연결하며 인쇄된 치수값은 바꾸지 않는다.
철근 끝점과 치수 지시점의 그래픽 대응에는 해당 행의 직경을 사용한다. 대응 잔차를 근거에 기록하고, 실제 배치는 그래픽 끝점이 아니라 도면의 명시 치수로 한다. 단면 위치·수량, 3D 내부 검사, 도면 길이 범위, 실제 그려진 반쪽 벽체의 구배를 다시 검사한다.
## 회귀와 게시
### 수치·메시 표현 차이로 인한 중복/오판 방지
- 치수로 계산한 CAD 축척은 일반부와 경사부 모두 같은 소수점 정밀도로 정규화한다. 부동소수점 오차로 같은 도면 뷰를 두 번 세지 않는다. 다른 도면 영역이나 다른 외곽선은 합치지 않는다.
- 명시된 정점·면 메시가 있으면 표고 조회와 내부 판정 모두 그 메시를 기준으로 한다. 오래된 footprint 표고 배열을 메시보다 우선하지 않는다.
- 전단키 등 오목한 단면에는 볼록 다면체의 반공간 검사를 적용하지 않는다. 실제 면의 경계로 삼각분할하고 내부/빈 공간을 구분한다.
- 철근 경로의 객체 귀속은 몇 개의 고정 샘플만으로 결정하지 않는다. 실제 단면 경계면에서 경로를 분할해 좁은 접합부도 검사한다. 경계면 연장선은 검사 지점만 추가하며 콘크리트나 정착 관계를 만들어내지 않는다.
- 메시 기반 수정은 콘크리트 정점을 이동하지 않는다. 철근의 기존 표고를 교체할 때에는 원본 경로·직경·평면 위치·본수와 새 호스트 내부 검사 결과를 별도로 확인하고 이전 파일을 보관한다.
재생성에는 저장된 철근과 이전 설치선 좌표를 입력하지 않는다. 기존 모델과 비교할 때 좌표·직경·본수·소유 객체를 확인한다. 이름 스키마 변환과 형상 변경을 구분해서 기록한다.
부분 게시 시 기존 그룹은 유지하고 검사를 통과한 새 그룹만 추가한다. 제작 이음 분할 등이 미확정이면 검토용 상태를 유지한다. 기존 모델을 재현하지 못한 항목이 있으면 전체 회귀 통과라고 보고하지 않는다.
@@ -0,0 +1,702 @@
{
"policy": "attachment_first; 1000mm repeat / 500mm stagger unchanged; skew longer side gets more",
"scope": "six existing models, explicitly authorized R3/R4 body ties",
"saved_coordinates_changed": false,
"gitea_uploaded": false,
"engineering_approval": false,
"groups": 30,
"bars": 1684,
"tests": 63,
"models": [
{
"job": "03dd556bb61ab4adec0b670d",
"rows": [
{
"block": "BLOCK1",
"mark": "R4",
"count": 54,
"end_margins_mm": [
[
794.892,
723.443
],
[
698.112,
629.114
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 54,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R3",
"count": 54,
"end_margins_mm": [
[
574.416,
878.211
],
[
678.193,
628.211
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 54,
"bend_warnings": 0
}
},
{
"block": "BLOCK2",
"mark": "R4",
"count": 78,
"end_margins_mm": [
[
205.469,
205.469
],
[
205.469,
205.469
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 78,
"bend_warnings": 0
}
},
{
"block": "BLOCK2",
"mark": "R3",
"count": 78,
"end_margins_mm": [
[
204.574,
204.574
],
[
204.574,
204.574
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 78,
"bend_warnings": 0
}
},
{
"block": "BLOCK3",
"mark": "R4",
"count": 24,
"end_margins_mm": [
[
551.035,
575.103
],
[
551.035,
782.301
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 24,
"bend_warnings": 0
}
},
{
"block": "BLOCK3",
"mark": "R3",
"count": 24,
"end_margins_mm": [
[
550.133,
594.97
],
[
285.712,
964.746
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 24,
"bend_warnings": 0
}
}
]
},
{
"job": "dc0a31e7e7d7fda5afb703bd",
"rows": [
{
"block": "BLOCK2",
"mark": "R4",
"count": 52,
"end_margins_mm": [
[
520.595,
475.14
],
[
520.595,
647.275
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 52,
"bend_warnings": 0
}
},
{
"block": "BLOCK2",
"mark": "R3",
"count": 52,
"end_margins_mm": [
[
523.455,
492.519
],
[
554.051,
606.968
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 52,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R4",
"count": 56,
"end_margins_mm": [
[
640.315,
494.941
],
[
496.401,
435.893
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 56,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R3",
"count": 56,
"end_margins_mm": [
[
647.267,
438.752
],
[
484.667,
438.752
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 56,
"bend_warnings": 0
}
}
]
},
{
"job": "c37ca61ba994edf2547dcd78",
"rows": [
{
"block": "BLOCK2",
"mark": "R3",
"count": 78,
"end_margins_mm": [
[
79.326,
329.326
],
[
79.326,
329.326
]
],
"equal_ends_or_skew_exempt": false,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 78,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R3",
"count": 58,
"end_margins_mm": [
[
84.333,
334.333
],
[
84.333,
334.333
]
],
"equal_ends_or_skew_exempt": false,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 58,
"bend_warnings": 0
}
},
{
"block": "BLOCK3",
"mark": "R4",
"count": 22,
"end_margins_mm": [
[
399.301,
399.301
],
[
399.301,
399.301
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 22,
"bend_warnings": 0
}
},
{
"block": "BLOCK3",
"mark": "R3",
"count": 22,
"end_margins_mm": [
[
402.833,
402.833
],
[
402.833,
402.833
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 22,
"bend_warnings": 0
}
},
{
"block": "BLOCK2",
"mark": "R4",
"count": 78,
"end_margins_mm": [
[
200.796,
200.796
],
[
200.796,
200.796
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 78,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R4",
"count": 58,
"end_margins_mm": [
[
205.8,
205.8
],
[
205.8,
205.8
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 58,
"bend_warnings": 0
}
}
]
},
{
"job": "f37b4289c97298fed715a88d",
"rows": [
{
"block": "BLOCK1",
"mark": "R3",
"count": 62,
"end_margins_mm": [
[
225.292,
225.292
],
[
225.292,
225.292
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 62,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R4",
"count": 62,
"end_margins_mm": [
[
222.422,
222.422
],
[
222.422,
222.422
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 62,
"bend_warnings": 0
}
},
{
"block": "BLOCK2",
"mark": "R3",
"count": 58,
"end_margins_mm": [
[
233.295,
233.295
],
[
233.295,
233.295
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 58,
"bend_warnings": 0
}
},
{
"block": "BLOCK2",
"mark": "R4",
"count": 58,
"end_margins_mm": [
[
230.423,
230.423
],
[
230.423,
230.423
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 58,
"bend_warnings": 0
}
}
]
},
{
"job": "2120ce4675c6c0e6340aaac8",
"rows": [
{
"block": "BLOCK2",
"mark": "R4",
"count": 62,
"end_margins_mm": [
[
176.418,
176.418
],
[
176.418,
176.418
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 62,
"bend_warnings": 0
}
},
{
"block": "BLOCK2",
"mark": "R3",
"count": 62,
"end_margins_mm": [
[
178.809,
178.809
],
[
178.809,
178.809
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 62,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R4",
"count": 64,
"end_margins_mm": [
[
212.92,
212.92
],
[
212.92,
212.92
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 64,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R3",
"count": 64,
"end_margins_mm": [
[
215.313,
215.313
],
[
215.313,
215.313
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 64,
"bend_warnings": 0
}
}
]
},
{
"job": "d0701131f1f87d687322a4f4",
"rows": [
{
"block": "BLOCK3",
"mark": "R4",
"count": 18,
"end_margins_mm": [
[
361.165,
361.165
],
[
361.165,
361.165
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 18,
"bend_warnings": 0
}
},
{
"block": "BLOCK3",
"mark": "R3",
"count": 18,
"end_margins_mm": [
[
361.869,
361.869
],
[
361.869,
361.869
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 18,
"bend_warnings": 0
}
},
{
"block": "BLOCK2",
"mark": "R4",
"count": 78,
"end_margins_mm": [
[
191.14,
191.14
],
[
191.14,
191.14
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 78,
"bend_warnings": 0
}
},
{
"block": "BLOCK2",
"mark": "R3",
"count": 78,
"end_margins_mm": [
[
191.835,
191.841
],
[
191.835,
191.841
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 78,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R4",
"count": 78,
"end_margins_mm": [
[
196.138,
196.138
],
[
196.138,
196.138
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 78,
"bend_warnings": 0
}
},
{
"block": "BLOCK1",
"mark": "R3",
"count": 78,
"end_margins_mm": [
[
196.838,
196.838
],
[
196.838,
196.838
]
],
"equal_ends_or_skew_exempt": true,
"attachment_and_containment": {
"raw_outside": 0,
"rounded_outside": 0,
"rounded_contacts": 78,
"bend_warnings": 0
}
}
]
}
]
}
@@ -0,0 +1,74 @@
# R3/R4 and parapet report audit — 2026-09-15
This is the earlier, pre-zigzag snapshot. The subsequent six-model local-only
results and remaining wing warnings are recorded in
[R34_SIX_MODEL_AUDIT_20260915.md](R34_SIX_MODEL_AUDIT_20260915.md).
## Applied results
All changes use shared source-reading, placement and validation code. No job
ID, drawing hash, fixed model quantity or copied geometry selects a pose.
Drawing-count distribution remains an explicitly authorized review policy,
not literal reconstruction of authored stations or engineering approval.
| Saved model | R3/R4 audit and publication |
| --- | --- |
| f37b4289c97298fed715a88d | Added B1 R3/R4 62 each, B2 R3/R4 58 each; all four groups pass |
| 2120ce4675c6c0e6340aaac8 | Added B1 R3/R4 64 each, B2 R3/R4 62 each; all four groups pass |
| 03dd556bb61ab4adec0b670d | Replaced B2 R3 78; preserved unrelated rows. B1/B3 R3 fail raw/rounded containment; R4 section axis remains ambiguous |
| dc0a31e7e7d7fda5afb703bd | No publication: R3 section axis ambiguous; R4 only half of proposed paths pass enclosure check |
| c37ca61ba994edf2547dcd78 | No publication: R3 rounded contact fails on some instances; R4 section axis ambiguous |
| 23d1a02df0d24b7bb0368d6f | Restored model has R3/R4 rows; fresh source seed inventory is empty. Existing rows preserved, not marked newly verified |
| 4ea7ba277676614b64ce3089 | Restored model has R3/R4 rows; fresh source seed inventory is empty. Existing rows preserved, not marked newly verified |
| 10d3dc5c7463012bd0dac27f | Failed saved job: B2 R3 candidate passes; other rows fail enclosure/contact/axis. No publication into failed job |
| d0701131f1f87d687322a4f4 | Existing R3/R4 retained: B1/B2 78 each, B3 18 each. Previously checked enclosure, not hook/engineering approval |
Nine groups / 570 bars were added or replaced in the three successful target
models. Publication rechecks current hosts, actual target bars, raw and rounded
tube containment, contact, physical enclosure, lengths and counts. Original
unrelated concrete and reinforcement are preserved; each save has a backup.
An incidental pair of surface contacts is not sufficient enclosure evidence.
## Parapet report defect
The actual report worker reproduced START_PARAPET NA1 as 20 exposed bars even
though the sampled backend tube test reported zero. The stored parapet bottom
and roof top used differently rounded elevations: maximum contact difference
0.00000039190000045 m. Continuous interval inspection correctly detected that
numerical gap. No exposure-length threshold or mark-specific exemption was added.
Shared contact normalization now closes only uniquely matched planar contacts
within 0.000001 m, checking corners and interior/edge probes. It keeps the roof,
parapet top and every reinforcement path unchanged. Actual 1 mm gaps and
ambiguous hosts remain unchanged. Mesh-based parapets now use this same common
contact rule, alongside the existing ruled-surface contact rule.
d070 start/end contact meshes were updated. All 32 parapet groups in the eight
saved models with parapet bars now pass the actual report worker with zero
exposed bars. The live 8097 page also returned all four d070 parapet rows as pass.
An old report window is an immutable snapshot: reload the model and reopen the
report to obtain the corrected geometry.
Parapet anchorage and longitudinal generation now independently check the
actual viewer-rounded paths against their explicit parapet/roof hosts.
## Wing workflow retained in this release
The common current-source wing stage publishes strict validated groups plus
explicitly unapproved review groups using the existing wing workflow. d070 has
52 wing groups across four occurrences (13 each), with all 79 existing body
groups preserved. WR2/WR7/WH1/WR11 retain anchorage exposure warnings. This is
not complete wing geometry/anchorage approval.
## Verification and unresolved scope
- Shared mesh contact tests: closure, idempotence, real-gap preservation,
ambiguous-host rejection.
- Body quantity tests: explicit source authorization, shared topology-based
dispatch, no alternate-policy fallback, rounded contacts and enclosure gate.
- Existing wing review, progressive preservation, fresh rebar, parapet and
wing module regression tests.
- JavaScript quantity report and placement editor regression scripts pass.
- AirExposure regression suite: 21 checks pass; real gaps remain detectable.
- R3/R4 failures listed above and remaining wing anchorage warnings stay open.
This release does not claim that every model or every reinforcement row is approved.
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,88 @@
# 본체 체결근 양측 배치 조정
## 사용자 확정 조건
- WR2·WR7·WH1·WR11은 사용자가 원도면 오류에 따른 이탈로 확인했다. 해당 철근과 이탈 검사는 변경하지 않는다.
- 본체 체결근만 수정한다. 난간벽 footprint를 별도 배치 금지 구간으로 취급하지 않는다.
- 기존 1,000 mm 반복과 500 mm 교대를 유지한다. 간격 축소는 허용하지 않았다.
- 직선 블럭은 실제 체결 위치 격자 안에서 양끝 여유를 최대한 맞춘다. 후속 사용자 확정: **체결 우선**. 끝 여유를 맞추기 위해 체결을 해제하거나 기존 반복 간격을 변경하지 않는다.
- 경사 블럭은 긴 쪽에 더 배치한다. 양끝 여유 일치는 강제하지 않는다.
- 제작 상세와 한 본 길이, 제작행 총수량, 다른 철근과 콘크리트는 보존한다.
- 모델 ID별 예외 없이 동일 코드로 실행한다. 커밋·Gitea 업로드는 하지 않는다.
## 공통 코드
`authorized_quantity_generation` → `quantity_cycle_contacts` →
`cycle_tie_rhythm.balanced_selection` → `quantity_review_validation`.
좌우를 같은 station과 같은 본수로 묶던 선택기를 실제 양측 배치열 선택기로
변경했다. 단면의 사선 투영 때문에 두 높이 열의 Y 좌표도 다르므로, 정확히
같은 Y가 아니라 두 물리 철근망 사이의 큰 횡방향 간격으로 좌우를 분류한다.
일반부에 한정된 기존 접촉 후보는 경사 단부를 누락했다. 현재 저장된 CAD
사이클 경로의 경사와 유한 선분을 읽어 경사 체결 후보를 추가한다. 제작
경로는 강체 회전만 하며, 실제 두 철근 접촉·감싸는 관계·원/굽힘 경로의
직경 포함 콘크리트 내부 검사를 통과해야 선택될 수 있다. 임의 전단·축척,
호스트 확대, 경고 삭제는 하지 않는다.
사용자가 허용한 배치 선택이며 원도면 설치선을 그대로 복원했다는 의미는
아니다. source contact와 quantity distribution 근거를 각 본에 남긴다.
경사 구간의 양끝 여유는 진단 수치로 유지하되 합격 조건으로 사용하지 않는다.
## 배치 수정 이력과 후속 체결 우선 결정
최초 배치 수정에서는 6개 저장 모델의 28개 그룹·1,548본을 교체했고,
나머지 두 행은 유지했다. 이 수치는 후속 체결 우선 확인 전의 좌표 교체 이력이다.
직선 c37 블럭1·2 R3 두 행은 실제 체결 격자 때문에 양끝 여유가 250 mm
차이 난다. 후속 사용자 확인으로 체결을 우선하므로 기존 체결 배치를 유지한다.
실제 표시되는 굽힘 경로와 철근 반지름으로 다시 측정하면 블럭1은
84.333/334.333 mm, 블럭2는 79.326/329.326 mm다. 블럭1의 125 mm
이동 시험은 직선화된 원 경로 접촉은 통과하지만 굽힘 처리 후 두 철근 접촉은
실패했다. 따라서 끝 여유만을 위해 이동하지 않는다.
두 높이 배치열의 여유 평균을 끝간격으로 사용하던 검사를 수정했다.
이제 각 물리 측의 첫/마지막 **표시 형상 외곽**과 소유 콘크리트 단부를
직접 비교한다. 저장된 합격 플래그나 여유값을 재사용하지 않으며,
기존 배치가 남아 있는 행도 전수 감사에 포함한다. 1 mm 판독 허용차를
기록하고, 체결 우선 조건에서는 끝간격 잔차를 체결 실패와 구분한다.
실제 두 철근 접촉, 원/굽힘 관단면 내부 검사 게이트는 완화하지 않는다.
| 모델 | 이번 반영 그룹 / 본수 | 경사부 R3·R4 양측 본수 |
| --- | --- | --- |
| 03dd | 6 / 312 | 블럭1 28·26, 블럭3 11·13 |
| dc0 | 4 / 216 | 블럭1 29·27, 블럭2 25·27 |
| c37 | 4 / 180 | 직선부 두 R3 행은 기존 배치 유지 |
| f37 | 4 / 240 | 동일 길이 양측 균등 |
| 2120 | 4 / 252 | 동일 길이 양측 균등 |
| d070 | 6 / 348 | 동일 길이 양측 균등 |
경사부는 각 행의 실제 유효길이가 긴 쪽에 더 배치됐다. 총수량과 각
제작 구간 길이는 유지됐고, 원 경로·굽힘 처리 경로의 체결 및 관단면
검사를 통과했다. 6개 모델 모두 수정 전 백업과 대조해 콘크리트 및
체결근 외 철근 다중집합이 보존됐음을 확인했다. 이름 정규화 필드만
비교에서 제외했다. 동명 JSON에 파일 해시, revision, 백업과 행별 결과가 있다.
브라우저에서는 03dd 블럭1 R3·블럭3 R4, dc0 블럭2 R4의 Top 배치를
확인했다. 회귀 테스트는 런타임·저장소 경로 각각 57개 통과했다.
위 57개 테스트 및 서버 재시작은 최초 28개 그룹 반영 시점의 이력이다.
후속 끝간격 검토에서는 모델 좌표를 변경하지 않았다. 공통 코드의 기본
우선순위는 명시적으로 허용된 체결근에 대해 `attachment_first`이며,
같은 반복·교대 격자의 실제 체결 후보 안에서 표시 외곽 여유를 최소화한다.
회귀 테스트는 런타임과 저장소 경로에서 동일하게 실행한다. 게시 도구는
검증된 제작행만 최신 모델에 병합하고 백업·동시 수정 검사를 수행한다.
`tools/audit_balanced_body_ties.py`는 고정 반복/교대, 실제 좌우 본수, 제작
길이, 원/굽힘 접촉과 관련 없는 모든 철근·콘크리트의 보존을 검사한다.
## 후속 전수 재검사 완료
체결 우선 결정 후 6개 모델의 R3·R4 **30개 그룹·1,684본**을 저장 파일에서
다시 읽어 실제 굽힘 경로를 생성하고 독립 검사했다. 원 경로와 굽힘 경로의
연속 관단면 이탈 0, 독립 표본 이탈 0, 굽힘 경고 0이며 1,684본 모두
두 실제 대상 철근 접촉 검사를 통과했다. 구조설계 승인을 뜻하지 않는다.
직선부 끝간격 차이가 1 mm를 넘는 행은 c37 블럭1·2 R3 두 행이다.
경사부는 사용자 요청대로 끝 여유 일치를 강제하지 않았다. 체결을 위해
유지한 잔차와 실제 수치는 `R34_ATTACHMENT_PRIORITY_20260916.json`에 기록했다.
이번 후속 확인에서 저장 모델 좌표는 바꾸지 않았고 Gitea에도 올리지 않았다.
회귀 테스트는 런타임과 저장소 경로 각각 63개 통과했다.
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,77 @@
# 6개 모델 R3/R4 공통 지그재그 검증
2026-09-15. 로컬 코드와 저장 모델에만 반영했으며 커밋·Gitea 업로드는 하지 않았다.
전체 모델 승인 또는 모든 미해결 항목의 완료를 뜻하지 않는다.
## 적용 결과
| 모델 | 블럭별 R3 / R4 본수 | R3/R4 이탈 | 전체 보고서 이탈 행 |
| --- | --- | --- | --- |
| 03dd556bb61ab4adec0b670d | 54/54 · 78/78 · 24/24 | 0 | 16 |
| dc0a31e7e7d7fda5afb703bd | 56/56 · 52/52 | 0 | 16 |
| c37ca61ba994edf2547dcd78 | 58/58 · 78/78 · 22/22 | 0 | 16 |
| f37b4289c97298fed715a88d | 62/62 · 58/58 | 0 | 0 |
| 2120ce4675c6c0e6340aaac8 | 64/64 · 62/62 | 0 | 16 |
| d0701131f1f87d687322a4f4 | 78/78 · 78/78 · 18/18 | 0 | 16 |
R3/R4 30개 그룹·1,684본 모두 수량, 고정 제작 길이, 실제 대상 철근 접촉,
감싸는 관계, 원 경로와 굽힘 처리 경로의 직경 포함 내부 검사를 통과했다.
각 열은 1,000 mm 반복, 두 높이 열은 500 mm 교대이며 좌우 대응 열의
station은 동일하다. 개별 본 길이 오차는 부동소수점 계산 수준이다.
6개 모델 모두 브라우저 Top 뷰에서 지그재그와 좌우 배치를 확인했다.
콘크리트 166개 솔리드의 열린 모서리·비다양체 모서리·컴파일 누락은 없다.
이 검사는 도면 대조나 구조 안전 검토를 대체하지 않는다.
## 공통 실행 경로
`authorized_quantity_generation` → `quantity_cycle_contacts` →
`cycle_tie_rhythm` → `quantity_review_validation`을 사용한다.
좌표, 상세, 지름, 본수와 사이클 설치선은 각 모델의 현재 CAD 근거를 사용한다.
작업 ID별 방향·좌표·수량 분기는 추가하지 않았다.
- 임의 균등 분배 대신 실제 같은 사이클 계열의 철근 쌍 중심을 후보로 사용한다.
- 원본 단면의 좌우 대응 열을 묶고 반복·교대 간격을 먼저 고정한다.
- 통과하지 못한 중간 위치를 다른 위치로 대체하지 않는다.
- 사용자가 허용한 재료표 수량으로 완전한 좌우 station 묶음을 끝낸다.
따라서 이 단부 선택은 원도면의 모든 종방향 설치선을 그대로 복원한 결과와 구분한다.
- 경사는 소속 슬래브의 공통 횡단 기준고를 사용한 강체 회전으로 반영한다.
원본 일반부 사이클 범위를 유지하며 스큐부 사이클을 일반부 후보에 섞지 않는다.
- 신규 생성과 저장 모델 반영 모두 `quantity_row_identity`로 기존 동일 제작행을
교체한다. 03dd 블럭3 R4의 잘못된 구형 직경 행과 신형 행 중복도 제거했다.
- 다른 콘크리트와 다른 철근은 유지하고 저장 전 백업 및 동시 수정 검사를 실행한다.
상부 헌치의 네 상단 절점이 슬래브 하면과 정확히 대응하는 경우에만 같은
해석 접촉면을 사용한다. 삼각 단면 깊이와 원 정점은 바꾸지 않는다. 실제 설계 틈은
닫지 않으며 철근명별 이탈 면제나 이탈 길이 절사 규칙은 없다.
## 전체 검사에서 남은 항목
실제 보고서와 같은 표시 대상 829개 행을 연속 관단면 검사했다.
03dd의 기존 비표시 근거 장부 32행은 모델 형상으로 간주하지 않았으며 JSON에
제외 목록을 별도로 남겼다. 표시 필터나 검증 경고를 숨기도록 바꾸지 않았다.
날개벽이 있는 5개 모델에서 WR2·WR7·WH1·WR11 각 네 발생 객체, 총 80행의
정착부 이탈이 남아 있다. R3/R4 이탈은 아니다. 03dd의 현재 원도면 정면도·A-A·B-B와
52본 설치 높이를 다시 추출해 확인했다. B-B 평면 형상을 상단 설치 높이에 적용하면
일부 정착다리가 본체/난간벽의 실제 상단·폭 밖으로 나간다. 예를 들어 WR2 상단
두 본의 정착다리는 난간벽 200 mm 폭을 넘어간다. 현재 수량·B-B 형상·제작 길이를
동시에 유지한 채 이 부분을 정상이라고 처리할 수는 없다.
이 80행은 삭제·절단·축척·임의 높이 재분배 또는 검사 면제로 처리하지 않았다.
상단 정착 상세와 설치면의 추가 폐합이 필요하다. 다른 행의 수량 불일치까지 모두
해결됐다는 의미도 아니다.
## 재현 및 회귀 검사
- 저장 결과의 revision, 파일 해시, 공통 코드 해시, 각 그룹의 반복·교대 검사와
이탈 행/위치는 동명 JSON에 기록했다.
- 브라우저 로드 후 표시 이름이 정규화되어 일부 파일 해시가 달라졌다. 전체 콘크리트와
철근 그룹 다중집합을 다시 대조해 `rebar_assembly_label` 외 변경이 없고 geometry revision도
같음을 확인했다. 로드 후 파일 해시도 별도로 기록했다.
- `tools/audit_saved_model_report.js`는 실제 `ModelReport.capture`와
`AirExposure.inspect`를 실행한다. 단일 호스트의 경고 숫자를 그대로 재사용하지 않는다.
- Python 회귀 검사: 기존 125개 및 제작행 교체 3개 통과. 저장소 경로에서도 127개 통과
(런타임 전용 단일 테스트 제외).
- JavaScript 수량 보고서 10개 검증 묶음, 치수 편집기 9개 검증 묶음 통과.
- `git diff --check` 통과. Git HEAD는 작업 전 `88b0dd2` 그대로다.
@@ -0,0 +1,41 @@
# 이형철근 굽힘 원호 — 2026-09-14
## 적용 기준
사용자가 첨부하고 적용을 승인한 표의 **최소 내면 지름**을 사용한다.
이 문서는 별도의 최신 설계기준 인증이나 구조 승인이 아니다.
- D16 이하: 내면 지름 = 2 × 철근 직경.
- D19 이상: 내면 지름 = 3.5 × 철근 직경.
- 중심선 반지름 = (내면 지름 + 철근 직경) / 2.
- 도면의 명시 내면 지름 `bend_inner_diameter_mm`이 더 크면 해당 값을 적용한다.
- 명시 치수가 최소 기준보다 작거나 구간에 원호가 들어가지 않으면 원본을 유지하고 경고한다. 반지름 축소·단부 이동·본수 삭제는 하지 않는다.
- 현재 CAD ARC 엔티티에 연결된 occurrence의 기존 곡선은 재절곡하지 않는다.
- `bend_radii_mm`만 있고 내면/중심선 및 절점 대응이 불명확하면 임의 해석하지 않는다.
## 공통 모델 경로
도면 원본 절점과 배치 → 선택 각도 적용 → `ModelKernel.compileRebar` → 굽힘 중심선 → 화면 / 연결된 관 메시 OBJ / 보고서.
기존 콘크리트와 저장된 철근의 원본 절점·객체 귀속·배치·본수는 변경하지 않는다.
화면 계산 시 공통 정책을 적용하므로 기존 작업도 새 코드로 열면 동일한 굽힘 규칙을 적용받는다.
백엔드의 과거 날카로운 절점에 대한 검증값을 곡률 적용 후의 검증값으로 바꾸지 않는다.
원호는 두 직선에 접하도록 넣으며 양단은 유지한다. 이에 따라 중심선 길이는 달라진다.
보고서는 원호 적용 길이를 사용하고, 이전 이탈 캐시를 무효화해 실제 표시 경로를 다시 검사한다.
작업 JSON에는 굽힘 정책과 곡률 적용 보고서 경로가 포함된다. 원본 경로는 원본으로 보존한다.
OBJ는 원호마다 잘린 원통이 아니라 연속 단면 링을 연결한 관 메시로 출력한다.
## 확인
| 모델 | 표시 대상 본수 | 새 굽힘 적용 | 원본 ARC 보존 | 굽힘 적용 경고 |
| --- | ---: | ---: | ---: | ---: |
| 03dd | 7,100 | 4,784 | 712 | 0 |
| f37 | 4,940 | 3,168 | 504 | 0 |
| 2120 | 7,992 | 5,800 | 528 | 0 |
| dc0 | 6,415 | 4,567 | 504 | 0 |
| c37 | 7,092 | 4,872 | 672 | 0 |
이외 철근은 직선이다. 입력 모델의 직렬화 전후 일치와 유한 좌표를 확인했다.
단위 검사는 직경별 반지름·각도·3차원 회전·폐쇄 경로·공간 부족·원본 ARC 보존·OBJ 메시 폐합·보고서 경로 일치를 포함한다.
굽힘 적용 경고 0은 모든 피복·상세·이음 검증 통과를 의미하지 않는다.
@@ -0,0 +1,31 @@
# 회귀검사 건너뜀 제거
최종 전체 실행 결과: **1,039건 통과 · 실패 0 · 오류 0 · 건너뜀 0** (274.786초).
이전에는 클래스 전체가 생략되었던 날개벽 검사 3건과 승인 차단 검사 1건이 전체 집계에 추가되었습니다.
## 이전 9건의 실제 사유
| 범위 | 건너뛴 보고 수 | 원인 및 수정 |
| --- | ---: | --- |
| 표준단면 5건·단면 정렬 1건 | 6 | 사라진 `before-cycle-2930f5bb37b3` 임시 백업을 고정 참조. 실제 보관된 동일 도면의 수정 전 백업을 사용하고 CAD는 SHA-256으로 검색 |
| 서로 다른 도면의 제작 상세 추출 | 1 | 사라진 임시 업로드 파일명 2개를 고정 참조. 현재 보유한 서로 다른 원본 2종을 내용 해시로 연결 |
| 날개벽 시·종점/좌·우 화면 분류 | 1 | PATH에서 Node를 찾지 못함. 실제 설치된 Node 또는 `MODEL_TEST_NODE`로 실행하고 현재 물리 호스트·가운데 점 표기 계약으로 검증 |
| 날개벽 회전·대칭·수평근 테스트 클래스 | 1 | 사라진 과거 작업 ID 2개를 고정 참조. 현재 도면 모델을 대상으로 실제 검사 수행. 이 클래스 안에는 테스트 3개가 있었음 |
## 검사 재실행으로 발견한 사항
- 과거 단면 정렬 도구가 그룹에 슬래브 외 연결 호스트가 함께 있으면 모호하다고 중단했습니다. 도면에 결속된 주 부재를 사용하도록 수정했습니다. 좌표축 잠금·동일 반복 실행·다른 객체 보존 검사는 유지합니다.
- 옛 날개벽 생성 함수는 미검증 설치를 승인하지 않도록 이미 차단되어 있습니다. 이를 통과로 기대하던 과거 검사를 현재 계약에 맞췄습니다. 후보의 형상 길이·회전·대칭 검사는 실제 실행하며, 후보를 승인해 버리지 않는지도 검사합니다.
- 수평근의 양성 검사는 2120 원본과 현재 공통 코드로 수행합니다. 원본 CAD의 단면/입면 배근선과 치수 근거에서 다시 경로를 만들며, 저장된 수평근 경로는 입력으로 사용하지 않습니다. 본수·높이·간격·구간 길이 및 호스트 발생 수를 확인합니다. 회전·대칭 및 객체 계약 검사는 2120·c37 두 모델을 대상으로 합니다.
- 필요한 자료가 없으면 더 이상 `skip`으로 넘기지 않고 명시적으로 실패합니다. 원본 자료 없이 검증을 통과시키지 않습니다.
## 필수 실행 명령
```sh
./.venv-dwg/bin/python tools/run_regressions.py
```
한 건이라도 건너뛰거나 실패·오류가 있거나 검사 수가 0이면 종료 코드 1입니다.
자료 위치는 `MODEL_TEST_JOB_ROOT`, `MODEL_TEST_CAD_ROOT`, `MODEL_TEST_SECTION_BASELINE`, `MODEL_TEST_NODE`로 지정할 수 있습니다.
이번 변경은 검사 구성과 과거 진단 도구 수정입니다. 화면의 콘크리트·철근 모델을 교체하거나 승인 상태를 바꾸지 않았습니다.
@@ -0,0 +1,38 @@
# 남은 슬래브·벽체 도면 연결 수정
범위: c37 블럭1 D1 리더, f37 블럭1 단부 대응, 03dd 블럭1·3 벽체 경사.
원본 CAD를 로컬에서 다시 읽었으며 외부 분석 서비스에 전송하지 않았습니다.
## 수정 내용
| 대상 | 원인 | 공통 코드의 처리 |
| --- | --- | --- |
| c37 블럭1 D1 | 단면 리더 끝점이 철근 기호에 닿지 않음 | 같은 원본의 독립된 벽체 입면 리더들이 가리키는 깊이와 단면 기호 열을 교차 확인. 가까운 점을 임의 선택하지 않음 |
| f37 블럭1 단부 | 단면의 동일 점을 상·하면에 중복 연결 | 각 면의 평면도에 실제로 그려진 종방향 단부 배근선과 상세 높이를 연결. 치수선만 있거나 다른 면의 배근선이면 연결하지 않음 |
| 03dd 블럭1·3 벽체 | 스큐 슬래브 윗면의 보간 경사를 벽체 배근에 적용 | 해당 벽체 입면의 콘크리트 양단에서 경사를 읽고, 직각 시공이음 기준면에 결속. 원본 배근선의 길이·경사 및 관단면 내부 검사를 다시 수행 |
철근명은 같은 원본 안의 리더·재료행 추적에만 사용합니다. 작업 ID나 D1/D2라는 이름으로 좌표·수량·설치 면을 정하는 분기는 추가하지 않았습니다.
## 반영 및 확인
- c37: 슬래브 6쌍 대조 통과. 블럭1 D1·D2 각각 26본을 화면용 모델에 반영.
- f37: 슬래브 4쌍 대조 통과. 블럭1 D2·D3의 양단을 각 평면도 배근선으로 연결. 각각 16본이며 재료표에 맞추어 본수를 늘리지 않음.
- 03dd: 벽체 6그룹을 재생성·대조 후 반영. 블럭1·3 입면 배근선 대조 오차 최대 약 0.136mm로 기존 1mm 기준 통과.
- 세 모델 모두 수정 전 백업 보관. 콘크리트 전체와 수정 대상 밖의 철근 그룹은 변경 전과 정확히 같음.
- 8097 서버 재시작 및 HTTP 200 확인. 세 모델의 대상 그룹은 브라우저의 표시 필터·렌더링 경로에서도 확인.
- 후속 전체 검사에서 1,039건 통과, 실패·오류·건너뜀 0건으로 마무리했습니다. 이전의 9건 생략 원인과 수정 사항은 [건너뜀 제거 기록](REGRESSION_NO_SKIPS_20260914.md)에 남겼습니다.
- 5개 모델 원본 재생성 회귀검사: 모든 슬래브 상·하면 쌍 검사 및 중복 경로 검사 통과. c37·f37·2120·dc0의 대상 면 생성 오류 0건. 03dd의 슬래브·벽체 18그룹도 생성 성공했으며, 과거 저장 행 S2/S3/S4의 현 원본 제작행 소속 경고 6건은 이 세 수정 항목과 별도로 유지.
- 2120 재생성 대상 좌표 차이 0mm. dc0 슬래브 차이 0mm, 벽체는 원본 입면 경사 적용에 따라 최대 0.853mm 차이로 기존 1mm 범위 안. 두 모델의 화면 저장본은 이번 부분 수정에서 덮어쓰지 않음.
## 완료 범위의 구분
위 세 연결 오류를 해결한 것이며 전체 제작 상세·이음 길이와 재료표 수량을 일괄 승인한 것은 아닙니다. 수량 차이는 도면 배치 수량과 재료표 수량을 구분해 남깁니다. 검사 기준을 낮추거나 미확정 항목을 일괄 통과시키지 않았습니다.
원본 재생성 검사 파일:
- `/tmp/face-source-regression-v4-20260914/03dd556bb61ab4adec0b670d.json`
- `/tmp/face-source-regression-v4-20260914/c37ca61ba994edf2547dcd78.json`
- `/tmp/face-source-regression-v5-20260914/`
반영 도구: `tools/publish_verified_slab_subset.py`의 `--source-faces`, `--source-walls`.
화면 모델의 입력과 원본 해시가 달라졌거나 콘크리트가 바뀌면 반영하지 않습니다.
@@ -0,0 +1,13 @@
# 서버 전용 AI 로그인
사용자가 명시적으로 승인한 ChatGPT 로그인은 서버 전용 `studio-ai-auth` 볼륨(`/root/.codex`)에 보관합니다. 클라이언트 PC, Gitea 저장소, 컨테이너 이미지, 공유 모델 캐시에 인증정보를 넣지 않습니다. 도면 생성 코드는 변경하지 않습니다.
배포 이미지는 현재 로컬과 동일한 Codex CLI 0.153.4 및 Node 런타임을 설치합니다. 최초 배포 시 `deploy-server.bat` 옆의 비공개 `codex-auth.json`을 표준입력으로 가져옵니다. 가져오기 프로그램은 웹에서 호출할 수 없으며, 토큰을 출력하지 않습니다. 파일/폴더 권한은 각각 600/700입니다.
재배포할 때 같은 계정의 기존 인증은 보존합니다. 서버에서 갱신된 인증을 오래된 설치 파일로 덮어쓰지 않습니다. 다른 계정이 이미 설정되어 있으면 덮어쓰지 않고 중단합니다. `codex login status`가 실패하면 배포 완료로 표시하지 않습니다. 인증 인식과 실제 AI 호출·도면 생성 검증은 서로 다릅니다.
계정 사용량은 서버에서 공유됩니다. 로그인 없이 접근 가능한 페이지를 인터넷에 공개하지 마십시오. 사내 승인 사용자 또는 VPN 등으로 접근 범위를 제한해야 합니다. 로그인 취소·갱신 실패 시 서버에서 다시 로그인해야 할 수 있습니다.
비공개 배포 ZIP은 승인된 서버로만 전달하십시오. 저장소 밖에서 `tools/package_private_server_login.py`로 만들며 Git/Docker 제외 규칙을 적용합니다. 계정 파일 내용은 로그·채팅·이슈에 기록하지 않습니다.
공식 안내: https://learn.chatgpt.com/docs/auth (headless 인증 및 Docker로 인증 캐시 전달). 공식 문서는 자동화의 기본 방식으로 API 키를 권장하며, 여기서는 사용자가 승인한 기존 ChatGPT 인증 전달 방식을 사용합니다.
@@ -0,0 +1,13 @@
# 서버 공용 저장 모델
이 저장소에는 사용자가 지정한 box·box2·box3·box4·box5·box6·9개 도면 묶음의 저장 모델 7개가 `shared-cache/selected-models.zip`으로 포함됩니다. AI 로그인 정보와 Gitea 토큰은 포함하지 않습니다.
배포 배치파일로 내려받아 컨테이너를 시작하거나 `src/backend/serve.py`를 실행하면 묶음의 해시를 검증하고 서버 데이터 폴더에 설치합니다. 같은 ID의 기존 서버 작업은 덮어쓰지 않습니다. Docker의 `studio-data` 볼륨은 업데이트 후에도 유지됩니다.
서버 페이지의 **서버 저장 모델 · 7개**에서 모델을 선택할 수 있습니다. 같은 도면 파일을 넣으면 파일명과 원본 SHA-256으로 저장 결과를 찾습니다. 서버에 접속한 다른 PC도 같은 서버 데이터를 사용하므로 PC별로 캐시를 복사할 필요가 없습니다.
이 묶음은 배포 시점의 저장본입니다. 개인 PC와 배포 서버가 이후 서로 자동 동기화되는 기능은 아닙니다. 배포 서버에서 저장한 수정은 그 서버의 모든 접속 PC가 공유합니다. 데이터 볼륨을 삭제하지 마십시오.
저장 모델·철근·보고서 근거는 7개 모두 포함합니다. 일부 과거 업로드 원본은 현재 보관 폴더에 없으며, 목록은 ZIP의 `manifest.json`에 기록합니다. 해당 저장 모델의 조회와 동일 원본 해시 조회는 가능하지만, 누락된 원본을 필요로 하는 새 분석·재생성에는 원본 재업로드가 필요할 수 있습니다. 캐시 설치는 모델 승인 상태나 좌표를 변경하지 않습니다.
현재 배포 주소: `http://10.14.12.22/box-sample/` (서버 포트 5092). 서버 운영망의 접근 권한이 있는 사용자에게 모델과 도면이 공유되므로 외부 공개망에 노출하지 마십시오.
@@ -0,0 +1,53 @@
# 도면값 기반 생성 경로 정리 — 2026-09-14
## 변경 범위
- 도면 해시별 고정 치수·경사·설치 위치를 가진 사이클/본체/접속슬래브 어댑터를 공통 CAD 생성기의 호환 진입점으로 교체했습니다.
- 원본 CAD나 현재 콘크리트 입력이 없으면 샘플 치수를 대입하지 않습니다.
- 원도면에서 소유 관계가 확인되지 않은 저장 철근 행은 새 생성 입력으로 재사용하지 않습니다. 기존 화면 결과 보존과 새 도면 근거 판독은 별개입니다.
- 서버의 모든 실행 진입점에 공통 생성 경로를 설정하고, 이후 구형 보정기가 철근을 다시 쓰는 경로를 차단했습니다.
- 해시 기반 샘플 수식 자동 주입을 제거했습니다. 원본 파일 식별·캐시 확인용 해시는 유지합니다.
- 날개벽 끝 높이, 구형 보정기의 피복 누락에 임의 기본값을 넣던 부분을 제거했습니다.
## 이번 검증의 한계
이 작업은 전체 도면을 처음부터 다시 읽어 콘크리트와 모든 철근을 완성했다는 의미가 아닙니다.
5개 모델 시험은 저장 콘크리트와 도면 근거를 복사하고, 원본 CAD를 다시 불러 공통 **날개벽 제외 철근 생성기**를 실행하는 시험입니다. 날개벽 전체 재생성, 콘크리트 원본 재생성, 모든 철근 치수의 도면 일치까지 입증하는 시험은 아닙니다. 일부 상세·설치 연결 및 체결근 접촉 검증은 남아 있습니다. 기존 승인된 화면 결과는 덮어쓰지 않았습니다.
기존 서버 파일에는 실행 차단된 구형 보정 함수가 일부 남아 있습니다. 따라서 ‘소스 전체에 어떤 고정값도 없다’고 단정하지 않습니다. 차단된 함수가 재진입하지 않는지 별도 회귀시험으로 확인합니다.
## 시험 결과
- 최신 회귀시험: 987개 실행, 실패 0개, 9개 건너뜀.
- 원본 CAD 재생성: 03dd 89그룹/5,582본, f37 98그룹/4,936본, 2120 84그룹/6,924본, dc0 106그룹/5,217본, c37 71그룹/5,820본.
- 다섯 시험 모두 저장 작업 파일과 콘크리트는 변경되지 않았고, 외부 분석 호출·결과 게시를 하지 않았습니다.
- 완료 시 미해결 기록은 각각 36/40/20/52/14건입니다. 이는 누락 철근 본수가 아니라 생성기의 상세·설치·검증 진단 건수입니다. c37 블럭2 벽체 체결근 두 그룹 등 실제 접촉/이탈 검증 실패도 남아 있습니다. 생성 본수가 있다는 이유로 모델 전체를 통과 처리하지 않습니다.
## 서비스 적용 상태
퇴역 샘플 구현과 해당 구형 테스트는 `/home/user/box/retired-drawing-recipes-20260914`에 복구 가능하게 보관했습니다. 애플리케이션 import 경로 밖이며 배포 소스에 포함하지 않습니다.
초기 점검에서는 서버 재시작을 보류했습니다. 이후 사용자의 전체 검증·서버 재시작·모델 교체 요청에 따라 8097을 재시작하고 다섯 모델에 공통 생성 결과를 병합했습니다. 기존 콘크리트와 새 검사로 대체할 수 없는 기존 철근은 유지했습니다. 미해결 행을 완료로 승인하거나 전체 모델을 새로 완성한 것은 아닙니다.
## 후속 적용 결과
- 최종 저장에서도 중간 표시와 같은 슬래브 쌍 검증을 적용합니다. 생성 성공만으로 미검증 경로를 교체하지 않습니다.
- 부분 생성 행의 본수가 기존보다 적으면 기존 행을 보존하고 미완료 이유를 기록합니다. 03dd 슬래브 단부 철근 소실을 차단했습니다.
- 다웰바 보고서에는 계산용 단면 별칭이 아닌 실제 저장 콘크리트의 근거를 연결합니다. 보고서 Worker에도 접합부 정보를 전달하며, 기존 잘못된 검사 캐시는 버전 6으로 무효화합니다.
- 수정 모델은 각 작업 디렉터리의 `before-common-runtime-*` 백업으로 복구할 수 있습니다. f37·2120의 접합부 보고서 수정에도 별도 `before-joint-report-*` 백업이 있습니다.
- Python 회귀시험 988개: 실패 0, 건너뜀 9개. 브라우저 보고서/이탈 검사 단위 검증 37개 통과.
실제 브라우저 전체 콘크리트 합집합 검사 결과(표시 대상 철근 기준):
| 모델 | 검사 그룹 | 이탈 표시 그룹 | 형상 미지원/미확인 그룹 |
| --- | ---: | ---: | ---: |
| 03dd | 149 | 16 | 0 |
| f37 | 98 | 0 | 0 |
| 2120 | 136 | 16 | 0 |
| dc0 | 158 | 20 | 0 |
| c37 | 129 | 16 | 0 |
다섯 모델 모두 난간벽 NA1/NA2는 이탈 미검출입니다. f37·2120은 도면 받침 접합부를 통과하는 다웰바 네 그룹씩도 이탈 미검출입니다. 이 검사는 철근 관단면을 샘플링한 구조물 외부 노출 검사이지, 전체 상세·본수·피복·정착 및 모든 도면 뷰의 최종 승인 검사가 아닙니다. 다른 모델의 이탈 경고와 원본 연결 미완료 기록은 지우지 않았습니다.
재시작 당시 남아 있던 d8f 작업은 정상 중단 요청으로 보존했으며 외부 분석을 자동 재개하지 않았습니다. 이번 생성은 모두 로컬에서 수행했습니다. Gitea 원격에는 푸시하지 않았습니다.
@@ -0,0 +1,49 @@
# 대형 철근 모델 뷰어 개선
## 후속 개선: WebGL2 철근 표시
첫 Canvas 2D 최적화 이후에도 사용자에게 무겁다는 피드백이 있어, 철근 표시를 WebGL2 인스턴싱으로 전환했다.
- 원호를 포함한 모든 선분을 유지한 채 GPU 버퍼에 한 번 업로드한다. 카메라 이동 중에는 버퍼를 다시 올리지 않는다.
- 테두리/본체 두 번의 instanced draw로 표시한다. 직경은 픽셀 투영으로 반영하며 물리 모델·OBJ·보고서 경로는 바꾸지 않는다.
- 큰 전역 좌표는 모델 원점에 대한 상대 좌표로 GPU에 전달한다. 화면용 float 정밀도와 원본 double 좌표를 구분한다.
- WebGL2를 사용할 수 없거나 context가 끊기면 기존 Canvas 2D 표시로 돌아간다. context 소실 때도 즉시 재표시를 요청한다.
- 보고서/JSON 캡처 시 콘크리트 Canvas와 GPU 철근층을 합성한다. 카메라 조작 중에는 이미지 readback을 하지 않는다.
- 현재 프레임 대체 타이머는 16ms다. 아래 50ms는 첫 최적화 당시 기록이다.
5개 모델에서 GPU 표시를 확인했다. f37은 GPU에 전달한 선분 수와 원본 표시 선분 수 모두 151,539개, 2120은 259,842개이며 조작 중 재업로드 없이 유지됐다.
가열 후 c37 JS 1.5~2.1ms, 03dd JS 1.7~2.1ms를 관측했다.
`gl.finish()`로 GPU 완료를 기다린 측정에서는 c37 입력→완료 5~17ms, f37 32ms, 2120 35ms, dc0 57ms 표본을 확인했다.
초기 프레임·자동 갱신·브라우저 스케줄링에 따른 변동은 있으며, 이 수치는 모든 PC의 FPS 보장이 아니다.
관련 로컬 unittest 19건 통과. 실제 context 소실 시 Canvas 2D 전환과 선분 수 보존을 확인했고, 보고서 캡처 PNG에 GPU 철근이 포함됨을 픽셀 검사로 확인했다.
추가 라이브러리나 외부 CDN을 도입하지 않았다.
## 변경
- 카메라 이동 중 콘크리트/굽힘 철근 계산과 상태 목록을 재사용한다. 모델 변경·필터·각도 선택 등 일반 그리기는 다시 계산한다.
- 좌표와 경계 계산에 점 인덱스 및 재사용 Float64 배열을 사용한다. 카메라 회전이 같으면 투영 중간값도 재사용한다.
- 확대·축소·이동 입력을 최신 카메라 상태의 한 프레임으로 합친다. 가시 탭에서도 RAF가 지연되는 환경에는 50ms 타이머를 대체 트리거로 사용하며 중복 프레임은 취소한다.
- 모든 선분을 개별 stroke로 그리는 대신 Path2D로 묶는다. 같은 철근의 원호 선분은 연속 경로로 그려 불필요한 선단 렌더링을 줄인다.
- 화면 밖으로 완전히 벗어난 선분만 표시 과정에서 제외한다. 이동하면 다시 표시한다. OBJ·보고서·물리 모델에서는 제외하지 않는다.
- 화면용 선 굵기만 0.25 CSS px 단위로 묶는다(최대 차이 0.125px). 실제 철근 직경·원호·좌표는 바꾸지 않는다.
- 드래그/카메라 조작 중과 비활성 페이지에서는 저장 작업 자동 조회를 미룬다. 다음 유휴 조회에서 변경 모델을 반영한다.
## 측정과 확인
03dd 전체 모델(167,536선분)에서 이전 동기식 휠 처리 502/1,315/1,362ms를 측정했다.
변경 후 캐시 사용 프레임의 JS 처리 시간은 약 24~62ms였다.
다른 모델의 단일 확대 프레임은 f37 33.5ms, 2120 37.0ms, dc0 37.3ms, c37 46.5ms였다.
이는 해당 브라우저에서의 JS 시간이며 GPU 완료 시간이나 보장 FPS가 아니다.
테스트 브라우저는 아무 작업이 없는 RAF도 약 1초 지연되는 현상이 있었다.
타이머 대체 후 관측된 입력→그리기 완료는 대체로 61~92ms였지만 777ms 지연 표본도 있었다.
따라서 모든 기기의 끊김 제거를 보장하지 않는다.
- 12개 연속 휠 입력: 새 프레임 1회, 철근 재계산 0회.
- 객체 선택 변경: 재계산 1회, 전체 선택 복귀 시 167,536선분 복원.
- 5개 모델의 개선 전후 콘크리트 및 철근 좌표·소속·굽힘 정보가 정확히 일치.
- 새 투영식과 기존 투영식의 좌표/화면 맞춤 일치, 원호 선분 보존, 화면 밖 제외/복원, 별개 철근 경로 비연결 검사 통과.
- 관련 로컬 unittest 18건 통과. 이번 변경에서 전체 백엔드 회귀검사는 재실행하지 않음.
- 실제 8097에서 5개 모델 로드 및 캐시 사용 프레임 확인. 콘솔 오류 0건.
기존 생성·배근·OBJ·보고서 계산은 변경하지 않았고 작업 JSON/도면 저장본도 덮어쓰지 않았다.
@@ -0,0 +1,75 @@
# 철근 표시 개선 및 JSON 단계 보기
## JSON 버튼 최종 정리
별도 이전/다음/보기 방식 변경 막대는 제거했다. JSON을 불러온 후에는 기존
형상 버튼(`형상 보기`)과 철근 버튼(`철근 보기`), 기존 보고서 버튼을 사용한다.
형상/철근 버튼은 이 경우에만 저장 데이터 표시를 전환하며 분석·생성 API를 호출하지 않는다.
새 도면을 선택하면 원래 생성 동작으로 돌아간다. 처음 불러올 때의 보기 선택 팝업은 유지한다.
실제 버튼 테스트: 형상 0 → 철근 2,088 → 형상 0선분, 추가 탐색 막대 0개, POST 요청 0건.
## 최종 적용: 기존 표현 유지, 내부 처리만 경량화
사용자는 새로운 표시 형식이 아니라 기존 Canvas 표현을 그대로 유지하도록 요청했다.
따라서 아래 GPU/색상/깊이/최소 굵기 실험은 최종 코드에서 제거했다.
- 기존 청록색 RGBA(91,221,230,.96), 어두운 테두리, .7–12px 화면 굵기로 복원.
- GPU 표시 모듈과 새 음영·색상·깊이 가림·MAX 합성을 제거하고 Canvas2D로 통일.
- 캐시, Float64 투영 재사용, 입력 프레임 통합, Path2D 묶음 처리는 유지.
- Path2D의 화면 굵기 묶음 오차는 최대 1/128 CSS px. 모델 좌표·직경·굽힘·OBJ는 변경 없음.
- JSON 단계 보기와 보고서 새 창은 유지.
- 최종 관련 unittest 21건 통과. c37 165,668선분 유지, 묶음 stroke 2회, 캐시 프레임 JS 40ms 표본 확인.
아래 내용은 변경 경위 기록이며 최종 표시 기준은 이 절이다.
## 후속 수정: 전체 배근 가시성과 눈부심
사용자 확인에서 앞뒤 가림과 최소 선 굵기 제거가 철근을 누락된 것처럼 보이게 함을 확인했다.
아래 최초 변경 기록 중 깊이 비교·최소 굵기 제거는 다음 설정으로 대체한다.
- 기본 투명 배근 뷰는 깊이 가림 없이 뒤쪽 철근도 표시한다.
- 축소 시에만 화면 최소 0.75 CSS px를 유지한다. 모델 직경·OBJ에는 적용하지 않는다.
- 색은 RGB(100,180,192) 청회색으로 낮췄다. 두꺼운 외곽선은 넣지 않는다.
- GPU 겹침은 MAX 합성을 사용한다. 원호 조각과 여러 철근이 겹쳐도 밝기가 누적되지 않는다.
- 확대 시에는 실제 직경에 따른 화면 굵기를 유지하며 12px 상한을 다시 넣지 않는다.
- 로컬 관련 unittest 21건 통과. JSON 단계 보기는 유지한다.
사내 주소 연결 실패는 인증 게이트웨이(18097) 미실행으로 확인했다.
기존 비밀번호 해시·Windows 포트 전달은 변경하지 않고 게이트웨이를 재실행했다.
`http://10.13.36.102:8097/`의 로그인 페이지 표시를 실제 브라우저에서 확인했다.
## 변경 범위
도면 판독·배근·굽힘·OBJ 생성 알고리즘과 저장된 작업 모델은 변경하지 않았다.
표시용 GPU 코드, JSON 가져오기 및 보기 전환 UI만 변경했다.
- 확대 시 철근 표시 굵기를 12px로 제한하던 처리를 제거했다.
- 최소 굵기 과장과 검은 테두리를 제거하고, 화면 배율·저장 직경에 따른 굵기와 서브픽셀 안티앨리어싱을 적용했다.
- GPU에서 앞뒤 철근의 깊이를 비교하고 단일 음영 패스로 그린다. 콘크리트는 기존처럼 투명 참조 형상이다.
- 원호의 모든 선분, 물리 좌표, 본수와 직경을 그대로 사용한다. GPU 경로는 중심선 기반 표시이며 제작용 솔리드 검증을 대신하지 않는다.
- WebGL2 미지원 시 모든 선분을 유지하는 Canvas2D 대체 표시를 사용한다. 대체 표시는 GPU 깊이 비교와 같지 않다.
## JSON 열기
`작업 JSON 불러오기`에서 파일 선택 후 팝업에서 선택한다.
1. **스텝별 보기:** 형상 → 철근 → 보고서. 이전/다음 이동이 가능하다.
2. **한 번에 보기:** 콘크리트와 저장된 철근을 함께 표시한다. 보고서는 별도 버튼으로 연다.
보기 방식은 불러온 후에도 변경할 수 있다. 취소하면 기존 프로젝트를 유지한다.
형상 단계는 철근의 화면 표시만 숨긴다. JSON 모델·OBJ 대상 철근은 삭제하지 않는다.
가져오기 자체는 `/api/analyze`나 모델 생성 API를 호출하지 않는다.
보고서는 기존 입력 서명·검사 버전이 일치하면 저장 결과를 재사용한다. 그렇지 않으면 보고서 검사만 수행한다.
이전 작업 조회 응답이 가져온 JSON을 덮어쓰지 않도록 작업 ID를 분리하고 응답 적용 전 다시 확인한다.
## 확인 결과
- 로컬 unittest 20건 통과: 표시 좌표·캐시·굽힘·OBJ 계약·JSON 보기 전환/취소 등.
- 보고서, 날개벽 각도, 이탈 검사 JavaScript 테스트 실행 성공.
- 실제 WebGL 픽셀 검사: 1m=1,000px 조건에서 직경 8/16/32mm가 각각 8/16/32px. GL 오류 없음.
- 실제 JSON 가져오기: 형상 0선분 → 철근 2,088선분 → 이전 0선분. 보고서 새 창 정상 표시.
- 원본 포함 JSON 테스트에서도 분석/생성 POST 요청 없음. 이전 작업의 진행 조회 GET만 관측됐으며 JSON 적용 후 분리됨.
- 5개 저장 모델의 WebGL 표시 확인: 03dd 167,536 / f37 151,539 / 2120 259,842 / dc0 196,775 / c37 165,668선분. 기존 표시 수 유지, 굽힘 적용 경고 0.
- c37 카메라 재표시 표본: JS 2.8ms, GPU 재업로드 없음. 초기 모델 준비 시간이나 모든 PC의 FPS를 보장하는 수치는 아니다.
이번 확인은 표시·가져오기 기능의 회귀검사이며 도면 전체 재분석이나 구조 설계 승인 검사가 아니다.