feat(640-2): implicit 점 수 = 지면점 비율 · 격자 칸 뽑기 · 설정 지문 바뀌면 다시 지음
- SURFACE_IMPLICIT_POINT_RATIO 0.175 · _MIN_POINTS 5 만 · _MAX_POINTS 200 만(옛 _MAX_POINTS_PER_TILE 걷음) - TerrainContext.grid_sample — 칸 = √(외곽 넓이 / 점 수) · 씨앗 558 · 칸마다 하나 · 모자라면 무작위 채움(sample() 그대로) - 짓기 캐시 흠 — manifest 항목 완료일 때만 재사용(지문 바뀐 뒤 implicit · nurbs · meshfree 옛 파일 재사용 막음) - 지킴 시험 test_640_lidar_default 점 수 · 격자 뽑기 · 지문 다시 지음 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,8 @@ ProgressCallback = Callable[[int], None]
|
||||
|
||||
# 대용량 포인트 배치 처리 크기
|
||||
_BATCH_SIZE = 500_000
|
||||
# implicit 격자 칸 뽑기 씨앗 — 고정이라 다시 지어도 같은 중심점
|
||||
IMPLICIT_SAMPLE_SEED = 558
|
||||
|
||||
# NURBS 평활 계수 — 제어점당 허용 잔차제곱(m²).
|
||||
# 0.01(RMS 0.1m)은 요구가 너무 빡빡해 FITPACK이 제어점 수(122x113)보다 많은
|
||||
@@ -262,6 +264,30 @@ class TerrainContext:
|
||||
self._samples[maximum] = points
|
||||
return points
|
||||
|
||||
def grid_sample(self, count: int, seed: int = IMPLICIT_SAMPLE_SEED) -> np.ndarray:
|
||||
"""implicit 전용 — 격자 칸(√(외곽 넓이 / 점 수))마다 하나 · 모자라면 무작위로 채움.
|
||||
|
||||
파일 차례 뽑기는 점 많은 트인 곳에 몰려 숲 밑 성긴 곳이 빔(요구 558). 씨앗 고정.
|
||||
"""
|
||||
indices = self.indices()
|
||||
if len(indices) <= count:
|
||||
return np.asarray(self.xyz[indices], dtype=np.float32)
|
||||
_, _, resolution, footprint = self.footprint()
|
||||
cell = max(math.sqrt(float(footprint.sum()) * resolution * resolution / count), 0.01)
|
||||
xy = np.asarray(self.xyz[indices][:, :2], dtype=np.float64)
|
||||
rng = np.random.default_rng(seed)
|
||||
order = rng.permutation(len(indices))
|
||||
gx = ((xy[order, 0] - self.bounds[0, 0]) // cell).astype(np.int64)
|
||||
gy = ((xy[order, 1] - self.bounds[1, 0]) // cell).astype(np.int64)
|
||||
_, first = np.unique(gy * (int(gx.max()) + 1) + gx, return_index=True)
|
||||
chosen = order[first]
|
||||
if len(chosen) > count:
|
||||
chosen = rng.choice(chosen, count, replace=False)
|
||||
elif len(chosen) < count:
|
||||
rest = np.setdiff1d(np.arange(len(indices)), chosen, assume_unique=True)
|
||||
chosen = np.concatenate([chosen, rng.choice(rest, count - len(chosen), replace=False)])
|
||||
return np.asarray(self.xyz[indices[np.sort(chosen)]], dtype=np.float32)
|
||||
|
||||
def footprint(self) -> tuple[float, float, float, np.ndarray]:
|
||||
if self._footprint is not None:
|
||||
return self._footprint
|
||||
|
||||
Reference in New Issue
Block a user