Repository: pyvista/pyvista

Issue:
Add a `cast_to_polydata` method for `Cell`
### Describe the feature you would like to be added.

There is a `cast_to_unstructured_grid` method, but sometimes it is needed to have a `PolyData` object instead.  We can check if the cell is:
- 0D -> create PolyData with vertex 
- 1D -> create PolyData with line 
- 2D -> create PolyData with faces (in pyvista terminology)

For example, in #5227 it was requested to get a single streamline from a `PolyData` object with each cell being a single streamline.  When `mesh.get_cell(i)` is used to get a single streamline, it would be better to have the option to cast to `PolyData` so that it has the same options as the original streamlines object.


### Links to VTK Documentation, Examples, or Class Definitions.

_No response_

### Pseudocode or Screenshots

_No response_

Discussion:
MatthewFlamm: As far as I can tell there is no way to construct a Poly Vertex cell through the `PyVista.PolyData` constructor method.  I think we need to add a `vertices` input like `faces` so that it is possible to do this.
github-actions[bot]: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY - APP ID SHA256: fa806a2cf6952a12e6174f41068bd77e8b2eec522017ddd7190a1bd99a7881db -->
🚀 Deployed on https://656551f647d92e0e1f85a1a8--tubular-marzipan-5e01ed.netlify.app
MatthewFlamm: > As far as I can tell there is no way to construct a Poly Vertex cell through the `PyVista.PolyData` constructor method. I think we need to add a `vertices` input like `faces` so that it is possible to do this.
> 
> This feels like a separate PR.

