# S-CANVAS — 프로그램 핵심 소개 (NotebookLM 발표자료 소스)

> **목적**: 본 문서는 NotebookLM 에 업로드하여 발표 슬라이드, Audio Overview,
> 마인드맵 등을 자동 생성하기 위한 **단일 소스 텍스트** 입니다. S-CANVAS
> 프로그램의 정체성·아키텍처·핵심 기술·워크플로·차별화 포인트를 한 파일에
> 응축했습니다.

---

## 1. 한 줄 요약

**S-CANVAS** — *Generative Design & Visualization Engine*. CAD 도면(DXF)과 실제
공개 DEM·위성영상·Generative AI 를 결합해 **건설/토목 프로젝트의 3D 조감도와
구조물 시각화**를 자동 생성하는 데스크톱 엔진. **Saman Corp.** 자체 개발.

- 원래 명칭: `EG-VIEW` (AI 기반 조감도 생성 시스템)
- 2026-04-24 리브랜딩: `S-CANVAS` (Generative Design & Visualization Engine)
- 메인 진입점: `scanvas_maker.py`
- 플랫폼: Windows 10/11, Python + CustomTkinter GUI

---

## 2. 배경 & 문제 정의

### 2.1 기존 토목·건설 시각화의 한계

전통적인 CAD 평면도는 **2D**이며, 등고선·구조물 윤곽만 담겨 있어 실제 지형
맥락(주변 산세, 강, 식생, 도로망)이 빠져 있다. 발주처 보고·주민 설명회에서는
**"실제 어떻게 보이는가"** 가 중요하지만, 기존 워크플로에서는:

1. CAD 도면을 3D 모델러(Civil 3D/Revit/Rhino) 로 다시 그리고
2. GIS 데이터를 별도로 받아 좌표 정합
3. 위성영상을 매핑하고
4. 렌더 엔진(Lumion/Twinmotion/V-Ray) 으로 조명·재질·하늘 설정
5. 카메라 앵글 잡고 이미지 출력

이 과정이 **수일에서 수주** 걸리며, 변경이 생길 때마다 대부분의 단계를 다시
수행해야 한다.

### 2.2 S-CANVAS 의 가설

> *"DXF 등고선·구조물 레이어 + 공개 DEM + 위성타일 + Generative AI 만으로,
> 클릭 4번에 사실 기반 3D 조감도를 만들 수 있다."*

- DXF 의 등고선 → TIN(Triangulated Irregular Network) 자동 생성
- DXF 범위 밖 지형 → AWS Open Terrain Tiles(글로벌 DEM) 자동 채움
- 표면 텍스처 → Google/ArcGIS/Vworld 위성 타일을 UV 매핑
- 최종 사실감 향상 → Gemini/Stability AI 가 **구조 보존 모드**로 재렌더

### 2.3 핵심 가치 제안 (Value Proposition)

| 기존 | S-CANVAS |
|---|---|
| 모델링 수일 | TIN 생성 30초 |
| 외부 라이선스 GIS | 공개 DEM 자동 페치 |
| 수동 좌표 정합 | 4점 매칭 자동 GeoRef |
| 렌더 1회 수시간 | AI 렌더 1분 이내 |
| 변경 → 재모델링 | 변경 → 재실행 (캐시 재활용) |

---

## 3. 시스템 아키텍처

### 3.1 모듈 구성 (Top Level)

