def pointcloud_to_sparse_voxel_grid_unbatched(points, features, grid_cell_size,
                                              segment_func):
  """Converts a pointcloud into a voxel grid.

  This function does not handle batch size and only works for a single batch
  of points. The function `pointcloud_to_sparse_voxel_grid` below calls this
  function in a while loop to map a batch of points to a batch of voxels.

  A sparse voxel grid is represented by only keeping the voxels that
  have points in them in memory. Assuming that N' voxels have points in them,
  we represent a sparse voxel grid by
    (a) voxel_features, a [N', F] or [N', G, F] tensor containing the feature
          vector for each voxel.
    (b) voxel_indices, a [N', 3] tensor containing the x, y, z index of each
          voxel.

  Args:
    points: A tf.float32 tensor of size [N, 3].
    features: A tf.float32 tensor of size [N, F].
    grid_cell_size: The size of the grid cells in x, y, z dimensions in the
      voxel grid. It should be either a tf.float32 tensor, a numpy array or a
      list of size [3].
    segment_func: A tensorflow function that operates on segments. Examples are
      one of tf.math.unsorted_segment_{min/max/mean/prod/sum}.

  Returns:
    voxel_features: A tf.float32 tensor of size [N', F] or [N', G, F] where G is
      the number of points sampled per voxel.
    voxel_indices: A tf.int32 tensor of size [N', 3].
    segment_ids: A size [N] tf.int32 tensor of IDs for each point indicating
      which (flattened) voxel cell its data was mapped to.
    voxel_start_location: A tf.float32 tensor of size [3] containing the start
      location of the voxels.

  Raises:
    ValueError: If pooling method is unknown.
  """
  grid_cell_size = tf.convert_to_tensor(grid_cell_size, dtype=tf.float32)
  voxel_xyz_indices, voxel_single_number_indices, voxel_start_location = (
      _points_to_voxel_indices(points=points, grid_cell_size=grid_cell_size))
  voxel_features, segment_ids, num_segments = pool_features_given_indices(
      features=features,
      indices=voxel_single_number_indices,
      segment_func=segment_func)
  voxel_xyz_indices = tf.math.unsorted_segment_max(
      data=voxel_xyz_indices,
      segment_ids=segment_ids,
      num_segments=num_segments)
  return voxel_features, voxel_xyz_indices, segment_ids, voxel_start_location