code: def _marching_cubes_lewiner(
      volume,
      level,
      spacing,
      gradient_direction,
      step_size,
      allow_degenerate,
      use_classic,
      mask,
  ):
      """Lewiner et al. algorithm for marching cubes. See
      marching_cubes_lewiner for documentation.
  
      """
  
      # Check volume and ensure its in the format that the alg needs
      if not isinstance(volume, np.ndarray) or (volume.ndim != 3):
          raise ValueError("Input volume should be a 3D numpy array.")
      if (
          volume.shape[0] < 2
          or volume.shape[1] < 2
          or volume.shape[2] < 2
      ):
          raise ValueError("Input array must be at least 2x2x2.")
      volume = np.ascontiguousarray(
          volume, np.float32
      )  # no copy if not necessary
  
      # Check/convert other inputs:
      # level
      if level is None:
          level = 0.5 * (volume.min() + volume.max())
      else:
          level = float(level)
          if level < volume.min() or level > volume.max():
              raise ValueError(
                  "Surface level must be within volume data range."
              )
      # spacing
      if len(spacing) != 3:
          raise ValueError("`spacing` must consist of three floats.")
      # step_size
      step_size = int(step_size)
      if step_size < 1:
          raise ValueError("step_size must be at least one.")
      # use_classic
      use_classic = bool(use_classic)
  
      # Get LutProvider class (reuse if possible)
      L = _get_mc_luts()
  
      # Check if a mask array is passed
      if mask is not None:
          if not mask.shape == volume.shape:
              raise ValueError(
                  "volume and mask must have the same shape."
              )
  
      # Apply algorithm
      func = _marching_cubes_lewiner_cy.marching_cubes
      vertices, faces, normals, values = func(
          volume, level, L, step_size, use_classic, mask
      )
  
      if not len(vertices):
          raise RuntimeError("No surface found at the given iso value.")
  
      # Output in z-y-x order, as is common in skimage
      vertices = np.fliplr(vertices)
      normals = np.fliplr(normals)
  
      # Finishing touches to output
      faces.shape = -1, 3
      if gradient_direction == "descent":
          # MC implementation is right-handed, but gradient_direction is
          # left-handed
          faces = np.fliplr(faces)
      elif not gradient_direction == "ascent":
          raise ValueError(
              f"Incorrect input {gradient_direction} in `gradient_direction`, "
              "see docstring."
          )
      if not np.array_equal(spacing, (1, 1, 1)):
          vertices = vertices * np.r_[spacing]
  
      if allow_degenerate:
          return vertices, faces, normals, values
      else:
          fun = _marching_cubes_lewiner_cy.remove_degenerate_faces
          return fun(
              vertices.astype(np.float32), faces, normals, values
          )
  
file_path: scikit-image/skimage/measure/_marching_cubes_lewiner.py
imports: import base64
  import numpy
  from .None import _marching_cubes_lewiner_luts
  from .None import _marching_cubes_lewiner_cy
label_desc: Use image node_id 2 for calling a global function with example usage: _marching_cubes_lewiner(volume, level, spacing, gradient_direction, step_size, allow_degenerate, use_classic, mask) and returns: vertices,  faces,  normals,  values, fun