```
scanvas_maker.py            # 메인 GUI 엔트리 (~6300 LOC, CustomTkinter)
├── splash.py               # 인트로 MP4 스플래시 (cv2 + Tk Toplevel)
├── dem_extender.py         # AWS Terrarium DEM 페치 + 도넛 링 메시
├── geo_referencing.py      # 4점 매칭 GeoReferencing 워크플로
├── structure_placement.py  # 구조물 위치/방향 자동 인식 + TIN 굴착
├── structure_templates.py  # 구조물 유형 레지스트리 (Registry 패턴)
├── intake_tower_3d_builder.py    # 취수탑 3D
├── intake_tower_parser.py        # 취수탑 DXF 치수 파싱
├── retaining_wall_3d_builder.py  # 옹벽 3D
├── retaining_wall_parser.py
├── gate_3d_builder.py            # 수문 3D
├── gate_parser.py
├── valve_chamber_3d_builder.py   # 제수변실 3D
├── valve_chamber_parser.py
├── detail_parser.py        # 상세도면 DXF 치수 파서 (TEXT/MTEXT/DIMENSION)
├── filename_classifier.py  # 파일명 → 구조물 유형 추정
├── polygon_reconstructor.py
├── dxf_geometry.py         # DXF 엔티티 → 좌표
├── tile_downloader.py      # 위성 XYZ 타일 다운로드
├── view_detector.py / view_reconstructor.py  # 도면 뷰 영역 인식
├── optional_detector.py
├── gemini_renderer.py      # Gemini API/Vertex AI 렌더링 워커
├── structure_vlm_feedback.py  # Gemini Vision 으로 구조물 결과 검증
├── egview_maker.py 의 후신:    # (이전 명칭, 현재 scanvas_maker.py 로 통합/리네임)
│
└── harness/                # 품질·재현성·이력 서브시스템
    ├── seed_manager.py     # DXF 해시 기반 결정론적 seed
    ├── quality_validator.py # OpenCV 기반 이미지 자동 QA
    ├── prompt_registry.py  # 프롬프트 버전 관리 (YAML)
    └── logger.py           # SQLite ORM (JobRecord) + structlog

prompt_templates/prompt_v1.yaml      # 렌더 프롬프트 (시간대/앙각/구조보존)
structure_types/structure_v1.yaml    # 구조물 유형 정의

Design/                              # 브랜딩 자산
├── logo_V2.png              # 로고 (다크 bg → 런타임 스트립)
├── Logo.png                 # 이전 로고 (투명 bg)
├── SAMAN_CI.gif             # Saman Corp 크레딧
├── logo_intro.mp4           # 인트로 스플래시 (8s, 24fps, 1280×720)
├── homepage_sample.png      # UI 디자인 레퍼런스
└── page_sample.png

cache/dem/                   # AWS Terrarium 타일 캐시
scanvas_jobs.db              # SQLite 작업 이력 (Harness)
scanvas_harness.log          # structlog 출력
scanvas_diagnostic.log       # Step 1 진단 로그
```

### 3.2 데이터 흐름 (Pipeline)

```
[DXF 도면] → [레이어 분류] → [등고선/구조물 분리]
                                  ↓
[GeoRef 4점 매칭] → [투영 CRS 결정 (EPSG:5187 등)]
                                  ↓
[TIN 생성 (Delaunay)] → [TIN core 정밀 영역 지정 (선택)]
                                  ↓
[DEM 자동 페치 (AWS Terrarium)] → [도넛 링 메시] → [smoothstep blend]
                                  ↓
[seam-free 통합 메시 (merge_points + compute_normals)]
                                  ↓
[위성 타일 다운로드] → [UV 매핑 (texture_map_to_plane)]
                                  ↓
[3D 미리보기 (PyVista)] → [카메라 앵글 캡처] → [제어맵]
                                  ↓
[Gemini/Stability AI 렌더링 (구조 보존 모드)]
                                  ↓
[QualityValidator 자동 검증] → [scanvas_jobs.db 이력 기록]
                                  ↓
[고해상도 PNG 출력]
```

### 3.3 외부 의존성

**Python 라이브러리** (주요):
- `customtkinter` — 모던 Tk GUI 프레임워크
- `tkintermapview` — 위성지도 뷰
- `ezdxf` — DXF 파싱
- `numpy`, `scipy` — 수치 연산, Delaunay
- `pyvista` + `vtk` — 3D 메시 렌더링
- `pyproj` — 좌표계 변환
- `Pillow (PIL)` — 이미지 처리
- `opencv-python (cv2)` — 비디오 / 이미지 검증
- `requests` — HTTP 타일 페치
- `google-genai` — Gemini SDK (Vertex AI 또는 API Key)
- `sqlalchemy` + `structlog` — 이력 추적
- `PyYAML` — 프롬프트/구조물 정의

**외부 데이터 소스**:
- AWS Open Terrain Tiles (`s3.amazonaws.com/elevation-tiles-prod/terrarium`)
  — 글로벌 DEM, ~30m 정확도, API 키 불필요
- Google Satellite / ArcGIS World Imagery / Bing Aerial / Vworld
  — 위성 타일 (사용자 선택)
- Google Vertex AI / Gemini API — 생성형 렌더링
- (옵션) Stability AI API — img2img 폴백

---

## 4. 핵심 워크플로 (Step-by-Step)

### Step 0 — DXF 로드 & 레이어 분류

DXF 를 열면 자동으로 레이어를 분석해 **구조물 유형**(취수탑/제수변실/옹벽/수문/
지형 등고선/도로/하천 등)을 추정. `filename_classifier.py` 가 파일명 패턴(예:
"신설 취수탑.dxf") 으로 1차 후보를 제시하고, 사용자가 GUI 다이얼로그에서 최종
확정. 결과는 `structure_v1.yaml` 의 정의에 따라 빌더로 라우팅.

### Step 1 — TIN 생성 (DXF)

