# S-CANVAS > **Generative Design & Visualization Engine** > CAD 도면(DXF) · 공개 DEM · 위성영상 · Generative AI 를 결합해 **건설/토목 프로젝트의 3D 조감도와 구조물 시각화**를 자동 생성하는 데스크톱 엔진. **Saman Corp.** 자체 개발. [![Python](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/) [![Platform](https://img.shields.io/badge/platform-Windows%2010%2F11-lightgrey.svg)]() [![GUI](https://img.shields.io/badge/GUI-CustomTkinter-success.svg)]() [![3D](https://img.shields.io/badge/3D-PyVista%20%2B%20VTK-orange.svg)]() --- ## 1. 프로그램 개요 S-CANVAS 는 토목·건설 도면(DXF)을 **클릭 4번**에 사실 기반 3D 조감도로 변환하는 자동 파이프라인입니다. ``` [DXF 도면] [최종 결과물] │ ▲ ▼ │ 레이어 분류 → 등고선/구조물 분리 AI 렌더링 (구조 보존) │ ▲ ▼ │ TIN 생성 (Delaunay 삼각화) ← 제어맵 추출 (Depth + Texture) │ ▲ ▼ │ DEM 자동 페치 (AWS Terrarium) → smoothstep blend │ │ │ ▼ │ 구조물 자동 빌드 (4단계): │ ① 위치 인식 (PCA frame) │ ② 굴착 pad + smoothstep 전이 │ ③ TIN 재-Delaunay (수정된 지형) │ ④ 3D 메시 배치 (취수탑/옹벽/수문/제수변실) │ │ │ ▼ │ 위성 타일 UV 매핑 (Seam-free 통합 메시) ────────────────────┘ ``` ### 1.1 핵심 진입점 - **`scanvas_maker.py`** — 메인 GUI 엔트리 (~6,300 LOC, CustomTkinter 기반) - **`splash.py`** — 인트로 MP4 스플래시 (cv2 + Tk Toplevel) - 메인 클래스: `SCanvasApp(ctk.CTk)` — 사이드바 워크플로 + 메인 맵뷰 - 상태 저장: `%LOCALAPPDATA%\S-CANVAS\` (DB · 로그 · 캐시) ### 1.2 모듈 구성 | 모듈 | 역할 | |---|---| | `scanvas_maker.py` | 메인 GUI, Step 1~4 워크플로 | | `dem_extender.py` | AWS Terrarium DEM 페치 + 도넛 링 메시 | | `geo_referencing.py` | 4점 매칭 GeoReferencing | | `structure_placement.py` | 구조물 위치/방향 자동 인식 + TIN 굴착 | | `structure_templates.py` | 구조물 유형 레지스트리 (Registry 패턴) | | `intake_tower_*.py` | 취수탑 파서 + 3D 빌더 | | `retaining_wall_*.py` | 옹벽 파서 + 3D 빌더 | | `gate_*.py` | 수문 파서 + 3D 빌더 | | `valve_chamber_*.py` | 제수변실 파서 + 3D 빌더 | | `detail_parser.py` | 상세도면 DXF 치수 파서 (TEXT/MTEXT/DIMENSION) | | `filename_classifier.py` | 파일명 → 구조물 유형 추정 | | `dxf_geometry.py` | DXF 엔티티 → 좌표 추출 | | `tile_downloader.py` | 위성 XYZ 타일 다운로드 | | `gemini_renderer.py` | Gemini API/Vertex AI 렌더링 워커 | | `structure_vlm_feedback.py` | Gemini Vision 기반 구조물 결과 검증 | | `harness/` | 품질·재현성·이력 서브시스템 (SQLite + structlog) | ### 1.3 주요 기능 - **TIN 자동 생성**: DXF 등고선 → Delaunay 삼각화 → zero-basing - **DEM 자동 확장**: 도면 범위 밖을 AWS 글로벌 DEM 으로 자동 채움 (3-Zone smoothstep 블렌드) - **구조물 자동 빌드**: 도면 → 4단계 (위치인식 → 굴착 → TIN수정 → 3D배치). 취수탑·옹벽·수문·제수변실 - **Seam-free 통합 메시**: `merge_points=True` + `compute_normals(feature_angle=180)` 로 도면-DEM 경계 쉐이딩 불연속 제거 - **위성 타일 UV 매핑**: Google / ArcGIS / Bing / Vworld 등 9종 지원 - **AI 조감도 렌더링**: Gemini (Vertex / API Key) + Stability AI 3단계 폴백 - **VLM 피드백 루프**: Gemini Vision 으로 빌더 결과 ↔ 원본 도면 자동 검증 - **결정론적 재현성 (Harness)**: DXF 해시 → seed → 같은 입력 → 같은 출력 - **자동 품질 검증**: OpenCV 기반 해상도/선명도/채도 게이트 ### 1.4 구조물 자동 빌드 워크플로 (핵심 차별화) 위성지도 결합 **이전** 에 실행되어 TIN 자체를 수정합니다. 구조물이 자연스럽게 지형에 묻히도록 4단계로 처리: | 단계 | 내용 | 핵심 모듈 | |---|---|---| | **① 위치 인식** | DXF 폴리곤 추출 → PCA 로 frame 방향 결정 | `structure_placement.py` (`compute_orientation_from_points`) | | **② 굴착 (Excavation)** | 폴리곤 평탄 pad + smoothstep 전이 — 구조물 발자국 영역만 매끈하게 | `structure_placement.py` (`apply_placement`) | | **③ TIN 수정** | 굴착된 영역으로 Delaunay 재계산 → 메시 재구성 | `scanvas_maker.py` 내부 | | **④ 3D 메시 배치** | 4개 quad 코너에 fit + `embed_offset` 으로 TIN 관통 방지 | `structure_placement.py` (`fit_meshes_to_quad`) | **지원 구조물 4종** (`structure_types/structure_v1.yaml` 정의): | 유형 | 빌더 | 입력 | |---|---|---| | 취수탑 (Intake Tower) | `intake_tower_3d_builder.py` | DXF 평면도 → 외곽 폴리곤 + 높이 | | 옹벽 (Retaining Wall) | `retaining_wall_3d_builder.py` | DXF 단면도 → 단면 형상 + 길이 | | 수문 (Gate) | `gate_3d_builder.py` | DXF 정면도 → 게이트 + 슬라브 | | 제수변실 (Valve Chamber) | `valve_chamber_3d_builder.py` | DXF 평면도 → 박스 + 슬래브 + 점검구 | **자동 분류**: `filename_classifier.py` 가 파일명 (예: "신설 취수탑.dxf") 으로 1차 후보 제시 → 사용자가 GUI 다이얼로그에서 최종 확정 → `structure_templates.REGISTRY` 가 적절한 빌더로 라우팅. **치수 자동 추출**: `detail_parser.py` 가 DXF TEXT/MTEXT/DIMENSION 엔티티에서 치수값 파싱 → 빌더 파라미터로 변환 (수동 입력 불필요). **메시 방향 보정** (디버깅에서 얻은 교훈): - CW(시계방향) picks + Y-flip + detail/TIN 상대회전 + PCA frame_angle - → 앞뒤 뒤집힘 / 좌우 반전 문제 자동 해결 **VLM 검증 루프**: 빌드 완료 후 `structure_vlm_feedback.py` 가 렌더 결과와 원본 DXF 평면도를 Gemini Vision 에 동시 전송 → 차이점 자연어 응답 → 사용자가 재시도 결정. --- ## 2. 필수 Package ### 2.1 시스템 요구사항 - **Python**: 3.9+ (권장 3.11+, 빌드 머신 검증 = 3.9.13) - **Platform**: Windows 10/11 (Linux/macOS 는 GUI 일부 제한) - **메모리**: 8GB+ (PyVista + VTK + 위성 타일 캐시) - **디스크**: 1GB+ 여유 (DEM/타일 캐시 포함) ### 2.2 설치 ```bash pip install -r requirements.txt ``` ### 2.3 카테고리별 패키지 ```text [GUI] customtkinter==5.2.2 모던 Tk 기반 GUI 프레임워크 tkintermapview==1.29 위성 지도 인터랙티브 뷰 Pillow==11.3.0 이미지 처리 (PIL) [3D / Mesh] pyvista==0.46.5 메시 처리 + 렌더링 (VTK 자동 설치, ~150MB) [Geospatial / DXF] ezdxf==1.4.2 DXF 파싱 (R12~R2024) pyproj==3.6.1 좌표계 변환 (EPSG) rasterio==1.4.3 (선택) 로컬 GeoTIFF DEM (NGII 5m 등) [Numerical] numpy==2.0.2 scipy==1.13.1 Delaunay 삼각화, KDTree matplotlib==3.9.4 signed-distance polygon paths [Image / Video] opencv-python==4.13.0.92 인트로 MP4 + Harness QualityValidator [Network] requests==2.32.5 HTTP 타일/DEM/AI 페치 [AI Rendering] google-genai==1.47.0 Gemini SDK (Vertex AI / API Key 통합) google-auth==2.49.2 [Persistence / Logging] SQLAlchemy==2.0.49 JobRecord ORM structlog==25.5.0 구조화 로깅 PyYAML==6.0.3 prompt_v*.yaml / structure_v*.yaml [Build (선택)] pyinstaller==6.18.0 Windows .exe 빌드 ``` --- ## 3. 간단 사용법 ### 3.1 실행 ```bash python scanvas_maker.py ``` 실행 흐름: 1. `splash.py` 가 `Design/logo_intro.mp4` 8초 인트로 재생 (페이드 인/아웃) 2. `SCanvasApp` 메인 창 기동 (1200×900) 3. 사이드바에서 워크플로 진행 ### 3.2 사이드바 워크플로 ``` SETTINGS ├─ Satellite Source (Google / ArcGIS / Vworld 등 선택) ├─ Vworld API Key (Vworld 사용 시) ├─ AI Engine (Gemini Vertex / Gemini API / Stability) ├─ GCP / API Key (선택한 엔진의 인증 정보) └─ Project CRS (EPSG:5187 / 5186 / 5185 / 5181 / 3857) WORKFLOW 1. TIN 생성 (DXF) ← DXF 파일 선택 + Delaunay 삼각화 🎯 TIN 이용 범위 ← (선택) 정밀 보존 영역 지정 1.5 DEM 으로 TIN 확장 ← AWS Terrarium 도넛 링 메시 추가 ── 구조물 상세 3D 빌드 ← 위치인식 → 굴착 → TIN수정 → 3D배치 (취수탑·옹벽·수문·제수변실) 2. 위성지도 결합 ← 위성 타일 다운로드 + UV 매핑 (구조물 굴착 반영된 TIN 위에 매핑) 3. 제어맵 추출 ← Depth / Texture 캡처 (PyVista offscreen) 4. AI 렌더링 ← 최종 조감도 생성 (Gemini / Stability) OPTIONS ├─ □ 와이어프레임 보기 ├─ 뷰 버퍼 (%) (Step 2/3 외곽 여유) ├─ □ 지형 확장 (DEM) └─ Light / Dark 테마 토글 ``` ### 3.3 결과 파일 | 파일 | 의미 | |---|---| | `rendered_birdseye.png` | 최종 AI 렌더 결과 | | `capture_textured.png` | Step 3 위성+DEM 합성 control map | | `depth_map.png` | Step 3 깊이 맵 | | `lineart_map.png` | Step 3 라인아트 | | `guide_composite.png` | 합성 가이드 이미지 | | `scanvas_jobs.db` | SQLite 작업 이력 (Harness) | | `scanvas_harness.log` | structlog 출력 | ### 3.4 인증 / API 키 설정 **모든 키는 코드에 하드코딩되지 않습니다.** 환경변수 또는 사이드바 입력란을 사용하세요. | 키 | 환경변수 | 발급처 | 용도 | |---|---|---|---| | GCP Service Account | (파일) `gcp-key.json` | GCP Console → IAM | Gemini Vertex AI | | GCP Project ID | `GCP_PROJECT_ID` | (gcp-key.json 자동 추출) | Vertex AI 라우팅 | | GCP Location | `GCP_LOCATION` | — | Vertex AI 리전 (기본 `global`) | | Gemini API Key | (UI 입력) | [aistudio.google.com](https://aistudio.google.com/) | Gemini API 직접 호출 | | Stability API Key | (UI 입력) | [platform.stability.ai](https://platform.stability.ai/) | Stability AI 폴백 | | **Vworld API Key** | **`VWORLD_API_KEY`** | [vworld.kr/dev](https://www.vworld.kr/dev/v4api.do) | 한국 위성 타일 (선택) | | Google API Key (VLM) | `GOOGLE_API_KEY` 또는 `GEMINI_API_KEY` | aistudio.google.com | structure_vlm_feedback | **Windows 환경변수 설정 예**: ```powershell # 영구 (사용자 환경) [Environment]::SetEnvironmentVariable("VWORLD_API_KEY", "your-key-here", "User") [Environment]::SetEnvironmentVariable("GCP_PROJECT_ID", "your-project-id", "User") # 현재 세션만 $env:VWORLD_API_KEY = "your-key-here" ``` **Gemini Vertex AI (서비스 어카운트)**: 1. GCP 프로젝트에서 서비스 어카운트 키 (JSON) 발급 2. `gcp-key.json` 을 프로젝트 루트 또는 `%LOCALAPPDATA%\S-CANVAS\` 에 배치 3. 자동으로 `GOOGLE_APPLICATION_CREDENTIALS` 설정 + `project_id` 추출 4. **`gcp-key.json` 은 `.gitignore` 차단됨** — 절대 커밋 금지 --- ## 4. URL 기반 외부 데이터 소스 S-CANVAS 가 사용하는 모든 외부 URL 엔드포인트입니다. **인터넷 연결 필요**. ### 4.1 DEM (지형 고도) — 인증 불필요 | 소스 | URL 패턴 | 비고 | |---|---|---| | AWS Open Terrain Tiles | `https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png` | 글로벌, ~30m 정확도, **API 키 없음**. terrarium PNG 디코딩: `elev_m = (R*256 + G + B/256) - 32768`. SHA1(bbox+zoom) 캐시 → 재실행 시 네트워크 0 | `dem_extender.py:48` 에 정의 → `cache/dem/` 에 PNG 캐시. 로컬 GeoTIFF (`cache/dem/local.tif`) 가 있으면 우선 사용 (rasterio 필요). ### 4.2 위성 타일 (Texture) `scanvas_maker.py:248-258` — UI 에서 사용자 선택. | 서버 | URL 패턴 | 인증 | |---|---|---| | Google Satellite | `https://mt{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}` | 불필요 | | Google Hybrid | `https://mt{s}.google.com/vt/lyrs=y&x={x}&y={y}&z={z}` | 불필요 | | ArcGIS World Imagery | `https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}` | 불필요 | | ArcGIS Hybrid | `https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer/tile/{z}/{y}/{x}` | 불필요 | | Bing Aerial | `https://ecn.t{s}.tiles.virtualearth.net/tiles/a{q}.jpeg?g=1` | 불필요 | | OpenStreetMap | `https://tile.openstreetmap.org/{z}/{x}/{y}.png` | 불필요 | | OpenTopo | `https://tile.opentopomap.org/{z}/{x}/{y}.png` | 불필요 | | Vworld 위성 | `https://api.vworld.kr/req/wmts/1.0.0/{vworld_key}/Satellite/{z}/{y}/{x}.jpeg` | **Vworld 키 필요** | | Vworld 기본 | `https://api.vworld.kr/req/wmts/1.0.0/{vworld_key}/Base/{z}/{y}/{x}.png` | **Vworld 키 필요** | | Vworld 하이브리드 | `https://api.vworld.kr/req/wmts/1.0.0/{vworld_key}/Hybrid/{z}/{y}/{x}.png` | **Vworld 키 필요** | `tile_downloader.py:11` 에서 `tile.openstreetmap.org` 폴백 처리. ### 4.3 AI 렌더링 — 인증 필수 | 엔진 | 엔드포인트 | 인증 방식 | |---|---|---| | **Gemini (Vertex AI)** | `google-genai` SDK 내부 호출 | GCP Service Account (`gcp-key.json`) — `GOOGLE_APPLICATION_CREDENTIALS` 자동 설정 | | **Gemini (API Key)** | `google-genai` SDK 내부 호출 | aistudio.google.com 키 | | **Stability Conservative Upscale** | `https://api.stability.ai/v2beta/stable-image/upscale/conservative` | Bearer API Key | | **Stability Creative Upscale** | `https://api.stability.ai/v2beta/stable-image/upscale/creative` | Bearer API Key | | **Stability img2img (sd3.5-large)** | `https://api.stability.ai/v2beta/stable-image/generate/sd3` | Bearer API Key | `scanvas_maker.py:6432` (Conservative/Creative) · `scanvas_maker.py:6477` (img2img) · `gemini_renderer.py` (Gemini 워커). Stability 는 3단계 자동 폴백 (Conservative → Creative → img2img). ### 4.4 위성 지도 미리보기 (GUI) `scanvas_maker.py:572` — `tkintermapview` 의 기본 타일 서버: - `https://mt0.google.com/vt/lyrs=s&x={x}&y={y}&z={z}` GeoReferencing 4점 매칭 시 사용자가 위성 위에 클릭하는 인터랙티브 맵. ### 4.5 캐시 정책 | 캐시 위치 | 내용 | 무효화 키 | |---|---|---| | `cache/dem/` | AWS Terrarium PNG 타일 | SHA1(bbox + zoom) | | `cache/tiles/` | 위성 타일 PNG | URL 해시 | | `scanvas_jobs.db` | SQLite Job 이력 (재현성) | dxf_hash + seed + prompt_hash | **오프라인 동작**: 캐시 hit 시 네트워크 호출 0회. 첫 실행 후 동일 영역은 오프라인 가능. --- ## 5. 좌표계 / 단위 지원 EPSG (사이드바 선택): | EPSG | 이름 | 영역 | |---|---|---| | **5187** | Korea 2000 / Central Belt 2010 | 한국 중부 (서울·경기·충청) — **기본값** | | 5186 | Korea 2000 / Central Belt | 한국 중부 (구) | | 5185 | Korea 2000 / West Belt 2010 | 한국 서부 | | 5181 | Korea 2000 / Unified CS | 통합 좌표계 | | 3857 | Web Mercator | 글로벌 (위성 타일 호환) | **단위 강제**: DXF `$INSUNITS` 헤더가 부정확한 경우가 많아 **항상 m 로 강제** (`unit_override="m"`). KATEC 류 대형 좌표값을 mm 로 오판하는 사고 차단. **Zero-Basing**: 큰 절대좌표(EPSG:5187 의 200,000m+) 의 float32 정밀도 손실 방지 → bbox 좌하단을 origin 으로 평행이동. --- ## 6. 디렉토리 구조 ``` . ├── scanvas_maker.py # 메인 진입점 ├── splash.py # 인트로 스플래시 ├── requirements.txt # 의존성 ├── S-CANVAS_brief.md # 상세 기술 문서 (NotebookLM 소스) ├── CHANGELOG.md # 수정 이력 (역순) │ ├── dem_extender.py # DEM 페치/링 메시 ├── geo_referencing.py # 4점 매칭 ├── structure_placement.py # 구조물 배치/굴착 ├── structure_templates.py # 구조물 레지스트리 ├── intake_tower_parser.py + _3d_builder.py ├── retaining_wall_parser.py + _3d_builder.py ├── gate_parser.py + _3d_builder.py ├── valve_chamber_parser.py + _3d_builder.py ├── detail_parser.py ├── filename_classifier.py ├── polygon_reconstructor.py ├── dxf_geometry.py ├── tile_downloader.py ├── view_detector.py ├── view_reconstructor.py ├── optional_detector.py ├── gemini_renderer.py ├── structure_vlm_feedback.py ├── resource_paths.py # PyInstaller 번들/소스 경로 분기 │ ├── harness/ # 품질·재현성 서브시스템 │ ├── seed_manager.py # DXF 해시 → seed │ ├── quality_validator.py # OpenCV 자동 QA │ ├── prompt_registry.py # YAML 버전 관리 │ └── logger.py # SQLite ORM + structlog │ ├── prompt_templates/ │ └── prompt_v1.yaml # 시간대/앙각/구조보존 프롬프트 │ ├── structure_types/ │ └── structure_v1.yaml # 구조물 유형 정의 │ ├── Design/ # 브랜딩 자산 │ ├── logo_V2.png │ ├── SAMAN_CI.gif │ └── logo_intro.mp4 # 8s, 24fps, 1280×720 │ ├── SAMPLE_CAD/ # 테스트용 DXF 샘플 └── cache/dem/ # 런타임 DEM 캐시 (gitignore) ``` --- ## 7. 추가 문서 - **`S-CANVAS_brief.md`** — 시스템 아키텍처/혁신 포인트/메모리화된 결정 사항 (개발자/리뷰어용 심층 자료) - **`CHANGELOG.md`** — 모든 수정 이력 (역순, 날짜/파일/사유/diff 요지) - **`Build_log.txt`** — 사용자 원본 요청 이력 --- ## 8. 라이선스 / 저작권 © 2026 **Saman Corp.** All rights reserved. 본 프로그램은 Saman Corp. 자체 개발 자산이며, 외부 라이선스가 부여된 패키지는 각 패키지의 라이선스를 따릅니다. 문의: 프로젝트 관리자에게 직접 연락