# 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", "마인드맵", "발표 슬라이드 초안" 자동 생성을 권장합니다.*