diff --git a/docs/raw/요구_1101/_분석_557-A_implicit_코드.md b/docs/raw/요구_1101/_분석_557-A_implicit_코드.md new file mode 100644 index 000000000..1e168315b --- /dev/null +++ b/docs/raw/요구_1101/_분석_557-A_implicit_코드.md @@ -0,0 +1,158 @@ +# 557-A — implicit 서피스: 쓰는 곳 · 누락 원인 · 매끄러움 · 매개변수 + +읽기 · 실측만 · 코드 · storage 고침 없음. 실측 = `검증_sub8`(`9872e9a7…`) — 용화.las 와 같은 자료(상자 896 × 643 m · 업체 지면점 114.1 만). 11-01 18:29~18:34 에 implicit 세 벌(분류 · CSF · grid_min_z)이 이미 지어져 있어 그대로 읽음. 변형 시험 = 앱 `build_implicit` 를 tmp 에 돌림. 잣대 = 모델에 안 쓴 업체 지면점(검사점)과의 높이 차 RMS. + +## ① 결론 다섯 줄 + +1. implicit 는 「지면점 1만 개 + 식」만 저장하고 **쓰는 곳마다 식을 다시 셈**. B04 3D · 등고선 · 서버 표본(종횡단 · 노선 표고 · 추천 노선)은 implicit 를 따르나, **브라우저 즉시 계산 · Node 측점 · B07 유역 · D03 은 implicit 를 모르고 같은 필터 DTM 을 씀**. B06 은 「지형 범위 밖」 배지가 뜸. +2. **빈 서피스는 implicit 탓이 아님.** 저장된 implicit 미리보기 · 등고선 덮임은 DTM · TIN 과 같음(상자 대비 39.3 % · 빈 값 0). 비는 까닭은 모든 표현이 같이 쓰는 **외곽 규칙**(틈 닫기 1 m + 가장 큰 덩이만)임. 숲 밑 지면점이 2 m 넘게 띄엄띄엄이라 덩이가 끊기고, 업체 분류 기준 **스캔 범위의 34.8 % 를 버림**. 점 오류가 아니라 「지면점 성김 + 규칙」 탓임. +3. 「매끄러움」의 정체 = 지면점 114 만 개 중 **1만 개(0.9 %)만 씀**. 평균 간격은 약 4.8 m이고, 사업이 넓을수록 더 성김(이름은 「타일당」이나 타일 없음). 넓은 비탈은 잘 맞음(검사점 RMS 0.28 m · 치우침 0 · 지금 DTM 0.77 m 보다 나음 · TIN 0.09 m 보다 못함). 그러나 **좁은 능선 · 둔덕은 3~4 m 깎임**. 200 m 칸 등고선 잔고리는 9 개(TIN 152 · DTM 102). +4. **품질은 점 수가 정하고, smoothing 은 거의 상관없음.** 점 수별 결과: + - 20만 점 — RMS 0.11 m · 짓기 35 → 51 s · 메모리 +166 MB · 잔고리 36 + - 전부(101 만) — RMS 0.07 m · 61 s · +243 MB · 잔고리 74 + - 5만 점 — RMS 0.16 m · 잔고리 13 · 매끄러움과 정확도의 가운데 + - smoothing 0~10 — RMS 0.11~0.13 m로 차이 거의 없음 +5. 누락 처리 첫 후보 = **외곽 틈 닫기 1 → 3 m**. 덮임이 스캔의 65 % 에서 94 % 로 늚. 다만 되살린 띠는 점이 성겨서, 지금 1만 점 implicit 로는 그 띠 RMS 가 1.22 m임(20만 점이면 0.24 m). 그래서 **점 수와 외곽을 함께 바꿔야 함**. 모든 화면이 implicit 를 쓰게 하려면, implicit 를 DTM 꼴 격자로 굳혀 내보내는 길이 고칠 곳이 가장 적음. + +## ② 쓰는 곳 표 + +| 쓰는 곳 | implicit 를 어떻게 | 파일:줄 | +| --- | --- | --- | +| B04 짓기 | 지면점을 기록 차례대로 고른 간격으로 1만 개 뽑음 → RBF(TPS · 이웃 64 · smoothing 0.1) → 미리보기 격자 **상자 전체**에서 셈 → 외곽 밖 자름 → npz 엔 중심점 · 높이 · smoothing 만 | `B04_PreProcess_Engine_ModelBuild.py:171-225`(뽑기 174-175 · 셈 188-197 · 자름 201-202 · 저장 205-210) · `ModelContext.py:253-263` · `:366-375` | +| B04 3D 미리보기 | 지을 때 구운 GLB 그대로 · 평활 단추 꺼짐 | `Router_Status.py:153-215` · `UI_TerrainViewer.ts:350-356` | +| B04 등고선 | 부를 때마다 RBF 를 다시 지어, 중심점 상자 1 m 격자를 한 번에 셈 → 같은 필터 `dtm_{필터}.npz` valid_mask 로 자름 → json 캐시 | `Engine_Contour.py:430-451` · `:125-176` · `Router_Contour.py:101-132` · `Pipeline.py:48-83` | +| 확정 | 고를 수 있음 · 평활 값 = 화면에서 꺼진 false | `B04_PreProcess_Router.py:211-245` · `UI_Page.ts:599` | +| 서버 표본(종횡단 · 노선 표고 · 배수 · 노선 형상) | `build_surface_sampler` — 부를 때마다 npz 를 읽고 RBF 를 다시 지음(DTM 만 캐시) · 유효 범위는 `dtm_{필터}[_smooth].npz` valid_mask(네 칸 모두 유효) | `common_util_surface_sampler.py:212-272`(캐시 131-136) · 부르는 곳 `B05 Router_Terrain.py:67` · `Engine_Sections.py:492` · `:608` · `AsPlanned.py:48` · `Router_PlanSource.py:50` · `Router_Lidar.py:113` · `B06 Server_Calc_Prebuild.py:222` · `common_util_route_geometry.py:350` · `common_util_drainage_context.py:147` | +| B05 추천 노선 비용면 | DTM 2 m 격자 자리에서 RBF 셈 · 실패하면 조용히 DTM 으로 대신함 | `B05_Profile_Engine_Solver.py:116-134` · `:143-144` · `:178-211` | +| B05 · B06 브라우저 즉시 계산 | 격자는 DTM 일 때만 줌 · implicit 면 None → 서버 표본 길(±표본만) · 사면이 표본 밖으로 나가면 B06 「지형 범위 밖」 배지 · [저장] 때 서버가 넓힘 | `B05_Profile_Router_Terrain.py:180-205`(188) · `B06_Section_UI_Cross_Card_Chrome.ts:113-120` | +| B05 · B06 Node 측점 생성 | DTM 격자만 받음 · implicit 면 파이썬 `generate_sections` 로 넘김 | `B05_Profile_Engine_Sections_Node.py:10-12` · `:160` · `B06_Section_Server_Calc_Prebuild.py:263-273` | +| B07 유역 음영 | implicit 를 무시하고 `dtm_{필터}[_smooth].npz` 씀 | `B07_DesignDetail_Router_Support_Basin.py:481-484` | +| D03 라이다 · 급경사 · 0차곡 | implicit 를 무시하고 DTM 씀 | `D03_PlanAnalysis_TerrainSource.py:106-109` · `D03_PlanAnalysis_Lidar.py:80` · `B05_Profile_Router_Lidar.py:244` | +| 프로젝트 복사 | DTM 파일만 짚음 | `common_util_project_copy.py:473-474` | + +- DTM 처럼 x · y · z · valid_mask 를 기대해 implicit 를 못 읽는 곳은 없음. 다만 위 아래 다섯 줄은 implicit 를 아예 보지 않고 DTM 으로 감 → implicit 를 확정해도 그 화면들은 DTM 값을 씀. +- 격자로 굳혀 두는 곳은 없음. 미리보기 GLB(약 1.07 m)와 등고선 json 만 구워 둠. + +## ③ 누락 원인 + +| 후보 | 판정 | 근거 | +| --- | --- | --- | +| **외곽 규칙**(닫기 1 m · 가장 큰 덩이 · 안쪽 1 m) | **주 원인 · 모든 표현 공통** | `ModelContext.py:283-313` · 분류 기준 유효 범위는 상자의 40.2 %, 점 찍힌 칸은 61.6 % → 스캔의 34.8 % 를 버림(CSF 는 11.4 %) · 버린 띠 10.9 만 m² 안에 업체 지면점 9.5 만 개 · 띠 칸에서 지면점까지 중앙 1.4 m · 90 % 3.6 m | +| implicit 계산 실패 · 빈 값 | 아님 | 미리보기 꼭짓점 200,908 개가 DTM 과 같은 자리 · NaN 0 · manifest 세 벌 모두 completed(36 · 40 · 34 s) | +| 미리보기 꼭짓점 상한 50 만 | 아님 | 모든 표현이 같은 격자 · 칸만 1.07 m 로 굵어짐(`ModelContext.py:366-375`) | +| 등고선 | 아님 | 유효 10 m 칸 중 등고선이 지나는 칸 99.4 %(DTM 99.1 · TIN 97.3) | +| 다른 모델 valid_mask 빌림 | 누락을 늘리진 않음 · implicit 는 외곽 밖까지 셈할 수 있으나 DTM 외곽으로 자름 | `Engine_Contour.py:446-448` · `surface_sampler.py:224` · 1만 중심점 일부는 외곽 밖에 있음(그림 `m1_centers_classification.png`) | +| 1만 점 분포 | 빈 곳은 아님 · 세부 손실 | 외곽 칸에서 가장 가까운 중심점까지 중앙 3.2 m · 90 % 6.7 m · 최대 18.6 m · 10 m 넘게 먼 칸 1.4 % | +| 시간 초과 · 타일 | 아님 | 제한 0 = 없음(`config_system_terrain.py:94` · `Pipeline.py:276`) · 타일은 코드에 없음(`ModelBuild.py:174-175`) | +| 설계 화면(B06) | implicit 확정 때만 생김 | 브라우저는 격자 없이 ±표본만 받아 끝에서 자름 → 「지형 범위 밖」 배지(위 표) | + +- 그림: `tmp/brain_557/m2_cover_classification.png` — 보라 = 스캔됐으나 버린 자리 · 회색 = 지면점 칸 · 초록 = 유효하나 지면점 없는 칸. `m2_hs_classification.png` · `m2_hs_csf.png` — 음영(왼쪽부터 DTM · TIN · implicit · NURBS). 네 벌의 외곽이 같음. +- CSF + implicit 의 흠은 누락이 아니라 **혹**임. 미리보기 기준 DTM 과 5 m 넘게 다른 꼭짓점이 4.6 %(분류는 0.02 %)임. 나무 점이 지면으로 잡힌 자리가 1만 점에 섞여 둥근 혹이 됨(음영 그림 오른쪽 위). + +## ④ 매끄러움의 정체 + +점 간격: + +- 1만 점 / 외곽 23.2 만 m² = 23 m² 당 1 점 → 평균 4.8 m 간격. 원 지면점보다 114 배 성김. +- 점 수가 고정이라 2 km² 사업이면 약 14 m 간격이 됨(`ModelBuild.py:174-175`). +- 기록 차례대로 고르므로 점이 많은 트인 곳에 몰리고 숲 밑은 성김(중심점끼리 가장 가까운 거리 중앙 1.26 m · 99 % 10.3 m). + +검사점 대조(30 만 점 · 같은 외곽 안 · 차 = 점 − 면): + +| 면 | 평균 | RMS | 95 % | 기울기 30 % 미만 | 100 % 넘음 | +| --- | --- | --- | --- | --- | --- | +| DTM | +0.601 | 0.766 | 1.372 | 0.329 | 1.572 | +| DTM 평활 | +0.603 | 0.752 | 1.336 | 0.346 | 1.527 | +| TIN | −0.000 | 0.087 | 0.168 | 0.103 | 0.117 | +| TIN 평활 | −0.002 | 0.253 | 0.515 | 0.340 | 0.340 | +| **implicit(저장 1만)** | −0.002 | **0.279** | 0.530 | 0.381 | 0.392 | +| NURBS | +2.176 | 2.569 | 4.232 | 1.714 | 3.974 | + +단면 8 개(80 m · 선 양옆 0.5 m 안 업체 지면점 1 m 칸 중앙값 대비 · RMS / 최대 m): + +| 단면 · 꼴 | 지면 높이차 | DTM | DTM 평활 | TIN | implicit 1만(저장) | implicit 20만 | +| --- | --- | --- | --- | --- | --- | --- | +| S1 좁은 능선 | 35.2 | 0.67 / 1.51 | 0.68 / 1.45 | 0.21 / 0.56 | **1.48 / 3.64** | 0.22 / 0.50 | +| S2 둔덕 · 바위 | 16.1 | 0.48 / 1.26 | 0.40 / 1.00 | 0.24 / 0.54 | **1.25 / 3.97** | 0.43 / 1.33 | +| S3 볼록 꺾임 | 23.4 | 0.71 / 1.09 | 0.69 / 1.09 | 0.22 / 0.38 | 0.35 / 1.21 | 0.25 / 0.53 | +| S4 볼록 꺾임 | 27.2 | 0.55 / 1.13 | 0.56 / 1.08 | 0.23 / 0.57 | 0.30 / 0.58 | 0.24 / 0.57 | +| S5 볼록 꺾임 | 20.6 | 0.72 / 1.60 | 0.68 / 1.12 | 0.25 / 0.87 | 0.43 / 1.39 | 0.18 / 0.42 | +| S6 골 | 15.1 | 0.77 / 1.57 | 0.76 / 1.49 | 0.16 / 0.47* | 0.33 / 1.07 | 0.16 / 0.44 | +| S7 골 | 10.2 | 0.58 / 1.07 | 0.57 / 1.03 | 0.17 / 0.39* | 0.30 / 0.49 | 0.16 / 0.33 | +| S8 왼위 굽은 턱(깎기 꼴) | 38.1 | 1.78 / 4.68 | 1.70 / 4.48 | 0.26 / 0.76* | 0.31 / 0.62 | 0.23 / 0.63 | + +\* = TIN 1 m 격자 값. 자리 = `m3_result.json` · 음영 `m3_crops.png`(S1~5) · `m3_crops2.png`(S6~8). + +- 깎이는 예: S1 마루 지면 855.75 m → implicit 852.45 m(−3.3 m) · S2 둔덕 840.09 → 836.12 m(−4.0 m). +- 골 · 넓은 비탈 · 턱(S6~S8)은 지면점이 많아 1만 점으로도 0.3 m 안팎임. 반대로 DTM 은 턱(S8)에서 1.8 m 틀림(칸 최저점 · 가까운 값 메움 · 553-A). +- **어떤 1만 점이 뽑히느냐에 따라 흔들림.** 검사점 10 % 를 빼고 다시 뽑자 S1 RMS 1.48 → 0.69 m · S3 0.35 → 0.80 m 로 바뀜. +- 임도 노면 단면은 못 잼. 라이다 범위 안에 도엽 도로중심선 · 성절토가 0 개임. S8 은 음영으로 본 깎기 턱 꼴이고, 노면인지는 확인 안 함. + +등고선(가운데 200 m 칸 · 1 m 간격): + +| 면 | 길이(TIN = 1) | 15 m 안 되는 조각(잔고리) | +| --- | --- | --- | +| DTM | 1.12 | 102 | +| DTM 평활 | 1.00 | 42 | +| TIN | 1.00 | 152 | +| implicit 1만 | 0.93 | **9** | +| implicit 5만 | 0.95 | 13 | +| implicit 20만 | 0.97 | 36 | +| implicit 전부 | 0.99 | 74 | + +→ 「매끄러운 등고선」 = 잔고리가 거의 없는 것. 그 값으로 좁은 볼록 자리 3~4 m 를 내줌. + +## ⑤ 매개변수 감도 + +조건 — 지면점 90 % 로 짓고, 남긴 10 % 중 10 만 점으로 잼. 앱 `build_implicit` 그대로 · 한 갈래당 한 프로세스. + +| 점 수 | smoothing | 짓기(s) | 메모리(+MB) | 검사점 RMS | 95 % | 1 m 넘음 % | 단면 최대 | 표본 10 만 점(s) | npz | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 1만 | 0.1 | 35.2 | 144 | 0.274 | 0.528 | 1.13 | 3.68 | 8.2 | 74 KB | +| 5만 | 0.1 | 46.7 | 152 | 0.158 | 0.296 | 0.22 | 1.24 | 11.2 | 343 KB | +| 20만 | 0.1 | 51.2 | 166 | 0.108 | 0.202 | 0.04 | 1.33 | 12.8 | 1.2 MB | +| 20만 | 0 | 51.9 | 166 | 0.113 | 0.218 | 0.05 | 1.40 | 13.0 | 1.2 MB | +| 20만 | 1 | 50.6 | 167 | 0.110 | 0.204 | 0.05 | 1.35 | 12.8 | 1.2 MB | +| 20만 | 10 | 51.9 | 166 | 0.126 | 0.238 | 0.06 | 1.58 | 13.7 | 1.2 MB | +| 전부(101 만) | 0.1 | 61.4 | 243 | 0.071 | 0.141 | 0.01 | 0.70 | 14.8 | 5.5 MB | + +- **매끄러움을 조절하는 손잡이는 점 수임.** smoothing 은 0~10 에서 RMS 0.11~0.13 m로 차이가 작아 손잡이로 못 씀. +- 점을 늘려도 비용이 작음. 짓는 시간 대부분은 미리보기 꼭짓점 약 50 만 개를 셈하는 데 듦. 게다가 외곽 밖(이 사업 상자의 약 60 %)까지 셈한 뒤 자름(`ModelBuild.py:188-202`). +- 등고선은 부를 때마다 1 m 격자 전체(57.8 만 칸)를 한 번에 다시 셈 → 짓는 시간과 비슷할 것으로 추정함(캐시 뒤엔 0). +- 설계 표본은 부를 때마다 RBF 를 다시 지음. 10 만 점에 8~15 s, 노선 표고 한 번(최대 4,000 점)은 1 s 안팎으로 추정함. +- 타일 — 이웃 64 개만 쓰는 국소식이라, 타일로 나눠도 결과 · 시간이 거의 같음(추정). 필요한 것은 타일이 아니라 「넓이에 비례한 점 수」(예 m² 당 0.2~1 점)임. +- 씨닝(1 억 점 넘음) 자료도 지면점은 수백만 개 수준 → 전부 써도 메모리 수백 MB 대로 추정함. + +## ⑥ 누락 처리 후보 (제안만) + +| 후보 | 하는 일 | 좋은 점 | 걸림 | 고칠 자리 | +| --- | --- | --- | --- | --- | +| A 외곽 틈 닫기 1 → 3 m | 덩이 끊김을 줄임 | 덮임 스캔 65.2 → 94.1 % · 23.2 → 34.1 만 m² · 지면점에서 5 m 넘게 먼 칸 1.1 % · 숫자 하나만 바꿈 | 모든 표현 · 화면에 번짐 · DTM 은 메운 칸 49 → 59 %(계단 늘어남) · 되살린 띠는 점이 성김 | `config_system_terrain.py:98`(5 m 면 97.9 % · 10 m 면 98.8 %) | +| B 가장 큰 덩이 → 넓이 문턱(예 500 m² 이상 모두) | 떨어진 섬을 살림 | 다른 자료에서 섬 살림(이 자료는 닫기 3 m 와 결과 같음) | 섬 사이 빈칸 | `ModelContext.py:294-301` | +| C implicit 점 수를 넓이에 비례 | 성긴 띠 · 좁은 능선 정확도를 올림 | 되살린 띠 RMS 1.22 → 0.24 m(20만) · 시간 +16 s | 잔고리 9 → 36 개 | `ModelBuild.py:174-175` · `config_system_terrain.py:114-117` | +| D 덩이 대신 「지면점까지 거리 x m 안」으로 자름 | 점이 닿는 곳만 남김 | 규칙이 눈에 보임 · 덩이 개념 없음 | 숲 속에 작은 구멍 | `ModelContext.py:265-317` | +| E 점 없는 곳 표시(신뢰 층) | 자르지 않고 「지면점에서 몇 m」 색으로 보이고 설계 화면에 경고 | 요구 557 「데이터 품질만 확인」에 맞음 | 새 층 · 화면 일 | 새 거리 격자 · B04 지도 층 | +| F 바깥 · 구멍을 수치지형도로 메움 | 라이다 밖을 `sheet_laplace` 로 | 설계 경계가 안 끊김 | 높이 차(라이다 − 지형도 중앙 −2.29 m · 553-A) → 이음매 계단 | 「분석 지형」 바꿈 길이 이미 있음(`common_util_surface_confirmation.py:85-101`) | +| G implicit 를 DTM 꼴로 굳힘 | 1 m 격자(x · y · z · valid_mask)로 셈해 `dtm_*` 자리처럼 내보냄 | 브라우저 · Node · B07 · D03 이 그대로 implicit 를 씀 · 화면 = 저장 | 1 m 해상도로 고정 · 새 필터 열쇠로 둘지, DTM 짓기를 바꿀지 결정 필요 | `ModelContext.py:336-364`(grid) 또는 빌더에서 굳힌 격자 저장 · 553-A ④ 경계 C · D | +| H RBF 를 외곽 밖까지 그대로 | 셈은 이미 상자 전체에서 함 → 자르기만 늦춤 | 코드가 적음 | 점 없는 곳은 식이 지어낸 값(평면 늘임) · 표시 없이 쓰면 위험 | `ModelBuild.py:201` · `Engine_Contour.py:446` | + +- 같이 갈 짝 = **A + C**(덮임 + 띠 정확도). 화면 전부 일치까지 원하면 **+ G**. +- 비교 잣대(요구 557 「그 값과 비교」) — 이번 틀(업체 지면점 검사점 RMS · 단면 8 개 · 등고선 잔고리 수)에 넣으려면, 바깥 도구 결과를 `dtm_*.npz` 꼴로 옮기기만 하면 됨(553 표와 같은 잣대). +- 분류 없는 길 실측(업체 지면점 10 만 대비 RMS): + + | 길 | RMS | 95 % | + | --- | --- | --- | + | 내장 CSF + implicit 1만 | 0.57 m | 0.85 m | + | CSF DTM | 0.91 m | — | + | CSF TIN | 0.52 m | 0.28 m | + | 553 PDAL SMRF + TIN | 0.27 m | — | + | 553 WBT 경사 필터 + TIN | 0.26 m | — | + + 분류 없는 자료에선 implicit 보다 내장 CSF(지면 가르기)가 먼저 걸림. + +곁 발견: + +- NURBS 는 화면과 설계가 다른 면을 씀. 설계 표본은 평활 없이 다시 맞추고(`surface_sampler.py:248-255`), B04 화면 · 등고선은 평활 계수를 줌(`ModelContext.py:48-55`). 검사점 평균 +2.18 m · RMS 2.57 m. +- TIN 평활본이 TIN 보다 나쁨(RMS 0.087 → 0.253 m). + +산출물(`tmp/brain_557/`): `m1_result.json` · `m2_*.png` · `m2_result.json` · `m3_result.json` · `m3_profiles.json` · `m3_crops*.png` · `m4_result.jsonl` · `m5_result.json` · `m6_result.json` · `m7_result.json` · `m8_result.json` — 측정 스크립트 · 중간 파일은 지움.