지형 레이어의 등고선 점·LINE/LWPOLYLINE 정점을 추출 → Delaunay 삼각화 →
**zero-basing** (원점을 도면 bbox 좌하단으로 평행이동, 부동소수점 정밀도 보존) →
PyVista PolyData 메시 생성.

**핵심 디테일**:
- 단위 자동 감지 → KATEC 좌표(EPSG:5187 등) 는 항상 m 로 강제 (`unit_override="m"`)
- DEM datum offset 사전 계산 → 이후 단계에서 **공통 offset 재사용**으로 seam Z 단차 0 보장
- DEM 격자도 사전 페치 → `_dem_elev_grid` / `_dem_grid_bounds` 로 캐시

### Step 1.5 — DEM 으로 TIN 확장

DXF 범위 밖이 절벽처럼 잘리는 문제 해결. AWS Terrarium 에서 **외곽 도넛 링**을
받아 TIN 과 이어 붙임.

**3-Zone 구조** (메모리화된 핵심 결정):
1. **Core** (`tin_core_bbox` 안): 원본 TIN 100% 보존. 사용자가 정밀 영역으로 지정.
2. **Transition** (core ~ bbox, `blend_width_m`): smoothstep `3t² − 2t³` 으로 TIN ↔ DEM Z 부드럽게 블렌드.
3. **DEM 외곽 링**: AWS DEM 으로 채움.

**Seam 처리 (다층 방어)**:
- **수직 datum 보정**: TIN 경계 근처 점들의 (TIN Z – DEM Z) 중앙값을 offset 으로 차감
- **공유 정점 weld**: TIN bbox 변 정점을 DEM 링 inner 경계로 강제 → 동일 XY 공유
- **smoothstep feather**: 경계 0 = TIN, feather_m = DEM 으로 C¹ 연속
- **벽 컷 (slope_ratio 기반)**: `slope_ratio = z_span / max_edge` 가 4.0 (≈76°) 초과 + Z스팬 30m + max_edge 5m 충족 시 "벽 삼각형" 으로 컷. **절대 Z 컷은 절대 사용하지 않음** (구멍이 뚫림 — 메모리화된 교훈)
- **링 Laplacian 1pass**: 톱니 fin 마지막 평활. 경계 정점은 pin

### Step 2 — 위성지도 결합 (Draping)

선택한 타일 서버에서 **확장된 bbox 전체**의 위성 이미지 다운로드 → 단일 큰
이미지로 합성 → `texture_map_to_plane` 으로 UV 매핑 → 텍스처 입힌 3D 메시.

**Seam-free 통합 렌더링** (2026-04-24 후속 수정):
- 이전: `tin_mesh` 와 `tin_extension_mesh` 가 두 개의 별도 PolyData → 경계에서
  쉐이딩 불연속 (사각 선이 보이는 증상)
- 수정: `merge(merge_points=True, tolerance=0.01)` 로 공유 정점 weld → 위상적
  단일 표면. `compute_normals(feature_angle=180)` 로 모든 edge smooth → seam
  법선 평활. UV 좌표는 `_uv_mapping_params` 저장 후 merge 후 재적용.

### Step 3 — 제어맵 추출

PyVista 카메라 앵글로 오프스크린 캡처:
- `capture_textured.png` — 위성+DEM 합성된 control map
- `capture_depth.png` — 깊이 맵 (Eye-Dome Lighting 활성화)

이 2개 이미지가 Step 4 의 AI 렌더 입력.

### Step 4 — AI 렌더링 (구조 보존 모드)

`prompt_templates/prompt_v1.yaml` 기반으로 프롬프트 구성:
- **시간대 프리셋**: daytime / sunset / night / dawn / overcast
- **앙각 프리셋**: top_down / high_angle / oblique / low_angle
- **구조 보존 지시**: "maintain exact terrain shape, contours, and layout from the input image"
- **품질 향상**: "8K ultra sharp detail, professional drone photography quality"
- **네거티브**: "blurry, distorted, watermark, changed terrain layout, moved structures..."

**렌더 엔진 3종**:
1. **Gemini (Vertex AI)** — google-genai SDK, GCP 인증
2. **Gemini (API Key)** — google-genai SDK, AI Studio 키
3. **Stability AI (API)** — 3단계 폴백:
   1. Conservative Upscale (원본 보존 최우선)
   2. Creative Upscale (조금 더 창의적)
   3. img2img 초저강도 (strength=0.2)

각 렌더 호출은 Harness 가 **결정론적 seed** + **prompt 버전** + **품질 점수**를
자동 기록 → 동일 입력에 동일 출력 보장.

---

## 5. 핵심 기술 컴포넌트 / 혁신 포인트

