class_docstr: A Transform3d object encapsulates a batch of N 3D transformations, and knows
  how to transform points and normal vectors. Suppose that t is a Transform3d;
  then we can do the following:
  
  .. code-block:: python
  
      N = len(t)
      points = torch.randn(N, P, 3)
      normals = torch.randn(N, P, 3)
      points_transformed = t.transform_points(points)    # => (N, P, 3)
      normals_transformed = t.transform_normals(normals)  # => (N, P, 3)
  
  
  BROADCASTING
  Transform3d objects supports broadcasting. Suppose that t1 and tN are
  Transform3d objects with len(t1) == 1 and len(tN) == N respectively. Then we
  can broadcast transforms like this:
  
  .. code-block:: python
  
      t1.transform_points(torch.randn(P, 3))     # => (P, 3)
      t1.transform_points(torch.randn(1, P, 3))  # => (1, P, 3)
      t1.transform_points(torch.randn(M, P, 3))  # => (M, P, 3)
      tN.transform_points(torch.randn(P, 3))     # => (N, P, 3)
      tN.transform_points(torch.randn(1, P, 3))  # => (N, P, 3)
  
  
  COMBINING TRANSFORMS
  Transform3d objects can be combined in two ways: composing and stacking.
  Composing is function composition. Given Transform3d objects t1, t2, t3,
  the following all compute the same thing:
  
  .. code-block:: python
  
      y1 = t3.transform_points(t2.transform_points(t1.transform_points(x)))
      y2 = t1.compose(t2).compose(t3).transform_points(x)
      y3 = t1.compose(t2, t3).transform_points(x)
  
  
  Composing transforms should broadcast.
  
  .. code-block:: python
  
      if len(t1) == 1 and len(t2) == N, then len(t1.compose(t2)) == N.
  
  We can also stack a sequence of Transform3d objects, which represents
  composition along the batch dimension; then the following should compute the
  same thing.
  
  .. code-block:: python
  
      N, M = len(tN), len(tM)
      xN = torch.randn(N, P, 3)
      xM = torch.randn(M, P, 3)
      y1 = torch.cat([tN.transform_points(xN), tM.transform_points(xM)], dim=0)
      y2 = tN.stack(tM).transform_points(torch.cat([xN, xM], dim=0))
  
  BUILDING TRANSFORMS
  We provide convenience methods for easily building Transform3d objects
  as compositions of basic transforms.
  
  .. code-block:: python
  
      # Scale by 0.5, then translate by (1, 2, 3)
      t1 = Transform3d().scale(0.5).translate(1, 2, 3)
  
      # Scale each axis by a different amount, then translate, then scale
      t2 = Transform3d().scale(1, 3, 3).translate(2, 3, 1).scale(2.0)
  
      t3 = t1.compose(t2)
      tN = t1.stack(t3, t3)
  
  
  BACKPROP THROUGH TRANSFORMS
  When building transforms, we can also parameterize them by Torch tensors;
  in this case we can backprop through the construction and application of
  Transform objects, so they could be learned via gradient descent or
  predicted by a neural network.
  
  .. code-block:: python
  
      s1_params = torch.randn(N, requires_grad=True)
      t_params = torch.randn(N, 3, requires_grad=True)
      s2_params = torch.randn(N, 3, requires_grad=True)
  
      t = Transform3d().scale(s1_params).translate(t_params).scale(s2_params)
      x = torch.randn(N, 3)
      y = t.transform_points(x)
      loss = compute_loss(y)
      loss.backward()
  
      with torch.no_grad():
          s1_params -= lr * s1_params.grad
          t_params -= lr * t_params.grad
          s2_params -= lr * s2_params.grad
  
  CONVENTIONS
  We adopt a right-hand coordinate system, meaning that rotation about an axis
  with a positive angle results in a counter clockwise rotation.
  
  This class assumes that transformations are applied on inputs which
  are row vectors. The internal representation of the Nx4x4 transformation
  matrix is of the form:
  
  .. code-block:: python
  
      M = [
              [Rxx, Ryx, Rzx, 0],
              [Rxy, Ryy, Rzy, 0],
              [Rxz, Ryz, Rzz, 0],
              [Tx,  Ty,  Tz,  1],
          ]
  
  To apply the transformation to points, which are row vectors, the latter are
  converted to homogeneous (4D) coordinates and right-multiplied by the M matrix:
  
  .. code-block:: python
  
      points = [[0, 1, 2]]  # (1 x 3) xyz coordinates of a point
      [transformed_points, 1] ∝ [points, 1] @ M
