Skip to content

Commit 06fb337

Browse files
committed
Fix '*_quat_to_xyz' helpers broken by PR#1478. (#1484)
1 parent 81577d1 commit 06fb337

File tree

2 files changed

+12
-22
lines changed

2 files changed

+12
-22
lines changed

genesis/utils/geom.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,7 @@ def ti_quat_to_xyz(quat):
149149

150150
siny_cosp = q_wz - q_xy
151151
cosy_cosp = 1.0 - (q_yy + q_zz)
152-
hypot_min = ti.min(siny_cosp, cosy_cosp)
153-
hypot_max = ti.max(siny_cosp, cosy_cosp)
154-
cosp = ti.select(hypot_max > 0.0, hypot_max * ti.sqrt(1.0 + (hypot_min / hypot_max) ** 2), 0.0)
152+
cosp = ti.sqrt(cosy_cosp**2 + siny_cosp**2)
155153

156154
roll = ti.atan2(q_wx - q_yz, 1.0 - (q_xx + q_yy))
157155
pitch = ti.atan2(q_xz + q_wy, cosp)
@@ -652,10 +650,7 @@ def _np_quat_to_xyz(quat, rpy=False, out=None):
652650
siny_cosp = q_wz - q_xy
653651
cosr_cosp = 1.0 - (q_xx + q_yy)
654652
cosy_cosp = 1.0 - (q_yy + q_zz)
655-
656-
hypot_min = np.minimum(siny_cosp, cosy_cosp)
657-
hypot_max = np.maximum(siny_cosp, cosy_cosp)
658-
cosp = np.where(hypot_max > 0.0, hypot_max * np.sqrt(1.0 + (hypot_min / hypot_max) ** 2), 0.0)
653+
cosp = np.sqrt(cosy_cosp**2 + siny_cosp**2)
659654

660655
out_[..., 0] = np.arctan2(sinr_cosp, cosr_cosp)
661656
out_[..., 1] = np.arctan2(sinp, cosp)
@@ -678,7 +673,9 @@ def _tc_quat_to_xyz(quat, rpy=False, out=None):
678673
q_yy, q_yz = torch.unbind(q_y * q_vec_s[..., 1:], -1)
679674
q_zz = q_z[..., 0] * q_vec_s[..., 2]
680675

681-
# Compute some intermediary quantities
676+
# Compute some intermediary quantities.
677+
# Numerical robustness of 'cos(pitch)' could be improved using 'hypot' implementation from Eigen:
678+
# https://gitlab.com/libeigen/eigen/-/blob/master/Eigen/src/Core/MathFunctionsImpl.h#L149
682679
if rpy:
683680
sinp = q_wy - q_xz
684681
sinr_cosp = q_wx + q_yz
@@ -689,14 +686,7 @@ def _tc_quat_to_xyz(quat, rpy=False, out=None):
689686
siny_cosp = q_wz - q_xy
690687
cosr_cosp = 1.0 - (q_xx + q_yy)
691688
cosy_cosp = 1.0 - (q_yy + q_zz)
692-
693-
# Use numerical robust formula for computing cos(pitch)
694-
# See Eigen implementation for reference:
695-
# https://gitlab.com/libeigen/eigen/-/blob/master/Eigen/src/Geometry/EulerAngles.h#L45
696-
# https://gitlab.com/libeigen/eigen/-/blob/master/Eigen/src/Core/MathFunctionsImpl.h#L149
697-
hypot_min = torch.minimum(siny_cosp, cosy_cosp)
698-
hypot_max = torch.maximum(siny_cosp, cosy_cosp)
699-
cosp = torch.where(hypot_max > 0.0, hypot_max * torch.sqrt(1.0 + (hypot_min / hypot_max) ** 2), 0.0)
689+
cosp = torch.sqrt(cosy_cosp**2 + siny_cosp**2)
700690

701691
# Roll (x-axis rotation)
702692
out[..., 0] = torch.atan2(sinr_cosp, cosr_cosp)

tests/test_utils.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,14 @@ def test_utils_geom_taichi_inverse(batch_shape):
206206
ti_value_in_args, ti_transform_args, ti_value_out_args, ti_value_inv_out_args = [], [], [], []
207207
for i, shape_arg in enumerate(map(tuple, (*shapes_in, *shapes_value_args, *shapes_value_args))):
208208
if shape_arg in ((4, 4), (3, 3)):
209-
R = gu.rotvec_to_R(np.random.rand(*batch_shape, 3).astype(gs.np_float))
209+
R = gu.rotvec_to_R(np.random.randn(*batch_shape, 3).clip(-1.0, 1.0).astype(gs.np_float))
210210
if shape_arg == (4, 4):
211-
trans = np.random.rand(*batch_shape, 3).astype(gs.np_float)
211+
trans = np.random.randn(*batch_shape, 3).astype(gs.np_float)
212212
np_arg = gu.trans_R_to_T(trans, R)
213213
else:
214214
np_arg = R
215215
else:
216-
np_arg = np.random.rand(*batch_shape, *shape_arg).astype(gs.np_float)
216+
np_arg = np.random.randn(*batch_shape, *shape_arg).clip(-1.0, 1.0).astype(gs.np_float)
217217

218218
ti_type = ti.Vector if len(shape_arg) == 1 else ti.Matrix
219219
ti_arg = ti_type.field(*shape_arg, dtype=gs.ti_float, shape=batch_shape)
@@ -251,7 +251,7 @@ def test_utils_geom_taichi_identity(batch_shape):
251251
for shape_arg in (*shape_args, shape_args[0]):
252252
ti_type = ti.Vector if len(shape_arg) == 1 else ti.Matrix
253253
ti_arg = ti_type.field(*shape_arg, dtype=gs.ti_float, shape=batch_shape)
254-
ti_arg.from_numpy(np.random.rand(*batch_shape, *shape_arg).astype(gs.np_float))
254+
ti_arg.from_numpy(np.random.randn(*batch_shape, *shape_arg).clip(-1.0, 1.0).astype(gs.np_float))
255255
ti_args.append(ti_arg)
256256

257257
num_funcs = len(ti_funcs)
@@ -273,9 +273,9 @@ def test_utils_geom_tensor_identity(batch_shape):
273273
np_args, tc_args = [], []
274274
for shape_arg in (*shape_args, shape_args[0]):
275275
if tuple(shape_arg) == (3, 3):
276-
np_arg = gu.rotvec_to_R(np.random.rand(*batch_shape, 3).astype(gs.np_float))
276+
np_arg = gu.rotvec_to_R(np.random.randn(*batch_shape, 3).clip(-1.0, 1.0).astype(gs.np_float))
277277
else:
278-
np_arg = np.random.rand(*batch_shape, *shape_arg).astype(gs.np_float)
278+
np_arg = np.random.randn(*batch_shape, *shape_arg).clip(-1.0, 1.0).astype(gs.np_float)
279279
tc_arg = torch.as_tensor(np_arg, dtype=gs.tc_float, device=gs.device)
280280
np_args.append(np_arg)
281281
tc_args.append(tc_arg)

0 commit comments

Comments
 (0)