def test15_quat_to_euler(package): Quaternion4f, Array3f, Float = package.Quaternion4f, package.Array3f, package.Float prepare(package) # Gimbal lock at +pi/2 q = Quaternion4f(0, 1.0 / np.sqrt(2), 0, 1.0 / np.sqrt(2)) assert(ek.allclose(ek.quat_to_euler(q), Array3f(0, np.pi / 2, 0))) # Gimbal lock at -pi/2 q = Quaternion4f(0, -1.0 / np.sqrt(2), 0, 1.0 / np.sqrt(2)) assert(ek.allclose(ek.quat_to_euler(q), Array3f(0, -np.pi / 2, 0))) # Quaternion without gimbal lock q = Quaternion4f(0.15849363803863525, 0.5915063619613647, 0.15849363803863525, 0.7745190262794495) e = Array3f(np.pi / 3, np.pi / 3, np.pi / 3) assert(ek.allclose(ek.quat_to_euler(q), e)) # Round trip assert(ek.allclose(e, ek.quat_to_euler(ek.euler_to_quat(e)))) # Euler -> Quat assert(ek.allclose(q, ek.euler_to_quat(e)))
def decompose_transform(self, transform, export_scale = False): ''' Export a transform as a combination of rotation, scale and translation. This helps manually modifying the transform after export (for cameras for instance) Params ------ transform: The Transform4f transform matrix to decompose export_scale: Whether to add a scale property or not. (e.g. don't do it for cameras to avoid clutter) ''' from enoki import transform_decompose, quat_to_euler scale, quat, trans = transform_decompose(transform.matrix) rot = quat_to_euler(quat) params = {} if rot[0] != 0.0: params['rotate_x'] = { 'type': 'rotate', 'x': '1', 'angle': rot[0] * 180 / np.pi } if rot[1] != 0.0: params['rotate_y'] = { 'type': 'rotate', 'y': '1', 'angle': rot[1] * 180 / np.pi } if rot[2] != 0.0: params['rotate_z'] = { 'type': 'rotate', 'z': '1', 'angle': rot[2] * 180 / np.pi } if export_scale and scale != 1.0: params['scale'] = { 'type': 'scale', 'value': "%f %f %f" % (scale[0,0], scale[1,1], scale[2,2]) } if trans != 0.0: params['translate'] = { 'type': 'translate', 'value': "%f %f %f" % (trans[0], trans[1], trans[2]) } return params