code: def from_quaternion(
      quaternions: type_alias.TensorLike,
      name: str = "euler_from_quaternion",
  ) -> tf.Tensor:
      """Converts quaternions to Euler angles.
  
      Args:
        quaternions: A tensor of shape `[A1, ..., An, 4]`, where the last dimension
          represents a normalized quaternion.
        name: A name for this op that defaults to "euler_from_quaternion".
  
      Returns:
        A tensor of shape `[A1, ..., An, 3]`, where the last dimension represents
        the three Euler angles.
      """
  
      def general_case(r00, r10, r21, r22, r20, eps_addition):
          """Handles the general case."""
          theta_y = -tf.asin(r20)
          sign_cos_theta_y = safe_ops.nonzero_sign(tf.cos(theta_y))
          r00 = safe_ops.nonzero_sign(r00) * eps_addition + r00
          r22 = safe_ops.nonzero_sign(r22) * eps_addition + r22
          theta_z = tf.atan2(
              r10 * sign_cos_theta_y, r00 * sign_cos_theta_y
          )
          theta_x = tf.atan2(
              r21 * sign_cos_theta_y, r22 * sign_cos_theta_y
          )
          return tf.stack((theta_x, theta_y, theta_z), axis=-1)
  
      def gimbal_lock(r01, r02, r20, eps_addition):
          """Handles Gimbal locks."""
          sign_r20 = safe_ops.nonzero_sign(r20)
          r02 = safe_ops.nonzero_sign(r02) * eps_addition + r02
          theta_x = tf.atan2(-sign_r20 * r01, -sign_r20 * r02)
          theta_y = -sign_r20 * tf.constant(
              math.pi / 2.0, dtype=r20.dtype
          )
          theta_z = tf.zeros_like(theta_x)
          angles = tf.stack((theta_x, theta_y, theta_z), axis=-1)
          return angles
  
      with tf.name_scope(name):
          quaternions = tf.convert_to_tensor(value=quaternions)
  
          shape.check_static(
              tensor=quaternions,
              tensor_name="quaternions",
              has_dim_equals=(-1, 4),
          )
  
          x, y, z, w = tf.unstack(quaternions, axis=-1)
          tx = safe_ops.safe_shrink(2.0 * x, -2.0, 2.0, True)
          ty = safe_ops.safe_shrink(2.0 * y, -2.0, 2.0, True)
          tz = safe_ops.safe_shrink(2.0 * z, -2.0, 2.0, True)
          twx = tx * w
          twy = ty * w
          twz = tz * w
          txx = tx * x
          txy = ty * x
          txz = tz * x
          tyy = ty * y
          tyz = tz * y
          tzz = tz * z
  
          # The following is clipped due to numerical instabilities that can take some
          # enties outside the [-1;1] range.
          r00 = safe_ops.safe_shrink(1.0 - (tyy + tzz), -1.0, 1.0, True)
          r10 = safe_ops.safe_shrink(txy + twz, -1.0, 1.0, True)
          r21 = safe_ops.safe_shrink(tyz + twx, -1.0, 1.0, True)
          r22 = safe_ops.safe_shrink(1.0 - (txx + tyy), -1.0, 1.0, True)
          r20 = safe_ops.safe_shrink(txz - twy, -1.0, 1.0, True)
          r01 = safe_ops.safe_shrink(txy - twz, -1.0, 1.0, True)
          r02 = safe_ops.safe_shrink(txz + twy, -1.0, 1.0, True)
          eps_addition = asserts.select_eps_for_addition(
              quaternions.dtype
          )
          general_solution = general_case(
              r00, r10, r21, r22, r20, eps_addition
          )
          gimbal_solution = gimbal_lock(r01, r02, r20, eps_addition)
          # The general solution is unstable close to the Gimbal lock, and the gimbal
          # solution is not toooff in these cases.
          is_gimbal = tf.less(tf.abs(tf.abs(r20) - 1.0), 1.0e-6)
          gimbal_mask = tf.stack(
              (is_gimbal, is_gimbal, is_gimbal), axis=-1
          )
          return tf.where(
              gimbal_mask, gimbal_solution, general_solution
          )
  
file_path: graphics/tensorflow_graphics/geometry/transformation/euler.py
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import math
  import tensorflow
  from tensorflow_graphics.geometry.transformation import quaternion
  from tensorflow_graphics.geometry.transformation import rotation_matrix_3d
  from tensorflow_graphics.util import asserts
  from tensorflow_graphics.util import export_api
  from tensorflow_graphics.util import safe_ops
  from tensorflow_graphics.util import shape
  from tensorflow_graphics.util import type_alias
label_desc: Use image node_id 2 for calling a global function with example usage: from_quaternion(quaternions, name) and returns: tf, angles, tf