class_docstr: An internal class to manage filters/algorithms for polydata datasets.
class_docstr_tok: ["An","internal","class","to","manage","filters\/algorithms","for","polydata","datasets","."]
docstr: Perform multiple ray trace calculations.
  
  This requires a mesh with only triangular faces, an array of
  origin points and an equal sized array of direction vectors to
  trace along.
  
  The embree library used for vectorization of the ray traces is
  known to occasionally return no intersections where the VTK
  implementation would return an intersection.  If the result
  appears to be missing some intersection points, set
  ``retry=True`` to run a second pass over rays that returned no
  intersections, using :func:`PolyDataFilters.ray_trace`.
  
  Parameters
  ----------
  origins : array_like[float]
      Starting point for each trace.
  
  directions : array_like[float]
      Direction vector for each trace.
  
  first_point : bool, default: False
      Returns intersection of first point only.
  
  retry : bool, default: False
      Will retry rays that return no intersections using
      :func:`PolyDataFilters.ray_trace`.
  
  Returns
  -------
  intersection_points : numpy.ndarray
      Location of the intersection points.  Empty array if no
      intersections.
  
  intersection_rays : numpy.ndarray
      Indices of the ray for each intersection point. Empty array if no
      intersections.
  
  intersection_cells : numpy.ndarray
      Indices of the intersection cells.  Empty array if no
      intersections.
  
  Examples
  --------
  Compute the intersection between rays from the origin in
  directions ``[1, 0, 0]``, ``[0, 1, 0]`` and ``[0, 0, 1]``, and
  a sphere with radius 0.5 centered at the origin
  
  >>> import pyvista as pv  # doctest:+SKIP
  >>> sphere = pv.Sphere()  # doctest:+SKIP
  >>> points, rays, cells = sphere.multi_ray_trace(
  ...     [[0, 0, 0]] * 3,
  ...     [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
  ...     first_point=True,
  ... )  # doctest:+SKIP
  >>> string = ", ".join(
  ...     [
  ...         f"({point[0]:.3f}, {point[1]:.3f}, {point[2]:.3f})"
  ...         for point in points
  ...     ]
  ... )  # doctest:+SKIP
  >>> f'Rays intersected at {string}'  # doctest:+SKIP
  'Rays intersected at (0.499, 0.000, 0.000), (0.000, 0.497, 0.000), (0.000, 0.000, 0.500)'
docstr_tok: ["Perform","multiple","ray","trace","calculations",".","This","requires","a","mesh","with","only","triangular","faces",",","an","array","of","origin","points","and","an","equal","sized","array","of","direction","vectors","to","trace","along",".","The","embree","library","used","for","vectorization","of","the","ray","traces","is","known","to","occasionally","return","no","intersections","where","the","VTK","implementation","would","return","an","intersection",".","If","the","result","appears","to","be","missing","some","intersection","points",",","set","``","retry=True","``","to","run","a","second","pass","over","rays","that","returned","no","intersections",",","using",":","func",":","`","PolyDataFilters.ray_trace","`",".","Parameters","--","--","--","--","--","origins",":","array_like","[","float","]","Starting","point","for","each","trace",".","directions",":","array_like","[","float","]","Direction","vector","for","each","trace",".","first_point",":","bool",",","default",":","False","Returns","intersection","of","first","point","only",".","retry",":","bool",",","default",":","False","Will","retry","rays","that","return","no","intersections","using",":","func",":","`","PolyDataFilters.ray_trace","`",".","Returns","--","--","--","-","intersection_points",":","numpy.ndarray","Location","of","the","intersection","points",".","Empty","array","if","no","intersections",".","intersection_rays",":","numpy.ndarray","Indices","of","the","ray","for","each","intersection","point",".","Empty","array","if","no","intersections",".","intersection_cells",":","numpy.ndarray","Indices","of","the","intersection","cells",".","Empty","array","if","no","intersections",".","Examples","--","--","--","--","Compute","the","intersection","between","rays","from","the","origin","in","directions","``","[","1",",","0",",","0","]","``",",","``","[","0",",","1",",","0","]","``","and","``","[","0",",","0",",","1","]","``",",","and","a","sphere","with","radius","0.5","centered","at","the","origin",">",">",">","import","pyvista","as","pv","#","doctest",":","+SKIP",">",">",">","sphere","=","pv.Sphere","(",")","#","doctest",":","+SKIP",">",">",">","points",",","rays",",","cells","=","sphere.multi_ray_trace","(","...","[","[","0",",","0",",","0","]","]","*","3",",","...","[","[","1",",","0",",","0","]",",","[","0",",","1",",","0","]",",","[","0",",","0",",","1","]","]",",","...","first_point=True",",","...",")","#","doctest",":","+SKIP",">",">",">","string","=","``",",","``",".join","(","...","[","...","f","''","(","{","point","[","0","]",":",".3f","}",",","{","point","[","1","]",":",".3f","}",",","{","point","[","2","]",":",".3f","}",")","''","...","for","point","in","points","...","]","...",")","#","doctest",":","+SKIP",">",">",">","f'Rays","intersected","at","{","string","}","'","#","doctest",":","+SKIP","'Rays","intersected","at","(","0.499",",","0.000",",","0.000",")",",","(","0.000",",","0.497",",","0.000",")",",","(","0.000",",","0.000",",","0.500",")","'"]
code: def multi_ray_trace(
      self, origins, directions, first_point=False, retry=False
  ):  # pragma: no cover
      """Perform multiple ray trace calculations.
  
      This requires a mesh with only triangular faces, an array of
      origin points and an equal sized array of direction vectors to
      trace along.
  
      The embree library used for vectorization of the ray traces is
      known to occasionally return no intersections where the VTK
      implementation would return an intersection.  If the result
      appears to be missing some intersection points, set
      ``retry=True`` to run a second pass over rays that returned no
      intersections, using :func:`PolyDataFilters.ray_trace`.
  
      Parameters
      ----------
      origins : array_like[float]
          Starting point for each trace.
  
      directions : array_like[float]
          Direction vector for each trace.
  
      first_point : bool, default: False
          Returns intersection of first point only.
  
      retry : bool, default: False
          Will retry rays that return no intersections using
          :func:`PolyDataFilters.ray_trace`.
  
      Returns
      -------
      intersection_points : numpy.ndarray
          Location of the intersection points.  Empty array if no
          intersections.
  
      intersection_rays : numpy.ndarray
          Indices of the ray for each intersection point. Empty array if no
          intersections.
  
      intersection_cells : numpy.ndarray
          Indices of the intersection cells.  Empty array if no
          intersections.
  
      Examples
      --------
      Compute the intersection between rays from the origin in
      directions ``[1, 0, 0]``, ``[0, 1, 0]`` and ``[0, 0, 1]``, and
      a sphere with radius 0.5 centered at the origin
  
      >>> import pyvista as pv  # doctest:+SKIP
      >>> sphere = pv.Sphere()  # doctest:+SKIP
      >>> points, rays, cells = sphere.multi_ray_trace(
      ...     [[0, 0, 0]] * 3,
      ...     [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
      ...     first_point=True,
      ... )  # doctest:+SKIP
      >>> string = ", ".join(
      ...     [
      ...         f"({point[0]:.3f}, {point[1]:.3f}, {point[2]:.3f})"
      ...         for point in points
      ...     ]
      ... )  # doctest:+SKIP
      >>> f'Rays intersected at {string}'  # doctest:+SKIP
      'Rays intersected at (0.499, 0.000, 0.000), (0.000, 0.497, 0.000), (0.000, 0.000, 0.500)'
  
      """
      if not self.is_all_triangles:
          raise NotAllTrianglesError(
              "Input mesh for multi_ray_trace must be all triangles."
          )
  
      try:
          import pyembree  # noqa: F401
          import rtree  # noqa: F401
          import trimesh
      except ImportError:
          raise ImportError(
              "To use multi_ray_trace please install trimesh, rtree and pyembree with:\n"
              "\tconda install trimesh rtree pyembree"
          )
  
      origins = np.asarray(origins)
      directions = np.asarray(directions)
      tmesh = trimesh.Trimesh(self.points, self.regular_faces)
      locations, index_ray, index_tri = tmesh.ray.intersects_location(
          origins, directions, multiple_hits=not first_point
      )
      if retry:
          # gather intersecting rays in lists
          loc_lst = locations.tolist()
          ray_lst = index_ray.tolist()
          tri_lst = index_tri.tolist()
  
          # find indices that trimesh failed on
          all_ray_indices = np.arange(len(origins))
          retry_ray_indices = np.setdiff1d(
              all_ray_indices, index_ray, assume_unique=True
          )
  
          # compute ray points for all failed rays at once
          origins_retry = origins[
              retry_ray_indices, :
          ]  # shape (n_retry, 3)
          directions_retry = directions[retry_ray_indices, :]
          unit_directions = directions_retry / np.linalg.norm(
              directions_retry, axis=1, keepdims=True
          )
          second_points = (
              origins_retry + unit_directions * self.length
          )  # shape (n_retry, 3)
  
          for id_r, origin, second_point in zip(
              retry_ray_indices, origins_retry, second_points
          ):
              locs, indices = self.ray_trace(
                  origin, second_point, first_point=first_point
              )
              if locs.any():
                  if first_point:
                      locs = locs.reshape([1, 3])
                  ray_lst.extend([id_r] * indices.size)
                  tri_lst.extend(indices)
                  loc_lst.extend(locs)
  
          # sort result arrays by ray index
          index_ray = np.array(ray_lst)
          sorting_inds = index_ray.argsort()
          index_ray = index_ray[sorting_inds]
          index_tri = np.array(tri_lst)[sorting_inds]
          locations = np.array(loc_lst)[sorting_inds]
  
      return locations, index_ray, index_tri
  
imports: import collections.abc
  import warnings
  import numpy
  import pyvista
  from pyvista.core import _vtk_core
  from pyvista.core.errors import MissingDataError, NotAllTrianglesError, PyVistaFutureWarning, VTKVersionError
  from pyvista.core.filters import _get_output, _update_alg
  from pyvista.core.filters.data_set import DataSetFilters
  from pyvista.core.utilities.arrays import FieldAssociation, get_array, get_array_association, set_default_active_scalars, vtk_id_list_to_array
  from pyvista.core.utilities.geometric_objects import NORMALS
  from pyvista.core.utilities.helpers import generate_plane, wrap
  from pyvista.core.utilities.misc import abstract_class, assert_empty_kwargs
label_desc: Use image node_id 28 for calling the PolyDataFilters obj's underlying member method code with example usage: obj.multi_ray_trace(origins, directions, first_point, retry) and returns: locations,  index_ray,  index_tri