Merge remote-tracking branches 'origin/sub_laptop_3' and 'origin/sub_laptop_8' into main_laptop_1

This commit is contained in:
2026-11-03 16:36:06 +09:00
69 changed files with 267 additions and 2675 deletions
+2 -68
View File
@@ -24,25 +24,16 @@ from typing import Literal, Protocol, get_args
import numpy as np
from scipy.interpolate import RegularGridInterpolator
#: 지면 필터 · 지표면 표현 허용 목록 — 파일 이름에 들어감(B04 `_FILTERS` · `MODEL_METHODS`)
#: 지면 필터 · 지표면 표현 허용 목록 — 파일 이름에 들어감(B04 `_FILTERS` · `BUILDERS`)
#: `sheet_*` = 수치지형도 등고선 서피스(B04 `SHEET_METHOD_LABELS` 키 앞에 `sheet_`)
SurfaceFilter = Literal[
"classification",
"grid_min_z",
"csf",
"pmf",
"ptd",
"ransac",
"classification_refine",
"ptd_refine",
"sheet_tin_sheet",
"sheet_tin",
"sheet_biharmonic",
"sheet_anudem",
"sheet_multires",
"sheet_laplace",
]
SurfaceMethod = Literal["dtm", "tin", "nurbs", "implicit", "meshfree"]
SurfaceMethod = Literal["dtm", "implicit"]
def check_surface_keys(filter_key: str, method: str = "dtm") -> None:
@@ -243,31 +234,12 @@ class CallableSurfaceSampler:
return values, valid
@dataclass
class InterpolatedSurfaceSampler:
"""불규칙/곡면 모델 보간기와 DTM footprint 유효성을 결합한다."""
interpolator: Callable[[np.ndarray], np.ndarray]
footprint: SurfaceElevationSampler | None = None
def sample_xy(self, xy: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
xy = np.asarray(xy, dtype=np.float64)
values = np.asarray(self.interpolator(xy), dtype=np.float64).reshape(-1)
valid = np.isfinite(values)
if self.footprint is not None:
_, footprint_valid = self.footprint.sample_xy(xy)
valid &= footprint_valid
values[~valid] = np.nan
return values, valid
def build_surface_sampler(
models_dir: Path | str, source_filter: str, method: str, smooth: bool
) -> SurfaceElevationSampler:
"""1단계 확정 모델을 종·횡단용 일괄 XY 표고 sampler로 연다."""
check_surface_keys(source_filter, method)
models_dir = Path(models_dir)
smooth_suffix = "_smooth" if smooth and method in {"dtm", "tin"} else ""
dtm_smooth = models_dir / f"dtm_{source_filter}_smooth.npz"
dtm_original = models_dir / f"dtm_{source_filter}.npz"
dtm_path = dtm_smooth if smooth and dtm_smooth.exists() else dtm_original
@@ -277,46 +249,8 @@ def build_surface_sampler(
if method == "dtm":
return footprint
if method == "tin":
from scipy.interpolate import LinearNDInterpolator
path = models_dir / f"tin_{source_filter}{smooth_suffix}.npz"
if not path.exists() and smooth_suffix:
path = models_dir / f"tin_{source_filter}.npz"
with np.load(path, allow_pickle=False) as data:
vertices = np.asarray(data["vertices"], dtype=np.float64)
interpolator = LinearNDInterpolator(vertices[:, :2], vertices[:, 2], fill_value=np.nan)
return InterpolatedSurfaceSampler(lambda xy: interpolator(xy), footprint)
if method == "nurbs":
from scipy.interpolate import RectBivariateSpline
path = models_dir / f"nurbs_{source_filter}.npz"
with np.load(path, allow_pickle=False) as data:
control_x = np.asarray(data["control_x"], dtype=np.float64)
control_y = np.asarray(data["control_y"], dtype=np.float64)
control_z = np.asarray(data["control_z"], dtype=np.float64)
degree = int(data["degree"][0]) if "degree" in data else 3
spline = RectBivariateSpline(
control_y,
control_x,
control_z,
kx=min(degree, len(control_y) - 1),
ky=min(degree, len(control_x) - 1),
)
return InterpolatedSurfaceSampler(lambda xy: spline.ev(xy[:, 1], xy[:, 0]), footprint)
if method == "implicit":
# 굳힌 격자(641-1) — 브라우저 · Node 측점 · B06 이 같은 파일을 읽음(`source` 가 붙음)
return DtmGridSampler.open_cached(implicit_grid_npz(models_dir, source_filter))
if method == "meshfree":
from scipy.interpolate import LinearNDInterpolator
path = models_dir / f"meshfree_{source_filter}.npz"
with np.load(path, allow_pickle=False) as data:
points = np.asarray(data["points"], dtype=np.float64)
interpolator = LinearNDInterpolator(points[:, :2], points[:, 2], fill_value=np.nan)
return InterpolatedSurfaceSampler(lambda xy: interpolator(xy), footprint)
raise ValueError(f"지원하지 않는 지표면 모델입니다: {method}")