### 5.1 DEM 자동 통합 (`dem_extender.py`)

- **AWS Open Terrain Tiles** terrarium PNG 디코딩:
  `elev_m = (R*256 + G + B/256) - 32768`
- 좌표계 변환: 투영 CRS(예: EPSG:5187) → WGS84 → 타일 좌표 (Web Mercator z/x/y)
- 캐시: SHA1(bbox+zoom) 으로 PNG 캐시 → 재실행 시 네트워크 0
- **로컬 GeoTIFF 우선**: `cache/dem/local.tif` 가 있으면 NGII 5m DEM 등 고정밀
  데이터 우선 사용 (rasterio 필요)

### 5.2 Seam-free 메시 통합 (Render-fix 2026-04-24)

> 원래 메모리: "벽 이슈는 create_tin_from_dxf 부터 점검. 판정은 slope_ratio 만,
> 절대 Z 컷은 구멍 낸다."

**문제**: TIN+DEM 을 두 개 별도 PolyData 로 add_mesh 하면 normal 평균이 메시
경계를 못 넘어 사각 쉐이딩 선이 보임.

**해결 (1순위 + 2순위 동시)**:
```python
merged = target.merge(ext_mesh, merge_points=True, tolerance=0.01)
if not isinstance(merged, pv.PolyData):
    merged = merged.extract_surface()
# 텍스처 모드: UV 재적용 (TCoords 가 merge 에서 소실되므로)
if textured and uv_params:
    merged = merged.texture_map_to_plane(origin=..., point_u=..., point_v=...,
                                          inplace=False)
merged.compute_normals(feature_angle=180.0, auto_orient_normals=True,
                       consistent_normals=True, inplace=True)
```

- `merge_points=True` → 공유 경계 정점 **물리적 weld** (1순위 unified Delaunay 효과)
- `feature_angle=180` → 모든 edge smooth, 경계 normal 평균 (2순위 normal averaging 효과)
- 폴백: 실패 시 기존 2-mesh 렌더 경로 유지

### 5.3 구조물 자동 빌드 (`structure_*_3d_builder.py`)

| 유형 | 빌더 | 입력 |
|---|---|---|
| 취수탑 | `intake_tower_3d_builder.py` | DXF 평면도 → 외곽 폴리곤 + 높이 |
| 옹벽 | `retaining_wall_3d_builder.py` | DXF 단면도 → 단면 + 길이 |
| 수문 | `gate_3d_builder.py` | DXF 정면도 → 게이트 형상 + 슬라브 |
| 제수변실 | `valve_chamber_3d_builder.py` | DXF 평면도 → 박스 + 슬래브 + 점검구 |

**구조물 위치인식 → 굴착 → TIN수정 → 3D배치** (메모리화된 워크플로):
1. DXF 레이어에서 폴리곤 인식
2. PCA 로 frame 방향 결정 (`compute_orientation_from_points`)
3. TIN 에 **굴착 pad** 영역 평탄화 + smoothstep 전이 + Delaunay 재계산
4. 메시 4개 quad 코너에 fit (`fit_meshes_to_quad`)
5. 구조물 메시를 `embed_offset` 으로 약간 묻어 TIN 관통 방지

**메시 방향 보정** (메모리화된 디테일):
- CW(시계방향) picks + Y-flip + detail/TIN 상대회전 + PCA frame_angle
  → 앞뒤 뒤집힘 문제 해결

### 5.4 VLM 피드백 루프 (`structure_vlm_feedback.py`)

Gemini Vision 으로 **빌더 결과물의 시각적 정합성**을 자동 검증.
- Render 후 이미지 + 원본 DXF 평면도를 함께 모델에 보냄
- 차이점 자연어로 응답 받음
- 사용자에게 표시해 재시도 결정

### 5.5 Geo-Referencing 3단계 (`geo_referencing.py`)

> 메모리: "미리보기 → 위치설정(4점 매칭) → 확정"

1. **미리보기**: DXF bbox 를 위성지도에 임시 투영 (대략 위치)
2. **위치설정**: 사용자가 DXF 의 4 모서리를 실제 위성지도 위치와 매칭 클릭
3. **확정**: Affine transform 행렬 계산 → 투영 CRS(EPSG:5187 등) 자동 결정

### 5.6 Harness — 재현성 + 품질 + 이력

세 컴포넌트가 모든 AI 렌더 호출을 감싼다:

**SeedManager**: `SHA256(dxf_file_hash)[:4] → uint32 seed`. 같은 DXF → 같은 seed.

**QualityValidator**: 3개 게이트
1. 해상도 ≥ 1024px
2. Laplacian variance ≥ 50.0 (선명도)
3. HSV saturation 평균 ≥ 0.15 (단색 평면 출력 탐지)

