Return the rotation matrix that rotates v1 to v2 in a geodestic manner. Args: v1: (*, 3) direction vector (unit norm), v2: (*, 3) direction vector (unit norm) Returns: (*, 3, 3) rotation matrix (s.t. v2 = R @ v1)
(
v1: T.Union[np.ndarray, torch.Tensor],
v2: T.Union[np.ndarray, torch.Tensor],
)
| 266 | |
| 267 | |
| 268 | def get_min_R( |
| 269 | v1: T.Union[np.ndarray, torch.Tensor], |
| 270 | v2: T.Union[np.ndarray, torch.Tensor], |
| 271 | ) -> T.Union[np.ndarray, torch.Tensor]: |
| 272 | """ |
| 273 | Return the rotation matrix that rotates v1 to v2 in a geodestic manner. |
| 274 | |
| 275 | Args: |
| 276 | v1: (*, 3) direction vector (unit norm), |
| 277 | v2: (*, 3) direction vector (unit norm) |
| 278 | |
| 279 | Returns: |
| 280 | (*, 3, 3) rotation matrix (s.t. v2 = R @ v1) |
| 281 | """ |
| 282 | is_numpy = False |
| 283 | if isinstance(v1, np.ndarray): |
| 284 | is_numpy = True |
| 285 | v1 = torch.from_numpy(v1) |
| 286 | if isinstance(v2, np.ndarray): |
| 287 | is_numpy = True |
| 288 | v2 = torch.from_numpy(v2) |
| 289 | |
| 290 | v1_norm = torch.linalg.vector_norm(v1, ord=2, dim=-1) |
| 291 | v2_norm = torch.linalg.vector_norm(v2, ord=2, dim=-1) |
| 292 | assert torch.allclose(v1_norm, torch.ones(1, dtype=v1_norm.dtype, device=v1.device)) |
| 293 | assert torch.allclose(v2_norm, torch.ones(1, dtype=v2_norm.dtype, device=v2.device)) |
| 294 | |
| 295 | k = torch.cross(v1, v2, dim=-1) # (*, 3) |
| 296 | cos_theta = (v1 * v2).sum(-1) # (*,) |
| 297 | |
| 298 | *b_shape, d = v1.shape |
| 299 | eye3 = torch.eye(3, device=v1.device, dtype=v1.dtype).expand(*b_shape, 3, 3) # (*, 3, 3) |
| 300 | if cos_theta > -1: |
| 301 | Kx = get_cross_product_matrix(k) # (*, 3, 3) |
| 302 | R = eye3 + Kx + (Kx @ Kx) / (1 + cos_theta).unsqueeze(-1).unsqueeze(-1) # (*, 3, 3) |
| 303 | else: |
| 304 | # v1 and v2 point to opposite directions |
| 305 | R = -1 * eye3 |
| 306 | |
| 307 | if is_numpy: |
| 308 | R = R.detach().cpu().numpy() |
| 309 | |
| 310 | return R # (*, 3, 3) |
| 311 | |
| 312 | |
| 313 | def get_cross_product_matrix( |
no test coverage detected