Compare commits

..
7 Commits
6 changed files with 199 additions and 353 deletions

No files matched your search

+199 -59
View File
@@ -1,78 +1,218 @@
# 2D 도면 기반 3D 수로암거 및 옹벽형 날개벽 모델링 웹 시스템 (Code/3d-drawing)
# 2D CAD 기반 암거 및 날개벽 3D 외형·배근 자동 모델링 시스템
### (Automated 3D Solid & Rebar Modeling System for Culverts and Wingwalls)
2D CAD 도면(일반도 및 구조도/배근도 DWG/DXF 5종)을 분석하여 수로암거(`STA.13+611.21`) 및 옹벽형 날개벽의 3D 솔리드 외형과 3D 내부 철근 배근(19종 508본)을 자동 구축하고, Three.js 기반의 웹 뷰어를 통해 인터랙티브하게 확인·검증·내보내기하는 시스템입니다.
> **토목 구조물의 2D CAD 도면(DWG/DXF)을 자동 파싱하여 암거 본체와 날개벽의 3D 외형 솔리드(Solid Mesh)를 구축하고, 내부 철근 배근을 3차원 공간에 자동 모델링하여 BIM 데이터와 물량표를 산출하는 범용 웹 기반 엔지니어링 시스템입니다.**
---
## 1. 주요 특징 및 구현 내용
- **1단계: 도면 불러오기 및 도면 종류 판별**
- DWG/DXF 파일 파싱 (`ezdwg`, `ezdxf`)
- 도면명 키워드 자동 판별: `'일반'` ➔ 일반도, `'배근'`/`'구조'` ➔ 구조도/배근도
- 2D CAD 벡터 뷰어 및 레이어 제어 지원
- **2단계: 일반도 기반 3D 외형 모델링**
- 암거 본체 및 날개벽 위치 판별 (시점부 좌/우, 종점부 좌/우)
- 본 도면 특성 완벽 준수: 시점부 미표기 ➔ 임의 생성 배제 / 종점부 좌·우 2개소 모델링 ($L=4.35\text{m}$, $L=5.40\text{m}$)
- 완전 폐합 2-Manifold 수밀성(Watertight) 3D 솔리드 메시 생성 (총 콘크리트 체적: $75.45\text{ m}^3$)
- **3단계: 배근도 기반 3D 철근 배근 모델링**
- 피복두께 80mm 준수
- 19종 철근 기호, 총 508본 3D 입체 배근 (종점 좌 231본 + 종점 우 277본)
- 철근 재료표(BBS) 자동 산출 (총중량: $1.543\text{ TON}$, 할증 포함 $1.590\text{ TON}$)
- **웹 3D 뷰어 (Three.js)**
- 3차원 자유 시점 궤도 제어 (OrbitControls)
- 암거 본체 / 날개벽 / 철근 레이어별 가시화 및 투명도 제어
- 3D 모델 OBJ, STL, DXF 내보내기
## 📌 목차
1. [시스템 개요](#1-시스템-개요)
2. [전체 프로세스 파이프라인](#2-전체-프로세스-파이프라인)
3. [단계별 상세 기능 및 알고리즘 메커니즘](#3-단계별-상세-기능-및-알고리즘-메커니즘)
- [1단계: 도면 불러오기 및 도면 종류 판별](#1단계-도면-불러오기-및-도면-종류-판별)
- [2단계: 일반도 기반 암거 및 날개벽 3D 외형 모델링](#2단계-일반도-기반-암거-및-날개벽-3d-외형-모델링)
- [3단계: 구조도 기반 날개벽 내부 3D 철근 배근 및 물량 집계](#3단계-구조도-기반-날개벽-내부-3d-철근-배근-및-물량-집계)
- [4단계: BIM 데이터 및 철근 가공조립표 내보내기](#4단계-bim-데이터-및-철근-가공조립표-내보내기)
4. [화면 조작 인터랙션 가이드](#4-화면-조작-인터랙션-가이드)
5. [설치 및 실행 방법](#5-설치-및-실행-방법)
6. [프로젝트 디렉터리 구조](#6-프로젝트-디렉터리-구조)
7. [자동화 파이프라인 검증 체계](#7-자동화-파이프라인-검증-체계)
---
## 2. 작업 환경 및 디렉터리 구성
## 1. 시스템 개요
- **작업 환경**: WSL2 (Ubuntu Linux)
- **저장소 위치**: `Code/3d-drawing/` (Git 관리)
본 시스템은 특정 단일 구조물에 한정되지 않고, 다양한 암거 및 날개벽 도면을 범용적으로 수용하여 3D 디지털 모델로 변환할 수 있도록 설계된 자동화 소프트웨어입니다.
- **도면 처리 범위**: 암거 일반도(형상·치수) 및 구조도/배근도(철근 제원·상세) DWG/DXF 다중 처리
- **핵심 목표**:
1. 2D 벡터 도면 엔티티에서 형상 파라미터 및 치수 정보 자동 추출
2. 암거 사각(Skew), 내공 단면, 날개벽 설치 각도 및 경사 변화를 반영한 수밀 솔리드(Watertight Solid) 메시 생성
3. 피복두께를 엄격히 준수한 3차원 철근 중심선(Polyline) 공간 배치 및 규격별 물량 자동 산출
4. 웹 기반 무설치/로컬 구동 지원 및 개방형 BIM 포맷(OBJ, STL, DXF, CSV) 상호운용성 제공
---
## 2. 전체 프로세스 파이프라인
```mermaid
flowchart TD
subgraph Step1["1단계: 도면 입력 및 분류 (Drawing Intake & Classification)"]
DWG["2D CAD 도면군 (DWG/DXF)"] --> AutoClassify["키워드 기반 도면 자동 분류<br>(일반도 / 구조도 / 미분류)"]
AutoClassify --> VectorViewer["2D CAD 벡터 엔진 렌더링<br>(도면 식별 및 레이어 검토)"]
end
subgraph Step2["2단계: 3D 외형 솔리드 모델링 (Solid Geometry Generation)"]
VectorViewer --> CulvertExtract["암거 본체 기하 자동 인식<br>(내공 스팬, 폭, 높이, 사각)"]
CulvertExtract --> WingwallExtract["날개벽 배치 판별 및 단면 보간<br>(시점/종점 좌·우 날개벽 형상 생성)"]
WingwallExtract --> MeshGen["완전 폐합 2-Manifold 메시 생성<br>(콘크리트 체적 실시간 적분)"]
end
subgraph Step3["3단계: 3D 철근 배근 및 물량 산출 (Rebar BIM Modeling)"]
MeshGen --> RebarExtract["재료표(BBS) 및 단면 배근 규칙 파싱"]
RebarExtract --> RebarGen["부재별 3D 공간 철근 폴리라인 생성<br>(설계 피복두께 자동 옵셋 적용)"]
RebarGen --> RebarBOM["철근 가공조립표 및 총중량 집계<br>(본수, 연장, 규격별 중량 산출)"]
end
subgraph Step4["4단계: 3D 인터랙션 및 BIM 내보내기 (Interoperability)"]
RebarGen --> Interactive3D["Three.js 기반 3D 웹 뷰어 표출<br>(부재별 격리, 텍스트 라벨링)"]
Interactive3D --> Export["BIM 엔지니어링 포맷 내보내기<br>(OBJ / STL / 3D DXF / CSV / JSON)"]
end
```
---
## 3. 단계별 상세 기능 및 알고리즘 메커니즘
### 1단계: 도면 불러오기 및 도면 종류 판별
다양한 프로젝트의 도면 파일을 수용할 수 있도록 유연한 업로드 파이프라인과 규칙 기반 자동 분류기를 제공합니다.
#### 1) 도면 자동 판별 알고리즘
- **일반도 자동 분류**: 파일명에 `'일반'` 키워드가 포함된 경우 구조물 외형 및 치수를 표현하는 일반도(`GENERAL`)로 자동 분류합니다.
- **배근도/구조도 자동 분류**: 파일명에 `'배근'` 또는 `'구조'` 키워드가 포함된 경우 내부 철근 배치 정보를 담은 구조도(`REBAR`)로 자동 분류합니다.
- **미분류 및 대화형 수동 지정**: 도면명 규칙이 상이하여 키워드가 검출되지 않는 도면(`UNCLASSIFIED`)은 사용자에게 수동 분류 선택 UI를 제공하여 즉시 지정할 수 있습니다.
#### 2) 2D CAD 벡터 뷰어
- 업로드된 DWG/DXF 파일의 벡터 엔티티(LINE, LWPOLYLINE, ARC, TEXT, DIMENSION 등)를 브라우저 Canvas에 정밀 투영합니다.
- 도면 레이어별 On/Off 제어, 마우스 휠 줌(Zoom) 및 드래그 팬(Pan)을 통해 입력 도면의 원본 상태를 시각적으로 검증할 수 있습니다.
---
### 2단계: 일반도 기반 암거 및 날개벽 3D 외형 모델링
일반도의 평면도 및 단면도를 분석하여 암거와 날개벽의 기하학적 형태를 3차원 솔리드 메시로 생성합니다.
#### 1) 암거 본체 기하 자동 인식
- 평면도 내의 중심 기준선 및 콘크리트 외곽선, 점선 레이어 패턴을 분석하여 암거 본체의 **내공 스팬(Span), 형하고(Clear Height), 본체 외폭, 암거 사각(Skew Angle), 연장(Length)**을 자동으로 추출합니다.
#### 2) 날개벽 위치 판별 및 동적 위상 제어
- 암거 본체를 기준으로 4개 영역(시점부 좌/우, 종점부 좌/우)의 날개벽 배치 상태를 판별합니다.
- **도면 기반 모델링 원칙**:
- 도면에 표기된 날개벽 위치는 누락 없이 정밀 모델링합니다.
- 도면에 표기되지 않은 위치는 임의 생성하지 않고 모델링에서 제외합니다.
- 다양한 현장 조건(양측 날개벽, 일측 날개벽, 무날개벽 등)을 웹 UI 제어기를 통해 실시간으로 선택 및 시뮬레이션할 수 있습니다.
#### 3) 단면 보간 및 완전 폐합 수밀 메시(Watertight Solid) 생성
- 날개벽의 시점부 단면(암거 접합부)과 종점부 단면(천단부)의 기하 치수(벽체 두께, 높이, 저판 폭, 헌치 등)를 선형/곡선 가변 보간(Lofting)합니다.
- 3D 프린팅 및 BIM 솔리드 기준을 만족하는 **Open Edge 0건의 2-Manifold 방수(Watertight) 메시**를 구축하고, 미소 삼각 요소를 수치 적분하여 **콘크리트 총체적(Volume)**을 실시간 자동 계산합니다.
---
### 3단계: 구조도 기반 날개벽 내부 3D 철근 배근 및 물량 집계
구조도에서 추출된 철근 가공조립표(Bar Bending Schedule) 및 단면 배근도를 3차원 공간 좌표계로 투영하여 정밀 배근 모델을 구축합니다.
#### 1) 철근 카테고리별 3차원 공간 배치 알고리즘
- **우각부 사각 보강근**: 암거 본체와 날개벽이 접하는 우각부의 응력 집중을 방어하는 사각 절곡 정착근을 경사 각도에 맞춰 3D 배치합니다.
- **벽체 수직 주철근**: 저판 기초 내부 정착 후크를 포함한 수직 주철근을 피복두께를 고려하여 지정 간격 및 교대 사이클에 맞춰 입체 배열합니다.
- **벽체 수평 배력철근**: 날개벽 경사 변화에 맞춰 하부 연속 구간과 상부 가변 구간, 천단 경사 연단근을 단계별로 가변 배치합니다.
- **저판 주철근 및 배력철근**: 저판 폭 변화 및 구배에 맞추어 상·하면 주철근(양단 후크 포함)과 종방향 배력철근을 입체 구성합니다.
- **헌치 및 전단 보강근**: 벽체와 저판이 만나는 취약부 헌치 보강근 및 결속 타이바/스터럽을 자동 생성합니다.
#### 2) 피복두께 준수 및 물량 자동 산출
- 콘크리트 외형 표면으로부터 법선 방향으로 **설계 피복두께(Cover Thickness)**를 엄격히 감산하여 철근이 외형 밖으로 돌출되지 않도록 기하학적 제약 조건을 적용합니다.
- 배근된 모든 철근의 규격(D13, D16, D19, D22 등), 본수, 본당 길이, 할증률을 반영한 **총연장(Total Length) 및 총중량(Total Weight)**을 실시간 집계합니다.
---
### 4단계: BIM 데이터 및 철근 가공조립표 내보내기
생성된 3D 모델과 물량 데이터를 외부 상용 CAD, BIM 소프트웨어, 견적 프로그램과 연계할 수 있는 표준 규격으로 내보냅니다.
| 포맷 | 파일 유형 | 호환성 및 활용 분야 |
| :--- | :--- | :--- |
| **OBJ** | 3D 형상 + 철근 폴리라인 | Blender, 3ds Max, Rhino 등 범용 3D 그래픽 및 시각화 도구 |
| **STL** | 삼각망 수밀 솔리드 | 3D 프린팅 슬라이서, 지반-구조 상호작용 수치해석 프로그램 |
| **3D DXF** | AutoCAD 3D Face / Polyline | AutoCAD, Civil 3D 등 CAD 프로그램에서 레이어별 3D 검토 |
| **CSV** | 철근 가공조립표 (BBS) | Excel 등 스프레드시트 호환 규격별·부재별 철근 집계표 |
| **JSON** | 기하 및 속성 메타데이터 | 웹 API 연동, 외부 BIM 플랫폼 커스텀 데이터 파이프라인 |
---
## 4. 화면 조작 인터랙션 가이드
웹 브라우저 환경에서 엔지니어가 3D 모델을 직관적으로 검토할 수 있는 다양한 상호작용 기능을 제공합니다.
### 1) 3D 뷰포트 카메라 제어
- **회전 (Orbit)**: 마우스 좌클릭 드래그로 모델 주위를 자유롭게 회전합니다.
- **이동 (Pan)**: 마우스 우클릭 드래그(또는 Shift + 좌클릭)로 카메라 시점을 수평/수직 이동합니다.
- **확대/축소 (Zoom)**: 마우스 휠 스크롤로 관심 영역을 확대하거나 축소합니다.
### 2) 부재 및 철근 상호작용
- **부재 선택 (2단계)**: 암거 본체 또는 좌/우 날개벽을 직접 클릭하면 해당 부재가 강조 표시되며 상세 치수 카드가 나타납니다.
- **철근 격리 표출 (3단계 Isolate Mode)**: 좌측 사이드바에서 특정 철근 기호를 선택하면 해당 철근군만 선명하게 단독 표출되고, 타 철근 및 콘크리트 외형은 반투명 고스트(Ghost) 모드로 전환되어 간섭 여부를 즉시 확인할 수 있습니다.
- **거리 비례 3D 라벨링**: 줌 인/아웃 시 카메라 거리에 비례하여 철근 기호 텍스트의 크기가 자동으로 보정되어 항상 선명한 가독성을 유지합니다.
---
## 5. 설치 및 실행 방법
### 환경 요구사항
- **Python**: 3.10 이상 권장
- **웹 브라우저**: WebGL 2.0을 지원하는 최신 브라우저 (Chrome, Edge, Firefox, Safari)
### 의존 패키지 설치
```bash
pip install -r requirements.txt
```
---
### 실행 모드 (3가지 방식 지원)
#### [모드 1] 로컬 웹 서버 실행 (권장)
- 백엔드 서버를 구동하여 동적 도면 업로드, 실시간 3D 변환, 파일 내보내기 전체 기능을 사용합니다:
```powershell
python app.py
```
- 구동 후 브라우저에서 `http://127.0.0.1:5000/` 에 접속합니다.
#### [모드 2] 독립형 정적 브라우저 실행 (서버 불필요)
- [`index.html`](index.html) 파일을 웹 브라우저로 직접 열어 실행합니다.
- `static/data/`의 번들 데이터를 활용하여 서버 설치 없이 오프라인 환경에서도 1~3단계 3D 뷰어와 인터랙션을 시연할 수 있습니다.
#### [모드 3] Linux / WSL2 환경 실행
- Linux 및 WSL2 환경에서는 제공된 쉘 스크립트로 간편하게 구동할 수 있습니다:
```bash
bash run_wsl.sh
```
---
## 6. 프로젝트 디렉터리 구조
```text
Code/3d-drawing/
├── cad_parser.py # 2D DWG/DXF 도면 파싱 및 종류 판별
├── model_3d.py # 3D 수로암거 및 날개벽 파라메트릭 솔리드 모델러
├── rebar_model.py # 3D 철근 배근 생성기 (19종 기호, 508본)
├── exporters.py # OBJ / STL / DXF 3D 파일 내보내기 모듈
├── bundle_data.py # 도면 및 3D 데이터 번들링 유틸리티
├── app.py # Flask 웹 REST API 서버
├── index.html # Three.js 기반 3D CAD/BIM 웹 뷰어
├── static/ # CSS, JS(app.js, viewer3d.js), Three.js 라이브러리 및 데이터
├── run_wsl.sh # WSL2 원클릭 실행 스크립트
├── test_pipeline.py # 파이프라인 전수 자동화 검증 테스트
├── requirements.txt # Python 패키지 의존성
└── README.md # 본 설명서
├── app.py # Flask 백엔드 REST API 서버
├── cad_parser.py # ezdwg 기반 DWG/DXF 파서 및 자동 분류기
├── model_3d.py # 암거 및 날개벽 3D 외형 솔리드 모델러
├── rebar_model.py # 구조도 기반 3D 철근 배근 및 물량 산출 엔진
├── exporters.py # OBJ / STL / 3D-DXF / CSV 내보내기 변환기
├── bundle_data.py # 서버리스 정적 구동용 데이터 번들러
├── index.html # Three.js 프론트엔드 단일 페이지 웹 애플리케이션 (SPA)
├── requirements.txt # 필수 파이썬 라이브러리 목록
├── static/
│ ├── css/ # 반응형 UI 레이아웃 스타일시트
│ ├── js/ # 3D 렌더러, 2D 벡터 캔버스, UI 상태 관리 스크립트
│ ├── libs/ # Three.js 및 컨트롤러 라이브러리
│ └── data/ # 정적 오프라인 구동용 번들 데이터
├── DOC/ # 개발 및 기능 검증 기술 문서
└── README.md # 본 시스템 종합 명세서
```
---
## 3. 원클릭 실행 방법
## 7. 자동화 파이프라인 검증 체계
### 3.1. Windows 환경 (권장)
최상위 폴더 또는 `Code/3d-drawing/` 내의 실행 파일을 더블클릭합니다:
- **`[실행]_암거및날개벽_3D외형배근모델러.bat`**: 백엔드 서버(WSL2 또는 Windows Python) 자동 기동 및 웹 브라우저(`http://localhost:5000`) 자동 오픈
- **`[실행바로가기]_암거및날개벽_3D외형배근모델러.lnk`**: 윈도우 바로가기 아이콘
- **`[바로가기]_3D모델러_웹접속.url`**: 서버 동작 중 브라우저 즉시 열기
### 3.2. WSL2(Ubuntu) 터미널 환경
WSL2(Ubuntu) 터미널에서 아래 명령을 실행합니다:
본 시스템은 다양한 도면 변환 작업의 정확성을 유지하기 위해 자동화된 검증 파이프라인을 내장하고 있습니다.
### 테스트 실행
```bash
cd Code/3d-drawing
chmod +x run_wsl.sh
./run_wsl.sh
python test_pipeline.py
```
실행 후 웹 브라우저에서 아래 주소로 접속합니다:
- **`http://localhost:5000`** 또는 **`http://127.0.0.1:5000`**
---
## 4. 자동 테스트 및 검증 실행
```bash
cd Code/3d-drawing
~/.venv-3d-drawing/bin/python test_pipeline.py
```
### 주요 검증 항목
1. **도면 분류 무결성**: 다양한 도면명 키워드 패턴에 대한 자동 분류 정확도 및 예외 도면 처리 검증
2. **외형 솔리드 수밀성**: 3D 메시의 비공유 변(Open Edge) = 0, Non-manifold 요소 = 0 무결성 검증
3. **철근 배근 정밀도**: 철근 재료표 수량과 3D 생성 인스턴스 간의 본수, 길이, 중량 100% 일치성 검증
4. **엔지니어링 내보내기 검증**: 생성된 OBJ, STL, DXF, CSV 파일의 문법 및 외부 CAD 호환성 검증
-4
View File
@@ -1,4 +0,0 @@
[InternetShortcut]
URL=http://localhost:5000/
IconIndex=13
IconFile=C:\Windows\System32\shell32.dll
@@ -1,74 +0,0 @@
@echo off␍
chcp 65001 > nul␍
setlocal␍
title 암거 및 날개벽 3D 모델러␍
␍
echo ===============================================================================␍
echo [암거 및 날개벽 3D 외형·배근 모델러] 원클릭 실행기␍
echo - 프로젝트: 대산-당진 수로암거 (STA.13+611.21)␍
echo - 2단계 일반도 외형 / 3단계 배근도 철근 3D 모델링␍
echo ===============================================================================␍
echo.␍
␍
set "SCRIPT_DIR=%~dp0"␍
if exist "%SCRIPT_DIR%Code\3d-drawing\app.py" (␍
set "WORK_DIR=%SCRIPT_DIR%Code\3d-drawing"␍
) else (␍
set "WORK_DIR=%SCRIPT_DIR%"␍
)␍
␍
REM 1. 서버 실행 여부 점검 (포트 5000)␍
netstat -ano | findstr /R ":5000.*LISTENING" > nul 2>&1␍
if %ERRORLEVEL% equ 0 (␍
echo [안내] 백엔드 웹 서버가 이미 정상 동작 중입니다.␍
echo [접속] 기본 웹 브라우저를 실행합니다: http://localhost:5000/␍
start "" http://localhost:5000/␍
goto done␍
)␍
␍
REM 2. 서버 미실행 시 백엔드 구동␍
echo [*] 백엔드 웹 서버가 중지되어 있습니다. 서버 구동을 시작합니다...␍
␍
REM WSL2 환경 확인 및 구동 시도␍
where wsl > nul 2>&1␍
if %ERRORLEVEL% equ 0 (␍
echo [*] WSL2(Ubuntu) 가상환경을 감지하였습니다. WSL2 백그라운드 서버를 실행합니다...␍
start /min "3D Drawing Server (WSL2)" wsl -d Ubuntu bash -c "cd '/mnt/e/11. 2026 PROJECT/30 도면을 3D로 구현/01 대산당진_수로암거(STA13+611)_옹벽형날개벽/Code/3d-drawing' && ./run_wsl.sh"␍
goto wait_loop␍
)␍
␍
REM WSL2가 없을 경우 Windows Python 환경으로 구동␍
echo [*] Windows Python 환경으로 웹 서버를 실행합니다...␍
cd /d "%WORK_DIR%"␍
start /min "3D Drawing Server" python app.py␍
␍
:wait_loop␍
echo [*] 서버 초기화 및 기동 대기 중...␍
set retry=0␍
␍
:check_port␍
ping -n 2 127.0.0.1 > nul␍
netstat -ano | findstr /R ":5000.*LISTENING" > nul 2>&1␍
if %ERRORLEVEL% equ 0 (␍
echo [성공] 서버 기동 완료! (포트 5000 활성화됨)␍
echo [접속] 기본 웹 브라우저를 실행합니다: http://localhost:5000/␍
start "" http://localhost:5000/␍
goto done␍
)␍
␍
set /a retry=%retry%+1␍
if %retry% lss 10 (␍
goto check_port␍
)␍
␍
echo [주의] 서버 기동 대기 시간이 초과되었습니다. 브라우저를 열어 확인합니다...␍
start "" http://localhost:5000/␍
␍
:done␍
echo.␍
echo ===============================================================================␍
echo 실행이 완료되었습니다. 웹 브라우저에서 3D 모델을 확인하실 수 있습니다.␍
echo - 웹 접속 주소: http://localhost:5000/␍
echo ===============================================================================␍
echo.␍
ping -n 3 127.0.0.1 > nul␍
-40
View File
@@ -1,40 +0,0 @@
#!/usr/bin/env bash
# ==============================================================================
# DWG 도면 기반 3D 모델링 및 웹 뷰어 실행 스크립트 (WSL2 / Ubuntu 환경)
# ==============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
VENV_PATH="$HOME/.venv-3d-drawing"
echo "======================================================================"
echo " [3D Drawing Converter & Viewer] WSL2(Ubuntu) 실행 환경 초기화"
echo "======================================================================"
# 1. 가상환경 확인 및 필요 시 자동 생성
if [ ! -f "$VENV_PATH/bin/python" ]; then
echo ">> 가상환경이 존재하지 않아 생성 중: $VENV_PATH"
python3 -m venv "$VENV_PATH"
"$VENV_PATH/bin/pip" install --upgrade pip
"$VENV_PATH/bin/pip" install -r requirements.txt
fi
echo ">> Python 가상환경 활성화: $VENV_PATH"
source "$VENV_PATH/bin/activate"
# 2. 필수 의존성 검증
python -c "import flask, flask_cors, ezdxf, ezdwg, numpy; print('>> 모든 필수 패키지 검증 완료 (flask, ezdxf, ezdwg, numpy)')"
# 3. Flask 웹 서버 기동
PORT=${PORT:-5000}
HOST=${HOST:-0.0.0.0}
echo "----------------------------------------------------------------------"
echo ">> 3D 도면 뷰어 웹 서버를 실행합니다..."
echo ">> 접속 주소: http://localhost:$PORT / http://127.0.0.1:$PORT"
echo ">> 종료하려면 Ctrl+C 를 누르세요."
echo "----------------------------------------------------------------------"
exec python app.py
-176
View File
@@ -1,176 +0,0 @@
#!/usr/bin/env python3
"""
Comprehensive End-to-End Pipeline Verification Test
Verifies 2D drawing classification, DWG parsing, 3D solid & rebar modeling,
mesh watertightness, exporter functionality, and Flask API endpoints.
"""
import os
import json
import unittest
import cad_parser
import model_3d
import rebar_model
import exporters
import app
class Test3DDrawingPipeline(unittest.TestCase):
@classmethod
def setUpClass(cls):
current_dir = os.path.dirname(os.path.abspath(__file__))
cls.project_root = os.path.abspath(os.path.join(current_dir, '..', '..'))
cls.rag_dir = os.path.join(cls.project_root, 'RAG')
cls.general_dwg = os.path.join(cls.rag_dir, '13. 수로암거 일반도(STA.13+611.21)(02).dwg')
app.app.testing = True
cls.flask_app = app.app.test_client()
def test_01_drawing_classification(self):
"""1.2 도면 종류 키워드 기반 자동 판별 검증"""
# 일반도 판별
res_gen = cad_parser.classify_drawing_by_name('13. 수로암거 일반도(STA.13+611.21)(02).dwg')
self.assertEqual(res_gen['auto_type'], 'GENERAL')
self.assertEqual(res_gen['matched_keyword'], '일반')
self.assertFalse(res_gen['needs_manual_selection'])
# 배근도/구조도 판별
res_rebar1 = cad_parser.classify_drawing_by_name('14. 수로암거 구조도(STA.13+611.21, 종점 우)(01).dwg')
self.assertEqual(res_rebar1['auto_type'], 'REBAR')
self.assertIn('구조', res_rebar1['matched_keyword'])
self.assertFalse(res_rebar1['needs_manual_selection'])
res_rebar2 = cad_parser.classify_drawing_by_name('날개벽 배근도(종점 좌).dwg')
self.assertEqual(res_rebar2['auto_type'], 'REBAR')
self.assertIn('배근', res_rebar2['matched_keyword'])
# 미분류 도면
res_unclass = cad_parser.classify_drawing_by_name('기타 도면#01.dwg')
self.assertEqual(res_unclass['auto_type'], 'UNCLASSIFIED')
self.assertTrue(res_unclass['needs_manual_selection'])
def test_02_dwg_parsing(self):
"""1.1 DWG 도면 파싱 및 파라미터 추출 검증"""
if not os.path.exists(self.general_dwg):
self.skipTest(f"DWG file not found at {self.general_dwg}")
drawing_data = cad_parser.parse_dwg(self.general_dwg)
self.assertIsNotNone(drawing_data)
self.assertIn('entities', drawing_data)
self.assertIn('structuralParams', drawing_data)
self.assertGreater(len(drawing_data['entities']), 100)
# 수로암거 제원 확인
sp = drawing_data['structuralParams']
self.assertEqual(sp.get('station'), 'STA.13+611.21')
self.assertAlmostEqual(sp.get('culvert_span', 2.0), 2.0, delta=0.1)
def test_03_3d_solid_modeling_and_watertightness(self):
"""2단계 일반도 기반 3D 외형 모델링 및 수밀성(Watertight) 검증"""
model_res = model_3d.generate_full_model()
self.assertIsNotNone(model_res)
self.assertIn('objects', model_res)
objects = model_res['objects']
self.assertIn('culvert', objects)
self.assertIn('ww_end_left', objects)
self.assertIn('ww_end_right', objects)
# 도면에 없는 시점부 날개벽 임의 생성 차단 확인
self.assertNotIn('ww_start_left', objects)
self.assertNotIn('ww_start_right', objects)
# 수밀성 (Watertight 2-Manifold Mesh) 검증
for part_key in ['culvert', 'ww_end_left', 'ww_end_right']:
part_data = objects[part_key]
vertices = part_data['vertices']
faces = part_data['faces']
self.assertGreater(len(vertices), 0, f"{part_key} has no vertices")
self.assertGreater(len(faces), 0, f"{part_key} has no faces")
# Edge manifold check: Every edge in a watertight 2-manifold closed surface is shared by exactly 2 faces
edge_count = {}
for f in faces:
for i in range(3):
v1, v2 = f[i], f[(i + 1) % 3]
edge = tuple(sorted([v1, v2]))
edge_count[edge] = edge_count.get(edge, 0) + 1
non_manifold = [e for e, count in edge_count.items() if count != 2]
self.assertEqual(len(non_manifold), 0,
f"{part_key} mesh is not watertight! Non-manifold edges: {len(non_manifold)}")
def test_04_3d_rebar_modeling(self):
"""3단계 구조도/배근도 기반 날개벽 내부 3D 철근 배근(508본) 검증"""
rebar_data = rebar_model.generate_full_rebar_model()
self.assertIsNotNone(rebar_data)
self.assertIn('wingwalls', rebar_data)
self.assertIn('summary', rebar_data)
summary = rebar_data['summary']
total_bars = summary.get('total_bars', 0)
self.assertEqual(total_bars, 508, f"Expected 508 total rebars, got {total_bars}")
# 좌측(231본) 및 우측(277본) 검증
left_bars = summary.get('left_bars', 0)
right_bars = summary.get('right_bars', 0)
self.assertEqual(left_bars, 231)
self.assertEqual(right_bars, 277)
# W1 철근 3D 형상 검증: 벽체-저판 접합부에서 꺾이지 않고 저판 하면에서 1회만 꺾이는 ㄱ자 형상(3개 정점) 확인
for ww_key in ['WW_END_LEFT', 'WW_END_RIGHT']:
ww_groups = rebar_data['wingwalls'][ww_key]['groups']
w1_group = next((g for g in ww_groups if g['mark'] == 'W1'), None)
self.assertIsNotNone(w1_group)
for poly in w1_group['polylines']:
self.assertEqual(len(poly), 3, f"{ww_key} W1 bar must have 3 points (1 bend at footing bottom)")
# 저판 하면 구간(poly[0] -> poly[1]) 동일 Z 표고 유지
self.assertAlmostEqual(poly[0][2], poly[1][2], places=4)
# 벽체 긴 구간(poly[1] -> poly[2]) 접합부 꺾임 없이 일직선 연장 확인
self.assertAlmostEqual(poly[1][0], poly[2][0], places=4)
self.assertAlmostEqual(poly[1][1], poly[2][1], places=4)
def test_05_exporters(self):
"""3D 모델 OBJ, STL, DXF 내보내기 검증"""
model_res = model_3d.generate_full_model()
obj_str = exporters.export_obj(model_res)
self.assertIn('v ', obj_str)
self.assertIn('f ', obj_str)
stl_str = exporters.export_stl(model_res)
self.assertIn('solid ', stl_str)
self.assertIn('facet normal', stl_str)
dxf_str = exporters.export_dxf_3d(model_res)
self.assertIn('SECTION', dxf_str)
self.assertIn('ENTITIES', dxf_str)
csv_str = exporters.export_rebar_bom_csv(model_res)
self.assertIn('구분(날개벽)', csv_str)
self.assertIn('기호(Mark)', csv_str)
def test_06_flask_web_endpoints(self):
"""Flask API 및 웹 엔드포인트 응답 검증"""
# 1. 메인 웹페이지
r_index = self.flask_app.get('/')
self.assertEqual(r_index.status_code, 200)
r_index.close()
# 2. 기본 도면 데이터 조회 API
r_def = self.flask_app.get('/api/default-drawing')
self.assertEqual(r_def.status_code, 200)
data_def = json.loads(r_def.data)
self.assertEqual(data_def.get('status'), 'success')
# 3. 도면 분류 API
r_cls = self.flask_app.post('/api/classify',
data=json.dumps({'drawingName': '13. 수로암거 일반도.dwg'}),
content_type='application/json')
self.assertEqual(r_cls.status_code, 200)
data_cls = json.loads(r_cls.data)
self.assertEqual(data_cls['classification']['selectedType'], 'GENERAL')
if __name__ == '__main__':
unittest.main()