**JobLogger** + SQLite `JobRecord` ORM:
```
id · dxf_path · dxf_hash · timestamp
seed · prompt_version · prompt_hash       ← 재현성 3종
status (pending/running/done/failed)
output_path · quality_score · latency_ms
error_message
```

**PromptRegistry**: `prompt_v*.yaml` 버전 관리. 비교/저장/해시 역조회 API.

---

## 6. GUI 디자인 & 브랜딩

### 6.1 디자인 철학 (homepage_sample 참고)

- **Light 기본 테마** (사용자가 Dark 토글 가능)
- **카드형 시각 계층화**: 헤더 → SETTINGS → WORKFLOW → OPTIONS → 크레딧 푸터
- **1px 구분선**: `("#DEE2E6", "#3F3F3F")` 테마 쌍으로 자동 스위칭
- **uppercase 섹션 헤더**: 10pt bold muted gray
- **메인 액션 강조**: Step 4 버튼만 Saman 오렌지 `#E67E22`, 나머지는 blue 테마 파생

### 6.2 사이드바 구조

```
[ S-CANVAS Logo (logo_V2.png, 다크 bg 소프트 스트립) ]
  Generative Design & Visualization Engine
  ─────────────────────────────────
  SETTINGS
    Satellite Source / Vworld Key (프리필 완료) / AI Engine /
    GCP/API Key / Vertex Location / Project CRS
  ─────────────────────────────────
  WORKFLOW
    1. TIN 생성 (DXF) [filled blue]
    🎯 TIN 이용 범위 (정밀 구역) [outlined]
    1.5 DEM으로 TIN 확장 [outlined]
    2. 위성지도 결합 [outlined]
    3. 제어맵 추출 [outlined]
    4. AI 렌더링 [filled ORANGE — primary CTA]
    구조물 상세 3D 빌드 [filled green]
    간단 치수 추가 (구) [muted]
    🗔 3D 뷰 다시 열기 [filled dark]
  ─────────────────────────────────
  OPTIONS
    □ 와이어프레임 보기
    뷰 버퍼 (%) [Step2/3]
    □ 지형 확장 (DEM)
    [Light ▼]
  ─────────────────────────────────
[ Saman CI (흰배경 알파 변환) ]
```

### 6.3 메인 영역

- **map_frame**: tkintermapview, corner_radius=12, border_color 테마쌍
- **textbox**: Consolas 12pt 로그
- **status_bar**: `● READY` 인디케이터 + 한 줄 상태

### 6.4 인트로 스플래시 (`splash.py`)

- **트리거**: `__main__` 에서 `SCanvasApp()` 생성 직전
- **재생**: cv2 VideoCapture 로 logo_intro.mp4 (24fps, 8s, 1280×720) 프레임 디코드 → PIL → Tk Label
- **효과**:
  - 알파 0→1 페이드인 400ms
  - MP4 자체 애니메이션 재생
  - 알파 1→0 페이드아웃 400ms 후 destroy
  - frameless overrideredirect, topmost, 화면 중앙 배치
  - 비디오 아래 44px 오렌지 italic tagline bar
- **안정성**:
  - max_duration_s=12 safety cap
  - 비디오 끝 자동 감지 → 페이드아웃
  - 임시 tk.Tk → 완전 destroy → SCanvasApp() 의 새 ctk.CTk 충돌 없음
  - 파일 없음/cv2 실패 → silent skip

### 6.5 자산 처리 헬퍼

```python
_load_image_strip_white_bg(path, threshold=240)  # 흰 배경 → 알파 0 (SAMAN_CI)
_load_image_strip_dark_bg(path, v_low=30, v_high=80)  # 어두운 bg 소프트 전이 (logo_V2)
```

logo_V2 결과: 36.7% 완전투명 / 49.5% 부분알파 / 13.8% 불투명 → halo 없는 부드러운 엣지.

---

## 7. AI 렌더링 파이프라인 상세

### 7.1 프롬프트 구성 (`prompt_v1.yaml`)