class_docstr_tok: ["A","Transform3d","object","encapsulates","a","batch","of","N","3D","transformations",",","and","knows","how","to","transform","points","and","normal","vectors",".","Suppose","that","t","is","a","Transform3d",";","then","we","can","do","the","following",":","..","code-block",":",":","python","N","=","len","(","t",")","points","=","torch.randn","(","N",",","P",",","3",")","normals","=","torch.randn","(","N",",","P",",","3",")","points_transformed","=","t.transform_points","(","points",")","#","=",">","(","N",",","P",",","3",")","normals_transformed","=","t.transform_normals","(","normals",")","#","=",">","(","N",",","P",",","3",")","BROADCASTING","Transform3d","objects","supports","broadcasting",".","Suppose","that","t1","and","tN","are","Transform3d","objects","with","len","(","t1",")","==","1","and","len","(","tN",")","==","N","respectively",".","Then","we","can","broadcast","transforms","like","this",":","..","code-block",":",":","python","t1.transform_points","(","torch.randn","(","P",",","3",")",")","#","=",">","(","P",",","3",")","t1.transform_points","(","torch.randn","(","1",",","P",",","3",")",")","#","=",">","(","1",",","P",",","3",")","t1.transform_points","(","torch.randn","(","M",",","P",",","3",")",")","#","=",">","(","M",",","P",",","3",")","tN.transform_points","(","torch.randn","(","P",",","3",")",")","#","=",">","(","N",",","P",",","3",")","tN.transform_points","(","torch.randn","(","1",",","P",",","3",")",")","#","=",">","(","N",",","P",",","3",")","COMBINING","TRANSFORMS","Transform3d","objects","can","be","combined","in","two","ways",":","composing","and","stacking",".","Composing","is","function","composition",".","Given","Transform3d","objects","t1",",","t2",",","t3",",","the","following","all","compute","the","same","thing",":","..","code-block",":",":","python","y1","=","t3.transform_points","(","t2.transform_points","(","t1.transform_points","(","x",")",")",")","y2","=","t1.compose","(","t2",")",".compose","(","t3",")",".transform_points","(","x",")","y3","=","t1.compose","(","t2",",","t3",")",".transform_points","(","x",")","Composing","transforms","should","broadcast",".","..","code-block",":",":","python","if","len","(","t1",")","==","1","and","len","(","t2",")","==","N",",","then","len","(","t1.compose","(","t2",")",")","==","N.","We","can","also","stack","a","sequence","of","Transform3d","objects",",","which","represents","composition","along","the","batch","dimension",";","then","the","following","should","compute","the","same","thing",".","..","code-block",":",":","python","N",",","M","=","len","(","tN",")",",","len","(","tM",")","xN","=","torch.randn","(","N",",","P",",","3",")","xM","=","torch.randn","(","M",",","P",",","3",")","y1","=","torch.cat","(","[","tN.transform_points","(","xN",")",",","tM.transform_points","(","xM",")","]",",","dim=0",")","y2","=","tN.stack","(","tM",")",".transform_points","(","torch.cat","(","[","xN",",","xM","]",",","dim=0",")",")","BUILDING","TRANSFORMS","We","provide","convenience","methods","for","easily","building","Transform3d","objects","as","compositions","of","basic","transforms",".","..","code-block",":",":","python","#","Scale","by","0.5",",","then","translate","by","(","1",",","2",",","3",")","t1","=","Transform3d","(",")",".scale","(","0.5",")",".translate","(","1",",","2",",","3",")","#","Scale","each","axis","by","a","different","amount",",","then","translate",",","then","scale","t2","=","Transform3d","(",")",".scale","(","1",",","3",",","3",")",".translate","(","2",",","3",",","1",")",".scale","(","2.0",")","t3","=","t1.compose","(","t2",")","tN","=","t1.stack","(","t3",",","t3",")","BACKPROP","THROUGH","TRANSFORMS","When","building","transforms",",","we","can","also","parameterize","them","by","Torch","tensors",";","in","this","case","we","can","backprop","through","the","construction","and","application","of","Transform","objects",",","so","they","could","be","learned","via","gradient","descent","or","predicted","by","a","neural","network",".","..","code-block",":",":","python","s1_params","=","torch.randn","(","N",",","requires_grad=True",")","t_params","=","torch.randn","(","N",",","3",",","requires_grad=True",")","s2_params","=","torch.randn","(","N",",","3",",","requires_grad=True",")","t","=","Transform3d","(",")",".scale","(","s1_params",")",".translate","(","t_params",")",".scale","(","s2_params",")","x","=","torch.randn","(","N",",","3",")","y","=","t.transform_points","(","x",")","loss","=","compute_loss","(","y",")","loss.backward","(",")","with","torch.no_grad","(",")",":","s1_params","-=","lr","*","s1_params.grad","t_params","-=","lr","*","t_params.grad","s2_params","-=","lr","*","s2_params.grad","CONVENTIONS","We","adopt","a","right-hand","coordinate","system",",","meaning","that","rotation","about","an","axis","with","a","positive","angle","results","in","a","counter","clockwise","rotation",".","This","class","assumes","that","transformations","are","applied","on","inputs","which","are","row","vectors",".","The","internal","representation","of","the","Nx4x4","transformation","matrix","is","of","the","form",":","..","code-block",":",":","python","M","=","[","[","Rxx",",","Ryx",",","Rzx",",","0","]",",","[","Rxy",",","Ryy",",","Rzy",",","0","]",",","[","Rxz",",","Ryz",",","Rzz",",","0","]",",","[","Tx",",","Ty",",","Tz",",","1","]",",","]","To","apply","the","transformation","to","points",",","which","are","row","vectors",",","the","latter","are","converted","to","homogeneous","(","4D",")","coordinates","and","right-multiplied","by","the","M","matrix",":","..","code-block",":",":","python","points","=","[","[","0",",","1",",","2","]","]","#","(","1","x","3",")","xyz","coordinates","of","a","point","[","transformed_points",",","1","]","\u221d","[","points",",","1","]","@","M"]
docstr: Returns a 4×4 matrix corresponding to each transform in the batch.
  
  If the transform was composed from others, the matrix for the composite
  transform will be returned.
  For example, if self.transforms contains transforms t1, t2, and t3, and
  given a set of points x, the following should be true:
  
  .. code-block:: python
  
      y1 = t1.compose(t2, t3).transform(x)
      y2 = t3.transform(t2.transform(t1.transform(x)))
      y1.get_matrix() == y2.get_matrix()
  
  Where necessary, those transforms are broadcast against each other.
  
  Returns:
      A (N, 4, 4) batch of transformation matrices representing
          the stored transforms. See the class documentation for the conventions.
