From cda037e10c156af1f812e3122e68e4414b1554ff Mon Sep 17 00:00:00 2001
From: Andrew Maclean <andrew.amaclean@gmail.com>
Date: Fri, 18 Oct 2024 14:16:46 +1100
Subject: [PATCH] Adding ClipClosedSurface

---
 src/PythonicAPI.md                            |   1 +
 src/PythonicAPI/Meshes/ClipClosedSurface.py   | 128 ++++++++++++++++++
 src/PythonicAPI/Snippets/VTKDataClasses.md    |  13 ++
 .../Meshes/TestClipClosedSurface.png          |   3 +
 4 files changed, 145 insertions(+)
 create mode 100644 src/PythonicAPI/Meshes/ClipClosedSurface.py
 create mode 100644 src/Testing/Baseline/PythonicAPI/Meshes/TestClipClosedSurface.png

diff --git a/src/PythonicAPI.md b/src/PythonicAPI.md
index e5e784c2931..1bd02d93048 100644
--- a/src/PythonicAPI.md
+++ b/src/PythonicAPI.md
@@ -248,6 +248,7 @@ This section includes examples of manipulating meshes.
 | -------------- | ------------- | ------- |
 [BoxClipStructuredPoints](/PythonicAPI/Visualization/BoxClipStructuredPoints) | Clip vtkStructuredPoints with a box. The results are unstructured grids with tetrahedra.
 [BoxClipUnstructuredGrid](/PythonicAPI/Visualization/BoxClipUnstructuredGrid) | Clip a vtkUnstructuredGrid with a box. The results are unstructured grids with tetrahedra.
+[ClipClosedSurface](/PythonicAPI/Meshes/ClipClosedSurface) | Clip a surface with multiple planes.
 [ClipDataSetWithPolyData](/PythonicAPI/Meshes/ClipDataSetWithPolyData) | Clip a vtkRectilinearGrid with arbitrary polydata. In this example, use a vtkConeSource to generate polydata to slice the grid, resulting in an unstructured grid.
 [ClipDataSetWithPolyData1](/PythonicAPI/Meshes/ClipDataSetWithPolyData1) | Clip a vtkRectilinearGrid with arbitrary polydata. In this example, use a vtkConeSource to generate polydata to slice the grid, resulting in an unstructured grid.
 [SolidClip](/PythonicAPI/Meshes/SolidClip) | Create a "solid" clip. The "ghost" of the part clipped away is also shown.