```yaml
time_presets:
  daytime: "bright daylight, clear blue sky, sharp shadows, vivid green vegetation"
  sunset: "golden hour sunset, warm orange light, long dramatic shadows"
  night: "nighttime aerial view, moonlight reflections, city lights in distance"
  dawn: "early dawn, soft pink and purple sky, morning mist over valleys"
  overcast: "overcast sky, diffused soft light, muted colors, atmospheric fog"

angle_presets:
  top_down: "top-down overhead aerial view, directly above"
  high_angle: "high-angle bird's-eye view, slightly tilted"
  oblique: "oblique aerial perspective, 3/4 view showing terrain depth"
  low_angle: "low-angle dramatic perspective, cinematic sweep"

structure_preservation:
  - "enhance the existing satellite terrain texture and details"
  - "maintain exact terrain shape, contours, and layout from the input image"
  - "preserve water bodies, roads, and structural positions precisely"
  - "do NOT add or remove any major landscape features"

quality_enhancement:
  - "photorealistic architectural visualization"
  - "professional drone photography quality"
  - "8K ultra sharp detail, high dynamic range"
  - "realistic vegetation depth and canopy textures"

negative_prompt: |
  blurry, low quality, distorted, watermark, text, logo,
  cartoon, anime, illustration, painting, sketch,
  oversaturated, underexposed, noisy, artifacts,
  changed terrain layout, moved structures, wrong topology
```

### 7.2 Stability AI 3단계 폴백

**1단계 — Conservative Upscale**
- mode: "conservative"
- creativity: UI 슬라이더 값 그대로 (기본 0.3)
- 목표: 원본 위성 텍스처 최대 보존

**2단계 — Creative Upscale**
- mode: "creative"
- creativity: min(strength, 0.35)
- 목표: 약간 더 사실적인 디테일 추가

**3단계 — img2img 초저강도**
- strength: min(strength, 0.2)
- 모델: sd3.5-large
- 목표: 위 2개 실패 시 백업

각 단계 실패 → 다음 단계 자동 폴백. 3개 모두 실패 시 `fail_job(error="모든 API 방법 실패")`.

### 7.3 Gemini 경로 (`gemini_renderer.py`)

- Vertex AI: google-genai SDK, GCP Project ID + gcp-key.json
- API Key: aistudio.google.com 발급 키
- 동일 인터페이스로 호출 → 인증만 다름

---

## 8. 좌표계 / 단위 / 정밀도

### 8.1 지원 CRS (사용자 선택)

| 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 | 글로벌 (위성 타일 호환) |

### 8.2 단위 강제 (메모리화된 결정)

> "extract_tin_shapes 는 unit_override='m' 고정 (자동감지가 KATEC 좌표를 mm 로 오판)"

DXF `$INSUNITS` 헤더가 부정확한 경우가 많아 **항상 m 로 강제**. KATEC 류
대형 좌표값(예: x=200000, y=550000) 을 mm 로 오판하면 단위가 1000배 어긋남.

### 8.3 Zero-Basing

큰 절대좌표(예: EPSG:5187 의 200,000m+)는 float32 정밀도에서 sub-meter 오차
발생 → **bbox 좌하단을 origin 으로 평행이동** → 모든 메시는 zero-based.
구조물 빌더는 절대좌표(`structure_v1.yaml` 의 origin) 와 zero-based 사이를
명시적으로 변환.

---

## 9. 메모리화된 핵심 결정 사항 (요약)

> 이 결정들은 과거 디버깅에서 얻은 교훈으로, 코드 곳곳의 분기 판단 기준이 됨.

1. **Structure Placement Workflow**: 위치인식 → 굴착 → TIN수정 → 3D배치 4단계
2. **Geo-Referencing**: 미리보기 → 4점 매칭 → 확정 3단계
3. **TIN Shape Unit**: extract_tin_shapes 는 항상 `unit_override="m"` (자동감지 금지)
4. **Excavation**: 폴리곤 평탄 pad + smoothstep 전이 + Delaunay 재계산.
   구조물은 `embed_offset` 으로 TIN 관통 방지
5. **Mesh Orientation**: CW picks + Y-flip + 상대회전 + PCA frame_angle 로
   앞뒤 뒤집힘 해결
6. **TIN/DEM 벽 근본 접근**: 벽 이슈는 `create_tin_from_dxf` 부터 점검. 판정은
   `slope_ratio (z_span / max_edge)` 만 사용. **절대 Z 컷은 구멍 낸다**
7. **TIN 3-Zone**: core(원본 TIN) / transition(smoothstep) / DEM 확장.
   `tin_core_bbox` · `blend_width_m` 로 제어
8. **CHANGELOG 의무**: 모든 수정은 `CHANGELOG.md` 에 즉시 기록 (역순, 날짜/파일/사유/diff 요지)

---

## 10. 최근 주요 수정 이력 (2026-04-24 ~)

### [render-fix] DEM 확장 경계 사각 선 제거 (후속)
- 두 개의 별도 PolyData → seam shading discontinuity 발생
- `merge(merge_points=True, tolerance=0.01)` + `compute_normals(feature_angle=180)`
  로 1순위(구조 통합) + 2순위(법선 평활) 동시 달성
- 텍스처 모드에서 TCoords 소실 → `_uv_mapping_params` 저장 후 merge 후 재적용

