|
| 1 | +import numpy as np |
| 2 | +import pytest |
| 3 | +from scipy.spatial.distance import mahalanobis |
| 4 | +from scipy.spatial.transform import Rotation as Rot |
| 5 | + |
| 6 | +from genmetaballs.core import fmb, geometry, intersector |
| 7 | + |
| 8 | +FMB = fmb.FMB |
| 9 | +Pose, Vec3D, Rotation, Ray = geometry.Pose, geometry.Vec3D, geometry.Rotation, geometry.Ray |
| 10 | + |
| 11 | + |
| 12 | +@pytest.fixture |
| 13 | +def rng() -> np.random.Generator: |
| 14 | + return np.random.default_rng(0) |
| 15 | + |
| 16 | + |
| 17 | +def test_linear_intersect(rng): |
| 18 | + for _ in range(100): |
| 19 | + # sample |
| 20 | + cam_quat, fmb_quat = rng.uniform(size=(2, 4)).astype(np.float32) |
| 21 | + fmb_extent, fmb_mu = rng.uniform(size=(2, 3)).astype(np.float32) |
| 22 | + cam_tran, ray_dir = rng.uniform(size=(2, 3)).astype(np.float32) |
| 23 | + ray_start = np.zeros(3, dtype=np.float32) # in camera frame |
| 24 | + # ground truth computation |
| 25 | + v = Rot.from_quat(cam_quat).apply(ray_dir) |
| 26 | + fmb_rotmat = Rot.from_quat(fmb_quat).as_matrix() |
| 27 | + cov_inv = fmb_rotmat.T @ np.diag(1 / fmb_extent) @ fmb_rotmat |
| 28 | + t = ((fmb_mu - cam_tran) @ cov_inv @ v) / (v @ cov_inv @ v) |
| 29 | + d = mahalanobis(fmb_mu, cam_tran + t * v, cov_inv) ** 2 |
| 30 | + # cuda computation |
| 31 | + fmb_pose = Pose.from_components(Rotation.from_quat(*fmb_quat), Vec3D(*fmb_mu)) |
| 32 | + cam_pose = Pose.from_components(Rotation.from_quat(*cam_quat), Vec3D(*cam_tran)) |
| 33 | + fmb = FMB(fmb_pose, *fmb_extent) |
| 34 | + ray = Ray(Vec3D(*ray_start), Vec3D(*ray_dir)) |
| 35 | + t_, d_ = intersector.linear_intersect(fmb, ray, cam_pose) |
| 36 | + assert np.isclose(t, t_) and np.isclose(d, d_) |
0 commit comments