code: def dattoxyz(f, c1, c2, d, angle, torsion):
      c1c2 = c2 - c1
      c1f = f - c1
      c1c3 = (
          c1f
          * torch.sum(c1c2 * c1f, dim=-1, keepdim=True)
          / torch.sum(c1f * c1f, dim=-1, keepdim=True)
      )
      c3 = c1c3 + c1
  
      c3c2 = c2 - c3
      c3c4_1 = c3c2 * torch.cos(torsion[:, :, None])
      c3c4_2 = (
          torch.cross(c3c2, c1f)
          / torch.norm(c1f, dim=-1, keepdim=True)
          * torch.sin(torsion[:, :, None])
      )
      c3c4 = c3c4_1 + c3c4_2
  
      new_pos = (
          -c1f
          / torch.norm(c1f, dim=-1, keepdim=True)
          * d[:, :, None]
          * torch.cos(angle[:, :, None])
      )
      new_pos += (
          c3c4
          / torch.norm(c3c4, dim=-1, keepdim=True)
          * d[:, :, None]
          * torch.sin(angle[:, :, None])
      )
      new_pos += f
  
      return new_pos
  
file_path: DIG/dig/ggraph3D/method/G_SphereNet/model/geometric_computing.py
imports: import torch
  from torch_scatter import scatter
  from torch_sparse import SparseTensor
  from math import sqrt, pi
  from torch_geometric.nn import knn_graph
label_desc: Use image node_id 4 for calling a global function with example usage: dattoxyz(f, c1, c2, d, angle, torsion) and returns: new_pos