앞선 두 커밋(c3f643b, 7d50ded)으로도 증상이 남아 헤드리스 크롬으로 실제 앱에 로그인해
B05 3D를 끌어 보며 측정했다. 원인은 회전 계산이 아니라 **탑뷰 카메라 자리**였다.
카메라를 정확히 수직으로 세우면(기존 top = [0, distance, 0.001], 극각 1e-6도) lookAt이
화면의 가로·세로 방향을 정하지 못한다. 그 자리에서 벗어나는 순간 화면 축이 180° 돌아간다.
실측(2px 드래그 6걸음):
before 극각 0.00° -> 0.86°, 1걸음째 화면축 반전, 이후 같은 방향 드래그 먹통
after 극각 2.00° -> 1.15°, 반전 0회, 반대 방향 20걸음도 반전 0회(1.15° -> 130°)
- TOP_VIEW_TILT(2°) 신설 — 화면상 위에서 내려다보는 그림과 구분되지 않으면서 여유각
(POLAR_EPSILON, 약 1.15°)보다 바깥이라 첫 드래그부터 회전이 이어진다.
- B05 노선 뷰어, B04 지형·포인트클라우드 뷰어의 탑뷰 세 곳에 모두 적용.
typecheck·prettier 통과, 정적 번들 재빌드.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
계획노선 CSV로 만든 제어점에는 표고가 없다(z: null). modelToScene이 point.z - cz를
계산하는데 JS에서 null - 548.5 = -548.5이라, BP·EP·경유점 135개가 전부 지형 중심보다
548m 아래 수평면에 깔렸다. 화면에서는 노선 모양이 평면에 투영된 주황 구슬 커브로
보였고(경유점 색 0xf59e0b), 원근 때문에 지형 밖으로 밀려 나갔다.
- markerElevation() 신설: 표고가 있으면 그 값, 없으면 시·종점만 지형 표면을 찾아 얹는다.
표고 없는 경유점은 그리지 않는다 — 그 자리는 경로선으로 이미 보이고, CSV 정점
전부(여기선 133개)에 마커를 세우면 노선이 구슬에 덮인다.
- 뷰어에 terrainElevation() 추가: 지형 위에서 수직으로 광선을 쏴 표면 높이를 읽는다.
- renderRoute도 같은 함정을 막는다: z ?? 0 대신 지형 표고 → 직전 점 높이 순으로 채운다.
경고 구간이 인덱스로 점 배열을 다시 자르므로 점 개수는 그대로 둔다.
typecheck·prettier 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>