From d9f38815d694685bad09a565c797ce8bdba9750f Mon Sep 17 00:00:00 2001
From: Andrew Maclean <andrew.amaclean@gmail.com>
Date: Fri, 23 Feb 2024 08:26:07 +1100
Subject: [PATCH] Adding SmoothMeshGrid.py and updating to use vtkTextwidget

---
 src/PythonicAPI/PolyData/SmoothMeshGrid.md    |   7 +
 src/PythonicAPI/PolyData/SmoothMeshGrid.py    | 214 ++++++++++++++++++
 .../PolyData/TestSmoothMeshGrid.png           |   3 +
 3 files changed, 224 insertions(+)
 create mode 100644 src/PythonicAPI/PolyData/SmoothMeshGrid.md
 create mode 100755 src/PythonicAPI/PolyData/SmoothMeshGrid.py
 create mode 100644 src/Testing/Baseline/PythonicAPI/PolyData/TestSmoothMeshGrid.png

diff --git a/src/PythonicAPI/PolyData/SmoothMeshGrid.md b/src/PythonicAPI/PolyData/SmoothMeshGrid.md
new file mode 100644
index 00000000000..e25771c8ee9
--- /dev/null
+++ b/src/PythonicAPI/PolyData/SmoothMeshGrid.md
@@ -0,0 +1,7 @@
+### Description
+
+Create a terrain with regularly spaced points. The triangles are created manually. Then different types of smoothing filters are used to smooth the terrain.
+
+Left : initial terrain, middle : vtkLoopSubdivisionFilter, right : vtkButterflySubdivisionFilter
+
+* Contributed by Michka Popoff, with the help of Bill Lorensen and madz (madaramh).
diff --git a/src/PythonicAPI/PolyData/SmoothMeshGrid.py b/src/PythonicAPI/PolyData/SmoothMeshGrid.py
new file mode 100755
index 00000000000..a4c8978d221
--- /dev/null
+++ b/src/PythonicAPI/PolyData/SmoothMeshGrid.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python3
+
+import numpy
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkInteractionStyle
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkRenderingOpenGL2
+from vtkmodules.vtkCommonColor import vtkNamedColors
+from vtkmodules.vtkCommonCore import (
+    vtkMinimalStandardRandomSequence,
+    vtkPoints,
+    vtkUnsignedCharArray
+)
+from vtkmodules.vtkCommonDataModel import (
+    vtkCellArray,
+    vtkPolyData,
+    vtkTriangle
+)
+from vtkmodules.vtkFiltersCore import vtkCleanPolyData
+from vtkmodules.vtkFiltersModeling import (
+    vtkButterflySubdivisionFilter,
+    vtkLoopSubdivisionFilter
+)
+from vtkmodules.vtkInteractionWidgets import (
+    vtkTextRepresentation,
+    vtkTextWidget
+)
+from vtkmodules.vtkRenderingCore import (
+    vtkActor,
+    vtkPolyDataMapper,
+    vtkRenderWindow,
+    vtkRenderWindowInteractor,
+    vtkRenderer,
+    vtkTextActor,
+    vtkTextProperty
+)
+
+
+def main():
+    nc = vtkNamedColors()
+
+    # Make a 32 x 32 grid
+    size = 32
+
+    rn = vtkMinimalStandardRandomSequence(seed=1)
+    # rn.SetSeed(1)
+
+    # Define z values for the topography (random height)
+    topography = numpy.zeros([size, size])
+    for i in range(size):
+        for j in range(size):
+            topography[i][j] = rn.GetRangeValue(0, 5)
+            rn.Next()
+
+    # Define points, triangles and colors
+    colors = vtkUnsignedCharArray()
+    colors.SetNumberOfComponents(3)
+    points = vtkPoints()
+    triangles = vtkCellArray()
+
+    # Build the meshgrid manually
+    count = 0
+    for i in range(size - 1):
+        for j in range(size - 1):
+            z1 = topography[i][j]
+            z2 = topography[i][j + 1]
+            z3 = topography[i + 1][j]
+
+            # Triangle 1
+            points.InsertNextPoint(i, j, z1)
+            points.InsertNextPoint(i, (j + 1), z2)
+            points.InsertNextPoint((i + 1), j, z3)
+
+            triangle = vtkTriangle()
+            triangle.GetPointIds().SetId(0, count)
+            triangle.GetPointIds().SetId(1, count + 1)
+            triangle.GetPointIds().SetId(2, count + 2)
+
+            triangles.InsertNextCell(triangle)
+
+            z1 = topography[i][j + 1]
+            z2 = topography[i + 1][j + 1]
+            z3 = topography[i + 1][j]
+
+            # Triangle 2
+            points.InsertNextPoint(i, (j + 1), z1)
+            points.InsertNextPoint((i + 1), (j + 1), z2)
+            points.InsertNextPoint((i + 1), j, z3)
+
+            triangle = vtkTriangle()
+            triangle.GetPointIds().SetId(0, count + 3)
+            triangle.GetPointIds().SetId(1, count + 4)
+            triangle.GetPointIds().SetId(2, count + 5)
+
+            count += 6
+
+            triangles.InsertNextCell(triangle)
+
+            # Add some color.
+            r = [int(i / float(size) * 255), int(j / float(size) * 255), 0]
+            colors.InsertNextTypedTuple(r)
+            colors.InsertNextTypedTuple(r)
+            colors.InsertNextTypedTuple(r)
+            colors.InsertNextTypedTuple(r)
+            colors.InsertNextTypedTuple(r)
+            colors.InsertNextTypedTuple(r)
+
+    # Create a polydata object.
+    triangle_poly_data = vtkPolyData()
+
+    # Add the geometry and topology to the polydata.
+    triangle_poly_data.SetPoints(points)
+    triangle_poly_data.GetPointData().SetScalars(colors)
+    triangle_poly_data.SetPolys(triangles)
+
+    # Clean the polydata so that the edges are shared!
+    clean_poly_data = vtkCleanPolyData()
+    triangle_poly_data >> clean_poly_data
+
+    # Use a filter to smooth the data (will add triangles and smooth).
+    # Use two different filters to show the difference.
+    smooth_loop = vtkLoopSubdivisionFilter(number_of_subdivisions=3)
+
+    smooth_butterfly = vtkButterflySubdivisionFilter(number_of_subdivisions=3)
+
+    # Create a mapper and actor for the initial dataset.
+    mapper = vtkPolyDataMapper()
+    clean_poly_data >> mapper
+    actor = vtkActor(mapper=mapper)
+
+    # Create a mapper and actor for smoothed dataset (vtkLoopSubdivisionFilter).
+    mapper = vtkPolyDataMapper()
+    clean_poly_data >> smooth_loop >> mapper
+    actor_loop = vtkActor(mapper=mapper)
+
+    # Create a mapper and actor for smoothed dataset (vtkButterflySubdivisionFilter).
+    mapper = vtkPolyDataMapper()
+    clean_poly_data >> smooth_butterfly >> mapper
+    actor_butterfly = vtkActor(mapper=mapper)
+
+    render_window = vtkRenderWindow(size=(900, 300))
+    render_window_interactor = vtkRenderWindowInteractor()
+    render_window_interactor.SetRenderWindow(render_window)
+
+    text = {0: 'Initial Terrain', 1: 'Loop Subdivision', 2: 'Butterfly Subdivision'}
+
+    # Define viewport ranges [x_min, y_min, x_max, y_max]
+    viewports = {0: [0.0, 0.0, 1.0 / 3.0, 1.0],
+                 1: [1.0 / 3.0, 0.0, 2.0 / 3.0, 1.0],
+                 2: [2.0 / 3.0, 0.0, 1.0, 1.0]
+                 }
+    camera = None
+    # Build the renderers and add them to the render window.
+    renderers = list()
+    for k in text.keys():
+        renderers.append(vtkRenderer(background=nc.GetColor3d('Cornsilk')))
+
+        # Add the actors.
+        if k == 0:
+            renderers[k].AddActor(actor)
+        elif k == 1:
+            renderers[k].AddActor(actor_loop)
+        elif k == 2:
+            renderers[k].AddActor(actor_butterfly)
+
+        if k == 0:
+            camera = renderers[k].GetActiveCamera()
+            camera.Elevation(-45)
+            camera.Zoom(2.5)
+        else:
+            renderers[k].SetActiveCamera(camera)
+
+        renderers[k].SetViewport(*viewports[k])
+        renderers[k].ResetCamera()
+
+        render_window.AddRenderer(renderers[k])
+
+    # Create the TextActors.
+    text_actors = list()
+    text_representations = list()
+    text_widgets = list()
+    text_scale_mode = {'none': 0, 'prop': 1, 'viewport': 2}
+    text_property = vtkTextProperty(color=nc.GetColor3d('DarkSlateGray'), bold=True, italic=True, shadow=True,
+                                    font_size=24)
+    text_positions = {0: {'p': [0.35, 0.05, 0], 'p2': [0.20, 0.15,0]},
+                 1: {'p': [0.37, 0.05,0], 'p2': [0.27, 0.15,0]},
+                 2: {'p': [0.3, 0.05,0], 'p2': [0.31, 0.15,0]}
+                 }
+    for k, v in text.items():
+        text_actors.append(
+            vtkTextActor(input=v, text_scale_mode=text_scale_mode['none'], text_property=text_property))
+
+        # Create the text representation. Used for positioning the text_actor.
+        text_representations.append(vtkTextRepresentation(enforce_normalized_viewport_bounds=True))
+        text_representations[k].GetPositionCoordinate().value = text_positions[k]['p']
+        text_representations[k].GetPosition2Coordinate().value = text_positions[k]['p2']
+
+        # Create the TextWidget
+        text_widgets.append(vtkTextWidget(representation=text_representations[k], text_actor=text_actors[k]))
+        text_widgets[k].SetDefaultRenderer(renderers[k])
+        text_widgets[k].SetInteractor(render_window_interactor)
+        text_widgets[k].GetTextActor()
+        text_widgets[k].SelectableOff()
+
+    render_window.Render()
+
+    for k in text.keys():
+        text_widgets[k].On()
+
+    render_window_interactor.Start()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/src/Testing/Baseline/PythonicAPI/PolyData/TestSmoothMeshGrid.png b/src/Testing/Baseline/PythonicAPI/PolyData/TestSmoothMeshGrid.png
new file mode 100644
index 00000000000..96bed825752
--- /dev/null
+++ b/src/Testing/Baseline/PythonicAPI/PolyData/TestSmoothMeshGrid.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a6a2944f9522f38bcfbd5b03e16a7c6529e0bbd516d3e20113598e6982797f2e
+size 138552
-- 
GitLab