diff --git a/src/PythonicAPI/Meshes/ClipClosedSurface.py b/src/PythonicAPI/Meshes/ClipClosedSurface.py
new file mode 100644
index 00000000000..3623a6e9e82
--- /dev/null
+++ b/src/PythonicAPI/Meshes/ClipClosedSurface.py
@@ -0,0 +1,128 @@
+# !/usr/bin/env python3
+
+from dataclasses import dataclass
+from pathlib import Path
+
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkInteractionStyle
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkRenderingOpenGL2
+from vtkmodules.vtkCommonColor import vtkNamedColors
+from vtkmodules.vtkCommonDataModel import (
+    vtkPlane,
+    vtkPlaneCollection
+)
+from vtkmodules.vtkFiltersGeneral import vtkClipClosedSurface
+from vtkmodules.vtkFiltersSources import vtkSphereSource
+from vtkmodules.vtkIOXML import vtkXMLPolyDataReader
+from vtkmodules.vtkRenderingCore import (
+    vtkActor,
+    vtkDataSetMapper,
+    vtkRenderer,
+    vtkRenderWindow,
+    vtkRenderWindowInteractor,
+)
+
+def get_program_parameters():
+    import argparse
+    description = 'Demonstrate the clipping of polygonal data.'
+    epilogue = '''
+'''
+    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
+                                     formatter_class=argparse.RawTextHelpFormatter)
+    parser.add_argument('file_name', nargs='?', default=None, help='A VTK Poly Data file e.g. cow.vtp')
+
+    args = parser.parse_args()
+    return args.file_name
+
+
+def main():
+    colors = vtkNamedColors()
+
+    fn = get_program_parameters()
+    if fn:
+        fn_path = Path(fn)
+        if not fn_path.is_file():
+            print('Unable to find: ', fn_path)
+            return
+        else:
+            reader = vtkXMLPolyDataReader(file_name=fn_path)
+            poly_data = reader.update().output
+    else:
+        source = vtkSphereSource(center=(0.0, 0.0, 0.0), radius=1.0, theta_resolution=20, phi_resolution=11)
+        poly_data = source.update().output
+
+    center = poly_data.GetCenter()
+    plane1 = vtkPlane(origin=(center[0], center[1], center[2]), normal=(0.0, -1.0, 0.0))
+    plane2 = vtkPlane(origin=(center[0], center[1], center[2]), normal=(0.0, 0.0, 1.0))
+    plane3 = vtkPlane(origin=(center[0], center[1], center[2]), normal=(-1.0, 0.0, 0.0))
+
+    planes = vtkPlaneCollection()
+    planes.AddItem(plane1)
+    planes.AddItem(plane2)
+    planes.AddItem(plane3)
+
+    clipper = vtkClipClosedSurface(input_data=poly_data, clipping_planes=planes, active_plane_id=2,
+                                   scalar_mode=ClipClosedSurface.ScalarMode.VTK_CCS_SCALAR_MODE_COLORS)
+    clipper.clip_color = colors.GetColor3d('Banana')
+    clipper.base_color = colors.GetColor3d('Tomato')
+    clipper.active_plane_color = colors.GetColor3d('SandyBrown')
+
+    clip_mapper = vtkDataSetMapper()
+    clipper >> clip_mapper
+
+    clip_actor = vtkActor(mapper=clip_mapper)
+    clip_actor.property.color = colors.GetColor3d('Tomato')
+    clip_actor.property.interpolation = Property.Interpolation.VTK_FLAT
+
+    # Create the graphics stuff.
+    ren = vtkRenderer(background=colors.GetColor3d('SteelBlue'))
+
+    ren_win = vtkRenderWindow(size=(512, 512), window_name='ClipClosedSurface')
+    ren_win.AddRenderer(ren)
+
+    iren = vtkRenderWindowInteractor()
+    iren.render_window = ren_win
+
+    # Add the actors to the renderer, set the background and size.
+    ren.AddActor(clip_actor)
+
+    # Generate an interesting view.
+    ren.ResetCamera()
+    ren.active_camera.Azimuth(120)
+    ren.active_camera.Elevation(30)
+    ren.active_camera.Dolly(1.0)
+    ren.ResetCameraClippingRange()
+
+    ren_win.Render()
+    iren.Initialize()
+    iren.Start()
+
+
+@dataclass(frozen=True)
+class ClipClosedSurface:
+    @dataclass(frozen=True)
+    class ScalarMode:
+        VTK_CCS_SCALAR_MODE_NONE: int = 0
+        VTK_CCS_SCALAR_MODE_COLORS: int = 1
+        VTK_CCS_SCALAR_MODE_LABELS: int = 2
+
+
+@dataclass(frozen=True)
+class Property:
+    @dataclass(frozen=True)
+    class Interpolation:
+        VTK_FLAT: int = 0
+        VTK_GOURAUD: int = 1
+        VTK_PHONG: int = 2
+        VTK_PBR: int = 3
+
+    @dataclass(frozen=True)
+    class Representation:
+        VTK_POINTS: int = 0
+        VTK_WIREFRAME: int = 1
+        VTK_SURFACE: int = 2
+
+
+if __name__ == '__main__':
+    main()
diff --git a/src/PythonicAPI/Snippets/VTKDataClasses.md b/src/PythonicAPI/Snippets/VTKDataClasses.md
index 5d8894e7eda..26acaec5e0d 100644
--- a/src/PythonicAPI/Snippets/VTKDataClasses.md
+++ b/src/PythonicAPI/Snippets/VTKDataClasses.md
@@ -94,6 +94,19 @@ class ButtonSource:
 
 ```
 
+### ClipClosedSurface
+
+``` Python
+@dataclass(frozen=True)
+class ClipClosedSurface:
+    @dataclass(frozen=True)
+    class ScalarMode:
+        VTK_CCS_SCALAR_MODE_NONE: int = 0
+        VTK_CCS_SCALAR_MODE_COLORS: int = 1
+        VTK_CCS_SCALAR_MODE_LABELS: int = 2
+
+```
+
 ### ColorTransferFunction
 
 ``` Python
diff --git a/src/Testing/Baseline/PythonicAPI/Meshes/TestClipClosedSurface.png b/src/Testing/Baseline/PythonicAPI/Meshes/TestClipClosedSurface.png
new file mode 100644
index 00000000000..0ca41003034
--- /dev/null
+++ b/src/Testing/Baseline/PythonicAPI/Meshes/TestClipClosedSurface.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3e4b27484bfb7ac80d137589de512b790de719941d00f4677cd984adcd607efb
+size 6695
-- 
GitLab