docstr_tok: ["Returns","a","4\u00d74","matrix","corresponding","to","each","transform","in","the","batch",".","If","the","transform","was","composed","from","others",",","the","matrix","for","the","composite","transform","will","be","returned",".","For","example",",","if","self.transforms","contains","transforms","t1",",","t2",",","and","t3",",","and","given","a","set","of","points","x",",","the","following","should","be","true",":","..","code-block",":",":","python","y1","=","t1.compose","(","t2",",","t3",")",".transform","(","x",")","y2","=","t3.transform","(","t2.transform","(","t1.transform","(","x",")",")",")","y1.get_matrix","(",")","==","y2.get_matrix","(",")","Where","necessary",",","those","transforms","are","broadcast","against","each","other",".","Returns",":","A","(","N",",","4",",","4",")","batch","of","transformation","matrices","representing","the","stored","transforms",".","See","the","class","documentation","for","the","conventions","."]
code: def get_matrix(self) -> torch.Tensor:
      """
      Returns a 4×4 matrix corresponding to each transform in the batch.
  
      If the transform was composed from others, the matrix for the composite
      transform will be returned.
      For example, if self.transforms contains transforms t1, t2, and t3, and
      given a set of points x, the following should be true:
  
      .. code-block:: python
  
          y1 = t1.compose(t2, t3).transform(x)
          y2 = t3.transform(t2.transform(t1.transform(x)))
          y1.get_matrix() == y2.get_matrix()
  
      Where necessary, those transforms are broadcast against each other.
  
      Returns:
          A (N, 4, 4) batch of transformation matrices representing
              the stored transforms. See the class documentation for the conventions.
      """
      composed_matrix = self._matrix.clone()
      if len(self._transforms) > 0:
          for other in self._transforms:
              other_matrix = other.get_matrix()
              composed_matrix = _broadcast_bmm(
                  composed_matrix, other_matrix
              )
      return composed_matrix
  
imports: import math
  import os
  import warnings
  from typing import List, Optional, Union
  import torch
  from ..common.datatypes import Device, get_device, make_device
  from ..common.workaround import _safe_det_3x3
  from .rotation_conversions import _axis_angle_rotation
  from .se3 import se3_log_map
label_desc: Use image node_id 5 for calling the Transform3d obj's underlying member method code with example usage: obj.get_matrix() and returns: composed_matrix