18 KiB
S-CANVAS
Generative Design & Visualization Engine CAD 도면(DXF) · 공개 DEM · 위성영상 · Generative AI 를 결합해 건설/토목 프로젝트의 3D 조감도와 구조물 시각화를 자동 생성하는 데스크톱 엔진. Saman Corp. 자체 개발.
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 설치
pip install -r requirements.txt
2.3 카테고리별 패키지
[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 실행
python scanvas_maker.py
실행 흐름:
splash.py가Design/logo_intro.mp48초 인트로 재생 (페이드 인/아웃)SCanvasApp메인 창 기동 (1200×900)- 사이드바에서 워크플로 진행
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 | Gemini API 직접 호출 |
| Stability API Key | (UI 입력) | platform.stability.ai | Stability AI 폴백 |
| Vworld API Key | VWORLD_API_KEY |
vworld.kr/dev | 한국 위성 타일 (선택) |
| Google API Key (VLM) | GOOGLE_API_KEY 또는 GEMINI_API_KEY |
aistudio.google.com | structure_vlm_feedback |
Windows 환경변수 설정 예:
# 영구 (사용자 환경)
[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 (서비스 어카운트):
- GCP 프로젝트에서 서비스 어카운트 키 (JSON) 발급
gcp-key.json을 프로젝트 루트 또는%LOCALAPPDATA%\S-CANVAS\에 배치- 자동으로
GOOGLE_APPLICATION_CREDENTIALS설정 +project_id추출 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. 자체 개발 자산이며, 외부 라이선스가 부여된 패키지는 각 패키지의 라이선스를 따릅니다.
문의: 프로젝트 관리자에게 직접 연락