### [rebrand] EG-VIEW → S-CANVAS 전면 리네이밍
- 클래스 `EGViewApp → SCanvasApp`
- 파일 `egview_maker.py → scanvas_maker.py`
- DB/로그 `egview_*.db/log → scanvas_*.db/log`
- 144개 문자열 occurrence (43 파일) 일괄 교체

### [ui-redesign] Light 기본 테마 + 사이드바 카드형
- `set_appearance_mode("light")`
- 모든 하드코딩 색상을 `(light, dark)` 튜플 쌍으로 → 자동 테마 스위칭
- SETTINGS / WORKFLOW / OPTIONS 섹션 헤더 + 1px 구분선
- SAMAN_CI 흰 배경 68.5% 알파 변환

### [feature] Vworld 키 프리필 + logo_V2 + 인트로 스플래시
- Vworld API 키 하드코딩 (사용자 제공)
- 로고 `Logo.png → logo_V2.png` (다크 bg 소프트 스트립)
- 신규 `splash.py` — cv2 기반 8초 MP4 스플래시 + 페이드 인/아웃
- `__main__` 에서 `show_intro_splash()` → `SCanvasApp()` 순차 실행

---

## 11. 차별화 포인트 (발표 슬라이드용 강조)

### 11.1 **사실 기반 vs 환각 기반**
경쟁 도구가 AI 의 상상으로 지형을 만들 때, S-CANVAS 는 **실측 DEM + 실제 위성영상**
을 베이스로 깔고 AI 는 **사실감 향상만** 담당. → 발주처에 실제와 다른 지형을
제출하는 사고 원천 차단.

### 11.2 **Seam-free 통합 메시**
TIN(설계 도면) + DEM(실제 지형) + 위성텍스처 + AI 렌더가 모두 **하나의 연속
표면**으로 합쳐짐. 사용자가 어디까지가 도면이고 어디부터가 실제 지형인지 구분
못 하도록.

### 11.3 **결정론적 재현성** (Harness)
DXF 해시 → seed → AI 렌더. 같은 입력에 항상 같은 출력. 발주처에 제출했던 그림과
1주일 뒤 회의에서 띄울 그림이 픽셀 단위로 동일.

### 11.4 **모듈러 구조물 빌더**
취수탑·제수변실·옹벽·수문 4종 즉시 지원. `structure_v1.yaml` 에 정의 추가하면
새 유형 확장 가능. DXF 단면도 → 자동 치수 파싱 → 3D 배치까지 클릭 1번.

### 11.5 **공개 데이터 + 무료 티어**
AWS Open Terrain Tiles · Google Satellite · ArcGIS World Imagery 모두 무료.
유일한 유료 항목은 AI 렌더(Gemini/Stability) — 그것도 사용자 본인 키 사용.

### 11.6 **자동 품질 게이트**
모든 렌더 결과를 OpenCV 로 즉시 검증. 흐릿하거나 단색 출력은 자동 PASS/FAIL
표시 → 사용자가 100장을 일일이 확인할 필요 없음.

### 11.7 **Saman Corp 자체 개발**
국내 토목·건설 도메인 지식이 코드 곳곳에 — KATEC 단위 처리, 한국 EPSG 코드
프리셋, Vworld 타일 지원, 한글 UI·로그 등.

---

## 12. 기술 스택 요약 (한눈에)

```
[Frontend / GUI]
└─ CustomTkinter (Tk 기반 모던 위젯) + tkintermapview

[3D Engine]
└─ PyVista + VTK (메시 처리·렌더링)

[Geospatial]
├─ ezdxf (DXF 파싱)
├─ pyproj (좌표 변환)
├─ scipy.spatial.Delaunay (TIN)
└─ AWS Open Terrain Tiles (DEM)

[Image / Video]
├─ Pillow (PIL)
├─ OpenCV (cv2)
└─ tkintermapview (위성 타일)

[AI Rendering]
├─ Google google-genai (Vertex AI / API Key)
└─ Stability AI REST API

[Persistence]
├─ SQLAlchemy + SQLite (JobRecord)
├─ structlog (구조화 로깅)
└─ PyYAML (프롬프트/구조물 정의)

[Build / Distribution] (계획)
└─ PyInstaller (단일 .exe 또는 onedir 배포)
```

---

## 13. 배포 / 패키징 계획