Started in #5245 
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/pyvista/pyvista/pull/5242?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyvista) Report
> Merging [#5242](https://app.codecov.io/gh/pyvista/pyvista/pull/5242?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyvista) (4f5fb9b) into [main](https://app.codecov.io/gh/pyvista/pyvista/commit/19896236df625885e453f95677476ec588434354?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyvista) (1989623) will **decrease** coverage by `7.12%`.
> The diff coverage is `90.90%`.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #5242      +/-   ##
==========================================
- Coverage   96.20%   89.08%   -7.12%     
==========================================
  Files         134      134              
  Lines       22636    22647      +11     
==========================================
- Hits        21776    20175    -1601     
- Misses        860     2472    +1612     
```

</details>

Patch:
diff --git a/pyvista/core/cell.py b/pyvista/core/cell.py
index 973de167..4db8ef2c 100644
--- a/pyvista/core/cell.py
+++ b/pyvista/core/cell.py
@@ -163,6 +163,46 @@ class Cell(_vtk.vtkGenericCell, DataObject):
         """
         self.cast_to_unstructured_grid().plot(**kwargs)
 
+    def cast_to_polydata(self) -> pyvista.PolyData:
+        """Cast this cell to PolyData.
+
+        Can only be used for 0D, 1D, or 2D cells.
+
+        Returns
+        -------
+        pyvista.PolyData
+            This cell cast to a :class:`pyvista.PolyData`.
+
+        Examples
+        --------
+        >>> from pyvista import examples
+        >>> mesh = examples.load_sphere()
+        >>> cell = mesh.get_cell(0)
+        >>> grid = cell.cast_to_polydata()
+        >>> grid  # doctest: +SKIP
+        PolyData (0x7f09ae437b80)
+          N Cells:    1
+          N Points:   3
+          N Strips:   0
+           X Bounds:   0.000e+00, 1.000e+01
+          Y Bounds:   0.000e+00, 2.500e+01
+          Z Bounds:   -1.270e+02, -1.250e+02
+          N Arrays:   0
+
+        """
+        cells = [len(self.point_ids)] + list(range(len(self.point_ids)))
+        if self.dimension == 0:
+            return pyvista.PolyData(self.points.copy(), verts=cells)
+        if self.dimension == 1:
+            return pyvista.PolyData(self.points.copy(), lines=cells)
+        if self.dimension == 2:
+            if self.type == CellType.TRIANGLE_STRIP:
+                return pyvista.PolyData(self.points.copy(), strips=cells)
+            else:
+                return pyvista.PolyData(self.points.copy(), faces=cells)
+        else:
+            raise ValueError(f"3D cells cannot be cast to PolyData: got cell type {self.type}")
+
     def cast_to_unstructured_grid(self) -> pyvista.UnstructuredGrid:
         """Cast this cell to an unstructured grid.
 


Test patch:
diff --git a/tests/core/test_cells.py b/tests/core/test_cells.py
index eb0aebca..b2132477 100644
--- a/tests/core/test_cells.py
+++ b/tests/core/test_cells.py
@@ -31,28 +31,113 @@ grids = [
 ids = [str(type(grid)) for grid in grids]
 
 cells = [
-    example_cells.Hexahedron().get_cell(0),
+    # 0D cells
+    example_cells.Vertex().get_cell(0),
+    example_cells.PolyVertex().get_cell(0),
+    # 1D cells
+    example_cells.Line().get_cell(0),
+    example_cells.PolyLine().get_cell(0),
+    # 2D cells
     example_cells.Triangle().get_cell(0),
-    example_cells.Voxel().get_cell(0),
     example_cells.Quadrilateral().get_cell(0),
-    example_cells.Tetrahedron().get_cell(0),
+    example_cells.Polygon().get_cell(0),
+    example_cells.TriangleStrip().get_cell(0),
+    # 3D cells
+    example_cells.Hexahedron().get_cell(0),
     example_cells.Voxel().get_cell(0),
+    example_cells.Tetrahedron().get_cell(0),
     example_cells.Polyhedron().get_cell(0),
 ]
 types = [
-    CellType.HEXAHEDRON,
+    # 0D cells
+    CellType.VERTEX,
+    CellType.POLY_VERTEX,
+    # 1D cells
+    CellType.LINE,
+    CellType.POLY_LINE,
+    # 2D cells
     CellType.TRIANGLE,
-    CellType.VOXEL,
     CellType.QUAD,
-    CellType.TETRA,
+    CellType.POLYGON,
+    CellType.TRIANGLE_STRIP,
+    # 3D cells
+    CellType.HEXAHEDRON,
     CellType.VOXEL,
+    CellType.TETRA,
     CellType.POLYHEDRON,
 ]
-
-dims = [3, 2, 3, 2, 3, 3, 3]
-npoints = [8, 3, 8, 4, 4, 8, 4]
-nfaces = [6, 0, 6, 0, 4, 6, 4]
-nedges = [12, 3, 12, 4, 6, 12, 6]
+dims = [
+    # 0D cells
+    0,
+    0,
+    # 1D cells
+    1,
+    1,
+    # 2D cells
+    2,
+    2,
+    2,
+    2,
+    # 3D cells
+    3,
+    3,
+    3,
+    3,
+]
+npoints = [
+    # 0D cells
+    1,
+    6,
+    # 1D cells
+    2,
+    4,
+    # 2D cells
+    3,
+    4,
+    6,
+    8,
+    # 3D cells
+    8,
+    8,
+    4,
+    4,
+]
+nfaces = [
+    # 0D cells
+    0,
+    0,
+    # 1D cells
+    0,
+    0,
+    # 2D cells
+    0,
+    0,
+    0,
+    0,
+    # 3D cells
+    6,
+    6,
+    4,
+    4,
+]
+nedges = [
+    # 0D cells
+    0,
+    0,
+    # 1D cells
+    0,
+    0,
+    # 2D cells
+    3,
+    4,
+    6,
+    8,
+    # 3D cells
+    12,
+    12,
+    6,
+    6,
+]
 cell_ids = list(map(repr, types))
 
 
@@ -144,17 +229,17 @@ def test_cell_copy_generic(cell):
     cell = cell.copy()
     cell_copy = cell.copy(deep=True)
     assert cell_copy == cell
-    cell_copy.points[:] = 0
+    cell_copy.points[:] = 1000
     assert cell_copy != cell
 
     cell_copy = cell.copy(deep=False)
     assert cell_copy == cell
-    cell_copy.points[:] = 0
+    cell_copy.points[:] = 1000
     assert cell_copy == cell
 
 
 def test_cell_copy():
-    cell = cells[0].get_face(0)
+    cell = example_cells.Hexahedron().get_cell(0).get_face(0)
     assert isinstance(cell, pv.Cell)
     cell_copy = cell.copy(deep=True)
     assert cell_copy == cell
@@ -238,6 +323,21 @@ def test_cell_cast_to_unstructured_grid(cell):
     grid = cell.cast_to_unstructured_grid()
     assert grid.n_cells == 1
     assert grid.get_cell(0) == cell
+    assert grid.get_cell(0).type == cell.type
+
+
+@pytest.mark.parametrize("cell", cells)
+def test_cell_cast_to_polydata(cell):
+    if cell.dimension == 3:
+        with pytest.raises(
+            ValueError, match=f"3D cells cannot be cast to PolyData: got cell type {cell.type}"
+        ):
+            cell.cast_to_polydata()
+    else:
+        poly = cell.cast_to_polydata()
+        assert poly.n_cells == 1
+        assert poly.get_cell(0) == cell
+        assert poly.get_cell(0).type == cell.type
 
 
 CELL_LIST = [3, 0, 1, 2, 3, 3, 4, 5]