Hi, I think it’s obviously. In the source code:
def matrix_to_euler_angles(mat: np.ndarray, degrees: bool = False, extrinsic: bool = True) -> np.ndarray:
"""Convert rotation matrix to Euler XYZ extrinsic or intrinsic angles.
Args:
mat (np.ndarray): A 3x3 rotation matrix.
degrees (bool, optional): Whether returned angles should be in degrees.
extrinsic (bool, optional): True if the rotation matrix follows the extrinsic matrix
convention (equivalent to ZYX ordering but returned in the reverse) and False if it follows
the intrinsic matrix conventions (equivalent to XYZ ordering).
Defaults to True.
Returns:
np.ndarray: Euler XYZ angles (intrinsic form) if extrinsic is False and Euler XYZ angles (extrinsic form) if extrinsic is True.
"""
if extrinsic:
if mat[2, 0] > _POLE_LIMIT:
roll = np.arctan2(mat[0, 1], mat[0, 2])
pitch = -np.pi / 2
yaw = 0.0
return np.array([roll, pitch, yaw])
if mat[2, 0] < -_POLE_LIMIT:
roll = np.arctan2(mat[0, 1], mat[0, 2])
pitch = np.pi / 2
yaw = 0.0
return np.array([roll, pitch, yaw])
roll = np.arctan2(mat[2, 1], mat[2, 2])
pitch = -np.arcsin(mat[2, 0])
yaw = np.arctan2(mat[1, 0], mat[0, 0])
if degrees:
roll = math.degrees(roll)
pitch = math.degrees(pitch)
yaw = math.degrees(yaw)
return np.array([roll, pitch, yaw])
else:
if mat[0, 2] > _POLE_LIMIT:
roll = np.arctan2(mat[1, 0], mat[1, 1])
pitch = np.pi / 2
yaw = 0.0
return np.array([roll, pitch, yaw])
if mat[0, 2] < -_POLE_LIMIT:
roll = np.arctan2(mat[1, 0], mat[1, 1])
pitch = -np.pi / 2
yaw = 0.0
return np.array([roll, pitch, yaw])
roll = -math.atan2(mat[1, 2], mat[2, 2])
pitch = math.asin(mat[0, 2])
yaw = -math.atan2(mat[0, 1], mat[0, 0])
if degrees:
roll = math.degrees(roll)
pitch = math.degrees(pitch)
yaw = math.degrees(yaw)
return np.array([roll, pitch, yaw])
if pitch = ± pi / 2, the function will directly return, and will not go to the “if degrees” branch.