**PyInstaller** 로 Windows .exe 빌드 예정. 주요 챌린지:
- PyVista + VTK 200MB+ 바이너리 → `--collect-all pyvista vtkmodules` 필요
- pyproj PROJ data → 명시적 hook
- google-genai → hidden imports
- 런타임 쓰기 경로(DB·로그·캐시) → `%LOCALAPPDATA%\S-CANVAS\` 분리 (onedir/onefile 양쪽)
- 자산 경로 (`Design/`, `prompt_templates/`, `structure_types/`) → `sys._MEIPASS` 핸들링

배포 형태 (예정): `dist/scanvas_maker/` 폴더 통째로 zip → 약 150-200MB 압축. 사용자는
.exe 더블클릭으로 실행, 본인 GCP 키 또는 Stability API 키만 환경변수/UI 입력.

---

## 14. 향후 로드맵

1. **다국어 (i18n)**: 한국어/영어 토글
2. **추가 구조물 유형**: 배수문·교량·터널·송수관 등
3. **Linux/macOS 지원**: 현재 Windows 전용
4. **클라우드 렌더 큐**: 다수 DXF 일괄 처리 후 결과 한꺼번에 ZIP
5. **VR/AR 출력**: glTF 익스포트 → Unity/Unreal 연동
6. **변경 추적**: 같은 DXF 의 V1/V2 자동 비교 → 변경 영역 하이라이트

---

## 15. 핵심 메시지 (발표 마무리용)

> **S-CANVAS 는 토목·건설 도면을, "수일짜리 모델링 작업" 에서 "클릭 4번의 자동
> 파이프라인" 으로 압축한다. 사실 기반(DEM·위성) 위에서 AI 가 사실감만 더하므로
> 환각 위험 없이, 결정론적 재현성을 보장하면서, 발주처·주민설명회 발표용 조감도를
> 분 단위로 양산할 수 있다. — Saman Corp.**

---

## 부록 A. 진입점 / 실행 방법

```bash
python scanvas_maker.py
```

진행 순서:
1. `splash.py` 가 logo_intro.mp4 8초 재생 (페이드 인/아웃)
2. `SCanvasApp(ctk.CTk)` 메인 창 기동
3. (사이드바) DXF 파일 선택 → CRS 확인 → Step 1~4 순차 실행
4. (옵션) 구조물 상세 3D 빌드 / 와이어프레임 / DEM 확장
5. AI 렌더 결과는 `rendered_birdseye.png` (와 SQLite 이력)

## 부록 B. 디렉토리 구조

```
D:\2026\00_EGVIEW2\
├── scanvas_maker.py              # 메인 진입점
├── splash.py                     # 인트로 스플래시
├── dem_extender.py
├── geo_referencing.py
├── 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
│
├── harness/
│   ├── __init__.py
│   ├── seed_manager.py
│   ├── quality_validator.py
│   ├── prompt_registry.py
│   └── logger.py
│
├── prompt_templates/
│   └── prompt_v1.yaml
│
├── structure_types/
│   └── structure_v1.yaml
│
├── Design/
│   ├── Logo.png
│   ├── logo_V2.png         (현재 사용)
│   ├── SAMAN_CI.gif
│   ├── logo_intro.mp4      (8s, 24fps, 1280×720)
│   ├── homepage_sample.png
│   └── page_sample.png
│
├── cache/dem/              (런타임 DEM 캐시)
├── scanvas_jobs.db         (SQLite 이력)
├── scanvas_harness.log     (structlog)
├── scanvas_diagnostic.log  (Step 1 진단)
├── CHANGELOG.md            (수정 이력 역순)
└── Build_log.txt           (사용자 원본 요청 로그)
```

## 부록 C. 핵심 메트릭 (발표 슬라이드 숫자용)

- 메인 모듈: 6300+ LOC (`scanvas_maker.py`)
- 지원 구조물 유형: 4종 (취수탑·제수변실·옹벽·수문) + 확장 가능
- 지원 좌표계: 5종 EPSG (한국 4 + Web Mercator 1)
- 지원 위성 타일 서버: 9종 (Google·ArcGIS·Bing·OSM·OpenTopo·Vworld 3종 등)
- 지원 AI 렌더 엔진: 3종 (Gemini Vertex·Gemini API·Stability)
- DEM 자동 페치: AWS Terrarium 글로벌, ~30m 정확도
- 인트로 스플래시: 8.0초 (24fps × 192 frames @ 1280×720)
- 메시 통합 weld 톨러런스: 0.01m (1cm)
- TIN 3-Zone 블렌드: smoothstep `3t² − 2t³`
- 벽 컷 임계: slope_ratio > 4.0 (≈76°) AND z_span > 30m AND e_max > 5m

---

*본 문서는 NotebookLM 의 단일 소스로 사용 가능하도록 자기완결형으로 작성되었습니다.
업로드 후 "Audio Overview", "마인드맵", "발표 슬라이드 초안" 자동 생성을 권장합니다.*
