File size: 3,412 Bytes
4c75661 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | """src/vkgs/src/sensors.hpp (๋ ์ด์บ์คํธ ๋ผ์ด๋คยท๋ ์ด๋) ๋ฅผ g++ ๋ก ์ปดํ์ผํด ์ํํ๋ค. ์ฐฝ์ ๋์ฐ์ง ์๋๋ค.
๋ณต์
์๋๋ nusim.sim.voxels ๋ก ๋ง๋ ๋ค โ ํ์ผ ํ์์ PythonยทC++ ์์ชฝ์ด ๊ฐ๊ฒ ์ฝ๋์ง๋ ๊ฐ์ด ๋ณธ๋ค."""
import os
import shutil
import subprocess
from pathlib import Path
import numpy as np
import pytest
from nusim.sim.voxels import read_voxels, write_grid
ROOT = Path(__file__).resolve().parents[1]
CXX = os.environ.get("CXX") or "g++"
def _world(path: Path):
g = np.mgrid[-30:30:0.1, -30:30:0.1].reshape(2, -1).T
ground = np.c_[g, np.full(len(g), 0.1)] # ์ง๋ฉด ์นธ z 0 ~ 0.2
yz = np.mgrid[-30:30:0.1, 0:6:0.1].reshape(2, -1).T
wall = np.c_[np.full(len(yz), 20.1), yz] # x = 20 ~ 20.2
pts = np.vstack([ground, ground, wall, wall]) # ์นธ๋ง๋ค 2์ ์ด์
return write_grid(path, pts, np.array([-30.0, -30.0, -2.0]), np.array([30.0, 30.0, 10.0]))
def test_voxels_roundtrip(tmp_path):
_world(tmp_path / "w.vox")
occ, lo, res = read_voxels(tmp_path / "w.vox")
assert not occ[int((5 - lo[0]) / res), int((0 - lo[1]) / res), int((0.1 - lo[2]) / res)] # ์ง๋ฉด์ ๋์ด ์ง๋๊ฐ ๋งก๋๋ค (๋ณต์
์๋)
assert occ[int((20.1 - lo[0]) / res), int((0 - lo[1]) / res), int((3 - lo[2]) / res)] # ๋ฒฝ
assert not occ[int((5 - lo[0]) / res), int((0 - lo[1]) / res), int((2 - lo[2]) / res)] # ๋น ๊ณต๊ฐ
@pytest.mark.skipif(shutil.which(CXX) is None, reason="g++ ์์")
def test_sensors(tmp_path):
_world(tmp_path / "w.vox")
exe = tmp_path / "t"
subprocess.run([CXX, "-std=c++20", "-O2", "-pthread", "-I", str(ROOT / "src/vkgs/src"),
str(ROOT / "tests/cpp/test_sensors.cpp"), "-o", str(exe)], check=True)
r = subprocess.run([str(exe), str(tmp_path / "w.vox")], capture_output=True, text=True)
assert r.returncode == 0, r.stdout + r.stderr
@pytest.mark.skipif(not (ROOT / "build" / "vkgs_voxcarve").exists(), reason="build/vkgs_voxcarve ์์ (cmake --build build)")
def test_free_space_carving(tmp_path):
"""๋น ๊ณต๊ฐ ๊น๊ธฐ: ํ sweep ์๋ง ์ฐํ '์ง๋๊ฐ ์ฐจ ์กฐ๊ฐ' ์ ๋ค๋ฅธ sweep ์ ๋น์ด ๊ทธ ์๋ฆฌ๋ฅผ ์ง๋๊ฐ๋ฏ๋ก ์ง์์ง๊ณ ,
๋งค sweep ์ฐํ๋ ๋ฒฝ์ ๋จ๋๋ค (nusim.sim.voxels.carve, src/vkgs/src/voxcarve.cpp)."""
rng = np.random.default_rng(0)
org, ends, sweep = [], [], []
for s in range(20): # ์์ฐจ๊ฐ x 0 โ 19 m ๋ก ๊ฐ๋ฉฐ 20 sweep
o = np.array([float(s), 0.0, 1.8])
org.append(o)
# ๋ฒฝ (x = 30, ๋์ด 0.5~3 m): ๋งค sweep
wall = np.c_[np.full(400, 30.1), rng.uniform(-3, 3, 400), rng.uniform(0.5, 3, 400)]
pts = [wall]
if s == 3: # ์ง๋๊ฐ ์ฐจ ์กฐ๊ฐ (x 15, y 0, ๋์ด 0.5 m) โ ํ sweep ์๋ง
pts.append(np.c_[rng.normal(15, 0.03, 50), rng.normal(0, 0.03, 50), rng.normal(0.5, 0.03, 50)])
p = np.vstack(pts)
ends.append(p)
sweep.append(np.full(len(p), s, np.int32))
pts = np.vstack(ends)
lo, hi = np.array([-5.0, -10.0, -2.0]), np.array([40.0, 10.0, 8.0])
write_grid(tmp_path / "w.vox", pts, lo, hi, rays=(np.array(org), np.concatenate(sweep)))
occ, lo2, res = read_voxels(tmp_path / "w.vox")
at = lambda x, y, z: occ[int((x - lo2[0]) / res), int((y - lo2[1]) / res), int((z - lo2[2]) / res)]
assert not at(15.0, 0.0, 0.5) # ๊น์๋ค
assert at(30.1, 0.0, 1.5) # ๋ฒฝ์ ๋จ๋๋ค
|