"""지형 분석·지표면 모델 생성 파라미터 (5장·5-2장). `config_system.py` 가 700줄을 넘어 떼어냈다(2026-09-04). 값·이름은 그대로이고, `config_system` 이 다시 내보내므로 기존 `from config.config_system import …` 는 불변이다. """ import os # 5. 지형 분석 알고리즘 파라미터 # ───────────────────────────────────────────────────────────────────────── SURFACE_LAS_CHUNK_SIZE = int(os.getenv("SURFACE_LAS_CHUNK_SIZE", "500000")) SURFACE_DEFAULT_RGB_VALUE = int(os.getenv("SURFACE_DEFAULT_RGB_VALUE", "128")) # 지형 파일 여러 장 병합 (2026-09-06 사용자 확정) # ───────────────────────────────────────────────────────────────────────── # 다른 사업지 파일이 섞여 들어오면 합친 범위가 통째로 어긋난다 — 어느 파일과도 이 # 거리 안에서 만나지 않는 파일은 업로드에서 막는다. 임도는 길어도 2~3km 라 5km 면 # 넉넉하다(2026-09-06 사용자 확정). 도엽이 나뉜 자료는 경계가 맞닿아 걸리지 않는다. SURFACE_MERGE_MAX_GAP_M = float(os.getenv("SURFACE_MERGE_MAX_GAP_M", "5000")) # 점이 이 수를 넘으면 아래 칸 크기로 씨닝한다(칸마다 최저점 하나). 넘지 않으면 원본 # 그대로 쓴다 — 작은 자료의 결과는 바뀌지 않는다. 1억점 = 메모리 약 3.2GB. SURFACE_THIN_TRIGGER_POINTS = int(os.getenv("SURFACE_THIN_TRIGGER_POINTS", "100000000")) # 씨닝 칸 크기(m). 설계 격자 1m·다듬기 칸 1m 보다 촘촘해야 결과가 안 변한다. SURFACE_THIN_CELL_SIZE_M = float(os.getenv("SURFACE_THIN_CELL_SIZE_M", "0.5")) # 씨닝 격자가 이보다 많아지면 범위가 비정상이다(먼 파일이 섞였거나 좌표계 불일치). SURFACE_THIN_MAX_CELLS = int(os.getenv("SURFACE_THIN_MAX_CELLS", "400000000")) # 점진 TIN(PTD) 지면 분류 — 장면 flat · gentle · steep(각 · 거리 묶음) · 시작 간격(씨앗 칸) # 시작 간격 = 숲 10 m(DJI 기본 20 m 는 급한 볼록 비탈을 못 따라감) SURFACE_PTD_SCENE = os.getenv("SURFACE_PTD_SCENE", "steep") SURFACE_PTD_SEED_SPACING_M = float(os.getenv("SURFACE_PTD_SEED_SPACING_M", "10.0")) # LAS 자체 지면분류(class 2) 필터 — 이 비율 이상 분류돼 있을 때만 필터로 제공한다. # 미분류 LAS는 classification이 전부 0이라 마스크가 비어 버린다. SURFACE_CLASSIFIED_GROUND_MIN_RATIO = float( os.getenv("SURFACE_CLASSIFIED_GROUND_MIN_RATIO", "0.002") ) # 자동 기본 고름만 — 점 있는 칸(한 변 아래 m) 중 class 2 가 있는 칸이 이 비율 이상이어야 분류 있음. SURFACE_CLASSIFIED_COVERAGE_CELL_M = float(os.getenv("SURFACE_CLASSIFIED_COVERAGE_CELL_M", "10.0")) SURFACE_CLASSIFIED_COVERAGE_MIN_RATIO = float( os.getenv("SURFACE_CLASSIFIED_COVERAGE_MIN_RATIO", "0.5") ) # 지면점 비율이 이 값 미만이면 필터가 사실상 실패한 것으로 보고 WARNING을 남긴다. SURFACE_GROUND_RATIO_WARN = float(os.getenv("SURFACE_GROUND_RATIO_WARN", "0.01")) # 계획노선이 지표면 밖으로 나가 잘릴 때, 잘린 쪽 끝에서 더 깎을 길이(m). # 서피스 가장자리는 점 밀도가 떨어져 외곽선이 불규칙하다 — 경계에 딱 붙여 자르면 # 그 구간 지반고가 못 미덥다 (2026-09-01 사용자 확정). # 30m 는 너무 많이 깎는다는 지적으로 3m 로 낮춤 (2026-09-04 사용자 지시). SURFACE_ROUTE_EDGE_TRIM_M = float(os.getenv("SURFACE_ROUTE_EDGE_TRIM_M", "3.0")) # ───────────────────────────────────────────────────────────────────────── # 5-2. 지표면 모델 생성 파라미터 (DTM/implicit) # ───────────────────────────────────────────────────────────────────────── # 고를 수 있는 지면 필터 전체 — 관리자가 B04 드롭다운에서 요청할 때 쓰인다. # 자동 전처리가 미리 만드는 조합이 아니다(그건 SURFACE_AUTO_* 가 정한다). SURFACE_MODEL_SOURCE_FILTERS = tuple( os.getenv("SURFACE_MODEL_SOURCE_FILTERS", "classification,ptd").split(",") ) # 자동 전처리가 만드는 조합 — 기본 필터 1종 × 아래 표현. 나머지는 관리자 요청 시 만든다. SURFACE_AUTO_METHODS = tuple(os.getenv("SURFACE_AUTO_METHODS", "dtm").split(",")) # 기본 필터는 입력 LAS를 보고 정한다 — 지면분류(class 2)가 있으면 그것을, 없으면 아래 값. SURFACE_AUTO_FALLBACK_FILTER = os.getenv("SURFACE_AUTO_FALLBACK_FILTER", "ptd") # 자동 전처리 · 확정 기본은 이 필터의 다듬기 판(`_refine`) — 요구 607. # 다듬기(SMRF 꼴) — 칸 · 물체 기울기(rise/run · PDAL 0.15 는 급경사 능선을 깎아 0.3) · 최대 창 · # 판정 문턱 · 기울기 배수 · 낮은 잡점 기울기 — 나머지는 PDAL 기본. SURFACE_REFINE_CELL_M = float(os.getenv("SURFACE_REFINE_CELL_M", "1.0")) SURFACE_REFINE_SLOPE = float(os.getenv("SURFACE_REFINE_SLOPE", "0.3")) SURFACE_REFINE_WINDOW_M = float(os.getenv("SURFACE_REFINE_WINDOW_M", "18.0")) SURFACE_REFINE_THRESHOLD_M = float(os.getenv("SURFACE_REFINE_THRESHOLD_M", "0.5")) SURFACE_REFINE_SCALAR = float(os.getenv("SURFACE_REFINE_SCALAR", "1.25")) SURFACE_REFINE_LOW_SLOPE = float(os.getenv("SURFACE_REFINE_LOW_SLOPE", "5.0")) # dtm 먼저 — implicit 이 dtm 메운 칸을 길잡이로 씀(766-2) SURFACE_MODEL_PRECOMPUTE = tuple(os.getenv("SURFACE_MODEL_PRECOMPUTE", "dtm,implicit").split(",")) SURFACE_MODEL_SMOOTHING_METHODS = tuple( os.getenv("SURFACE_MODEL_SMOOTHING_METHODS", "dtm").split(",") ) SURFACE_MODEL_SYNC_TIMEOUT_SECONDS = int(os.getenv("SURFACE_MODEL_SYNC_TIMEOUT_SECONDS", "0")) # footprint(외곽) 산출 SURFACE_FOOTPRINT_RESOLUTION_M = float(os.getenv("SURFACE_FOOTPRINT_RESOLUTION_M", "1.0")) # 외곽 틈 닫기 3 m — DJI 지면점이 성긴 숲 띠까지 스캔 범위로 살림(요구 558). SURFACE_FOOTPRINT_GAP_CLOSE_M = float(os.getenv("SURFACE_FOOTPRINT_GAP_CLOSE_M", "3.0")) SURFACE_BOUNDARY_INSET_M = float(os.getenv("SURFACE_BOUNDARY_INSET_M", "1.0")) SURFACE_KEEP_LARGEST_FOOTPRINT = ( os.getenv("SURFACE_KEEP_LARGEST_FOOTPRINT", "True").lower() == "true" ) SURFACE_TILE_SIZE_M = float(os.getenv("SURFACE_TILE_SIZE_M", "50.0")) SURFACE_MAX_PREVIEW_VERTICES = int(os.getenv("SURFACE_MAX_PREVIEW_VERTICES", "500000")) # 표현별 파라미터 (old 버전 검증값 기준 — PLAN F) SURFACE_DTM_GRID_RESOLUTION_M = float(os.getenv("SURFACE_DTM_GRID_RESOLUTION_M", "1.0")) # implicit 중심점 수 = clip(지면점 × 비율, 하한, 상한) · 지면점이 하한보다 적으면 전부(요구 558). SURFACE_IMPLICIT_POINT_RATIO = float(os.getenv("SURFACE_IMPLICIT_POINT_RATIO", "0.175")) SURFACE_IMPLICIT_MIN_POINTS = int(os.getenv("SURFACE_IMPLICIT_MIN_POINTS", "50000")) SURFACE_IMPLICIT_MAX_POINTS = int(os.getenv("SURFACE_IMPLICIT_MAX_POINTS", "2000000")) SURFACE_IMPLICIT_SMOOTHING = float(os.getenv("SURFACE_IMPLICIT_SMOOTHING", "0.1")) # 스무딩 파라미터 SURFACE_SMOOTHING_DTM_SIGMA_M = float(os.getenv("SURFACE_SMOOTHING_DTM_SIGMA_M", "0.5")) SURFACE_SMOOTHING_DTM_SPLINE_SMOOTH = float(os.getenv("SURFACE_SMOOTHING_DTM_SPLINE_SMOOTH", "0.0")) SURFACE_SMOOTHING_DTM_PREVIEW_RESOLUTION_M = float( os.getenv("SURFACE_SMOOTHING_DTM_PREVIEW_RESOLUTION_M", "0.5") ) # 등고선 파라미터 SURFACE_CONTOUR_INTERVAL_M = float(os.getenv("SURFACE_CONTOUR_INTERVAL_M", "1.0")) SURFACE_CONTOUR_GRID_RESOLUTION_M = float(os.getenv("SURFACE_CONTOUR_GRID_RESOLUTION_M", "1.0")) # 도엽등고선 3D 서피스 (LAS 없는 설계 — 2026-08-30 사용자 확정) # 노선 XY bbox에 더하는 절취 여유(m). 300m = 횡단·코리도·성토면 여유(사용자 확정값). SHEET_SURFACE_MARGIN_M = float(os.getenv("SHEET_SURFACE_MARGIN_M", "300.0")) # 도엽등고선 DTM 격자 한 변(m). LAS DTM·등고선 캐시와 같은 1m(사용자 확정값). SHEET_SURFACE_GRID_M = float(os.getenv("SHEET_SURFACE_GRID_M", "1.0")) # D 예정노선 지형 격자(m) — 길이 · 원지반 기울기를 대충 보는 계획 단계라 2m(B 는 위 1m 그대로). PLAN_TERRAIN_GRID_M = float(os.getenv("PLAN_TERRAIN_GRID_M", "2.0")) # 위성 조각 저장본 한도(590-2 · 요구 453 사용자 확정) — 프로젝트당 MB · 넘으면 오래 안 본 것부터 지움. PLAN_TILE_CACHE_MB = float(os.getenv("PLAN_TILE_CACHE_MB", "150")) # 만들어 둘 등고선 보간 방식 — B04 화면에서 버튼으로 바꿔 가며 비교한다 # (2026-08-30 사용자 지시). 정의는 B04_PreProcess_Engine_SheetMethods.py. SHEET_SURFACE_METHODS = [ method.strip() for method in os.getenv( "SHEET_SURFACE_METHODS", "laplace", ).split(",") if method.strip() ] # 확정에 쓸 기본 방식 — 라플라스 (2026-08-30 사용자 확정). SHEET_SURFACE_DEFAULT_METHOD = os.getenv("SHEET_SURFACE_DEFAULT_METHOD", "laplace") # 자동 전처리가 만드는 도엽 방식 — 기본 하나뿐이다. 여섯 방식을 매번 다 만들면 # WF1의 대부분(용화 실측 891초 중 655초)을 여기서 쓴다. 나머지는 관리자가 B04에서 # 그 방식을 고를 때 만든다 (2026-09-01 사용자 확정). SHEET_SURFACE_AUTO_METHODS = [ method.strip() for method in os.getenv("SHEET_SURFACE_AUTO_METHODS", SHEET_SURFACE_DEFAULT_METHOD).split(",") if method.strip() ] # 일반 사용자 WF1 자동 확정 기본값 SURFACE_CONFIRM_DEFAULT_FILTER = os.getenv("SURFACE_CONFIRM_DEFAULT_FILTER", "ptd_refine") # 확정 표현 = implicit · 평활 끔 — WF1 자동 짓기도 이 표현을 기본 필터에 지음(요구 558). SURFACE_CONFIRM_DEFAULT_METHOD = os.getenv("SURFACE_CONFIRM_DEFAULT_METHOD", "implicit") SURFACE_CONFIRM_DEFAULT_SMOOTH = ( os.getenv("SURFACE_CONFIRM_DEFAULT_SMOOTH", "False").lower() == "true" ) def build_surface_model_config() -> dict: """지표면 모델 파이프라인이 사용하는 config dict를 조립한다.""" return { "source_filters": list(SURFACE_MODEL_SOURCE_FILTERS), "precompute": list(SURFACE_MODEL_PRECOMPUTE), "smoothing_methods": tuple(SURFACE_MODEL_SMOOTHING_METHODS), "sync_timeout_seconds": SURFACE_MODEL_SYNC_TIMEOUT_SECONDS, "footprint_resolution_meters": SURFACE_FOOTPRINT_RESOLUTION_M, "footprint_gap_close_meters": SURFACE_FOOTPRINT_GAP_CLOSE_M, "boundary_inset_meters": SURFACE_BOUNDARY_INSET_M, "keep_largest_footprint": SURFACE_KEEP_LARGEST_FOOTPRINT, # 외곽 안 큰 구멍 메움 방식(766-2) — 바뀌면 모델 지문이 달라져 다시 지음 "hole_fill": "laplace", "tile_size_meters": SURFACE_TILE_SIZE_M, "max_preview_vertices": SURFACE_MAX_PREVIEW_VERTICES, "dtm_grid_resolution_meters": SURFACE_DTM_GRID_RESOLUTION_M, "implicit_point_ratio": SURFACE_IMPLICIT_POINT_RATIO, "implicit_min_points": SURFACE_IMPLICIT_MIN_POINTS, "implicit_max_points": SURFACE_IMPLICIT_MAX_POINTS, "implicit_smoothing": SURFACE_IMPLICIT_SMOOTHING, "smoothing_dtm_sigma_meters": SURFACE_SMOOTHING_DTM_SIGMA_M, "smoothing_dtm_spline_smooth": SURFACE_SMOOTHING_DTM_SPLINE_SMOOTH, "smoothing_dtm_preview_resolution_meters": SURFACE_SMOOTHING_DTM_PREVIEW_RESOLUTION_M, "contour_interval_meters": SURFACE_CONTOUR_INTERVAL_M, "contour_grid_resolution_meters": SURFACE_CONTOUR_GRID_RESOLUTION_M, }