diff --git a/src/PythonicAPI.md b/src/PythonicAPI.md index c306ce48ab0ecf0b656a926bd29c0a8d6b23f73d..a3b6ee01c855b1fce5d8e97592ebec26fd292715 100644 --- a/src/PythonicAPI.md +++ b/src/PythonicAPI.md @@ -58,9 +58,14 @@ This Python script, [SelectExamples](../PythonicAPI/Utilities/SelectExamples), w | -------------- | ------------- | ------- | [ReadAllPolyDataTypesDemo](/PythonicAPI/IO/ReadAllPolyDataTypesDemo) | Read all VTK polydata file types. [ReadExodusData](/PythonicAPI/IO/ReadExodusData) | A simple script for reading and viewing ExodusII data interactively. +[TransientHDFReader](/PythonicAPI/IO/TransientHDFReader) | Read transient data written inside a vtkhdf file. ###### Importers +| Example Name | Description | Image | +| -------------- | ------------- | ------- | +[3DSImporter](/PythonicAPI/IO/3DSImporter) | Import a 3D Studio scene that includes multiple actors. + ##### Output #### VTK Formats @@ -97,8 +102,16 @@ This Python script, [SelectExamples](../PythonicAPI/Utilities/SelectExamples), w ### Sources +| Example Name | Description | Image | +| -------------- | ------------- | ------- | +[TessellatedBoxSource](/PythonicAPI/GeometricObjects/TessellatedBoxSource) | Generate a box with tessellated sides. + ### Non Linear +| Example Name | Description | Image | +| -------------- | ------------- | ------- | +[IsoparametricCellsDemo](/PythonicAPI/GeometricObjects/IsoparametricCellsDemo) | Nonlinear isoparametric cell types in VTK. + ### Parametric Objects | Example Name | Description | Image | @@ -118,7 +131,6 @@ This Python script, [SelectExamples](../PythonicAPI/Utilities/SelectExamples), w [SampleFunction](/PythonicAPI/ImplicitFunctions/SampleFunction) | Sample and visualize an implicit function. [SmoothDiscreteFlyingEdges3D](/PythonicAPI/Modelling/SmoothDiscreteFlyingEdges3D) | Generate smooth surfaces from labeled data. - ## Working with 3D Data | Example Name | Description | Image | @@ -153,7 +165,6 @@ This section includes examples of manipulating meshes. | -------------- | ------------- | ------- | [DelaunayMesh](/PythonicAPI/Modelling/DelaunayMesh) | Two-dimensional Delaunay triangulation of a random set of points. Points and edges are shown highlighted with sphere glyphs and tubes. - #### Clipping | Example Name | Description | Image | @@ -337,10 +348,15 @@ See [this tutorial](http://www.vtk.org/Wiki/VTK/Tutorials/3DDataTypes) for a bri [Attenuation](/PythonicAPI/ImageProcessing/Attenuation) | This MRI image illustrates attenuation that can occur due to sensor position. The artifact is removed by dividing by the attenuation profile determined manually. [EnhanceEdges](/PythonicAPI/ImageProcessing/EnhanceEdges) | High-pass filters can extract and enhance edges in an image. Subtraction of the Laplacian (middle) from the original image (left) results in edge enhancement or a sharpening operation (right). [GaussianSmooth](/PythonicAPI/ImageProcessing/GaussianSmooth) | Low-pass filters can be implemented as convolution with a Gaussian kernel. +[ImageWarp](/PythonicAPI/Images/ImageWarp) | Combine the imaging and visualization pipelines to deform an image in the z-direction. The vtkMergeFilter is used to combine the warped surface with the original color data. [VTKSpectrum](/PythonicAPI/ImageProcessing/VTKSpectrum) | The discrete Fourier transform changes an image from the spatial domain into the frequency domain, where each pixel represents a sinusoidal function. This figure shows an image and its power spectrum displayed using a logarithmic transfer function. ## Widgets +| Example Name | Description | Image | +| -------------- | ------------- | ------- | +[BalloonWidget](/PythonicAPI/Widgets/BalloonWidget) | Uses a vtkBalloonWidget to draw labels when the mouse stays above an actor. + ## Plotting | Example Name | Description | Image | diff --git a/src/PythonicAPI/GeometricObjects/IsoparametricCellsDemo.md b/src/PythonicAPI/GeometricObjects/IsoparametricCellsDemo.md new file mode 100644 index 0000000000000000000000000000000000000000..2ad20d3636821ff6da1cc815065145181ee311a9 --- /dev/null +++ b/src/PythonicAPI/GeometricObjects/IsoparametricCellsDemo.md @@ -0,0 +1,12 @@ +### Description + +This example shows the isoparametric cells supported by the VTK. These cells are nonlinear and contain one or more +mid-side vertices. Isoparametric elements are typically used +in [finite element analysis](https://en.wikipedia.org/wiki/Finite_element_method). The term isoparametric is derived +from the use of the same shape functions (or interpolation functions) to define the element's geometric shape as are +used to define the displacements within the element. + +This example illustrates each cell's representation using its parametric coordinates (pcoords) as the vertices of the +cell. In practice, the vertices will correspond to physical points in a finite element model. Use vtkTessellatorFilter +to better see the shape of the cell. See for example, [QuadraticHexahedronDemo](../QuadraticHexahedronDemo) +and [QuadraticTetraDemo](../QuadraticTetraDemo). diff --git a/src/PythonicAPI/GeometricObjects/IsoparametricCellsDemo.py b/src/PythonicAPI/GeometricObjects/IsoparametricCellsDemo.py new file mode 100755 index 0000000000000000000000000000000000000000..662bff7764a65f8ac067d9027a8ac7ac7f244d46 --- /dev/null +++ b/src/PythonicAPI/GeometricObjects/IsoparametricCellsDemo.py @@ -0,0 +1,361 @@ +#!/usr/bin/env python3 + +from dataclasses import dataclass + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkCommonDataModel import ( + vtkBiQuadraticQuad, + vtkBiQuadraticQuadraticHexahedron, + vtkBiQuadraticQuadraticWedge, + vtkBiQuadraticTriangle, + vtkCubicLine, + vtkQuadraticEdge, + vtkQuadraticHexahedron, + vtkQuadraticLinearQuad, + vtkQuadraticLinearWedge, + vtkQuadraticPolygon, + vtkQuadraticPyramid, + vtkQuadraticQuad, + vtkQuadraticTetra, + vtkQuadraticTriangle, + vtkQuadraticWedge, + vtkTriQuadraticHexahedron, + vtkUnstructuredGrid +) +from vtkmodules.vtkFiltersSources import vtkSphereSource +from vtkmodules.vtkInteractionWidgets import ( + vtkTextRepresentation, + vtkTextWidget +) +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkActor2D, + vtkDataSetMapper, + vtkGlyph3DMapper, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer, + vtkTextActor, + vtkTextProperty +) +from vtkmodules.vtkRenderingLabel import vtkLabeledDataMapper + + +def main(): + colors = vtkNamedColors() + + # Set up the viewports. + x_grid_dimensions = 4 + y_grid_dimensions = 4 + renderer_size = 240 + size = (renderer_size * x_grid_dimensions, renderer_size * y_grid_dimensions) + viewports = list() + for row in range(0, y_grid_dimensions): + for col in range(0, x_grid_dimensions): + # (xmin, ymin, xmax, ymax) + viewports.append([float(col) / x_grid_dimensions, + float(y_grid_dimensions - (row + 1)) / y_grid_dimensions, + float(col + 1) / x_grid_dimensions, + float(y_grid_dimensions - row) / y_grid_dimensions]) + + ren_win = vtkRenderWindow(size=size, window_name='IsoparametricCellsDemo') + + iren = vtkRenderWindowInteractor() + iren.render_window = ren_win + + u_grids, titles = get_unstructured_grids() + + # Create one sphere for all. + sphere = vtkSphereSource(phi_resolution=21, theta_resolution=21, radius=0.08) + + # Create one text property for all. + text_property = vtkTextProperty(color=colors.GetColor3d('LightGoldenrodYellow'), bold=True, italic=True, + shadow=True, font_family_as_string='Courier', + font_size=16, justification=TextProperty.Justification.VTK_TEXT_CENTERED) + + # Position text according to its length and centered in the viewport. + text_positions = get_text_positions(titles, justification=TextProperty.Justification.VTK_TEXT_CENTERED) + + text_representations = list() + text_actors = list() + text_widgets = list() + renderers = list() + + # Create and link the mappers actors and renderers together. + for i in range(0, len(u_grids)): + name = titles[i] + print('Creating:', titles[i]) + + renderer = vtkRenderer(background=colors.GetColor3d('SlateGray'), viewport=viewports[i]) + + # Create the text actor and representation. + text_actors.append( + vtkTextActor(input=name, + text_scale_mode=vtkTextActor.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[i].GetPositionCoordinate().value = text_positions[name]['p'] + text_representations[i].GetPosition2Coordinate().value = text_positions[name]['p2'] + + # Create the text widget, setting the default renderer and interactor. + text_widgets.append( + vtkTextWidget(representation=text_representations[i], text_actor=text_actors[i], + default_renderer=renderer, interactor=iren, selectable=False)) + + mapper = vtkDataSetMapper() + u_grids[i] >> mapper + + actor = vtkActor(mapper=mapper) + actor.property.color = colors.GetColor3d('Tomato') + actor.property.edge_visibility = True + actor.property.line_width = 3 + actor.property.opacity = 0.5 + + # Label the points. + label_mapper = vtkLabeledDataMapper() + label_mapper.SetInputData(u_grids[i]) + label_actor = vtkActor2D() + label_actor.SetMapper(label_mapper) + + # Glyph the points + point_mapper = vtkGlyph3DMapper(input_data=u_grids[i], source_data=sphere.update().output, scaling=False, + scalar_visibility=False) + + point_actor = vtkActor(mapper=point_mapper) + point_actor.property.diffuse_color = colors.GetColor3d('Banana') + point_actor.property.specular = 0.6 + point_actor.property.specular_color = (1.0, 1.0, 1.0) + point_actor.property.specular_power = 100 + + renderer.AddViewProp(actor) + renderer.AddViewProp(label_actor) + renderer.AddViewProp(point_actor) + + renderers.append(renderer) + + ren_win.AddRenderer(renderers[i]) + + for row in range(0, y_grid_dimensions): + for col in range(0, x_grid_dimensions): + index = row * x_grid_dimensions + col + + if index > (len(renderers) - 1): + # Add a renderer even if there is no actor. + # This makes the render window background all the same color. + ren = vtkRenderer(background=colors.GetColor3d('SlateGray'), viewport=viewports[index]) + ren_win.AddRenderer(ren) + + continue + + renderers[index].ResetCamera() + renderers[index].GetActiveCamera().Azimuth(30) + renderers[index].GetActiveCamera().Elevation(-30) + renderers[index].ResetCameraClippingRange() + + for i in range(0, len(titles)): + text_widgets[i].On() + + iren.Initialize() + ren_win.Render() + iren.Start() + + +# These functions return a vtkUnstructured grid corresponding to the object. + +def make_unstructured_grid(a_cell): + pcoords = a_cell.GetParametricCoords() + for i in range(0, a_cell.number_of_points): + a_cell.point_ids.SetId(i, i) + a_cell.points.SetPoint(i, (pcoords[3 * i]), (pcoords[3 * i + 1]), (pcoords[3 * i + 2])) + + ug = vtkUnstructuredGrid(points=a_cell.points) + ug.InsertNextCell(a_cell.cell_type, a_cell.point_ids) + return ug + + +def make_quadratic_polygon(): + quadratic_polygon = vtkQuadraticPolygon() + + quadratic_polygon.point_ids.SetNumberOfIds(8) + quadratic_polygon.point_ids.SetId(0, 0) + quadratic_polygon.point_ids.SetId(1, 1) + quadratic_polygon.point_ids.SetId(2, 2) + quadratic_polygon.point_ids.SetId(3, 3) + quadratic_polygon.point_ids.SetId(4, 4) + quadratic_polygon.point_ids.SetId(5, 5) + quadratic_polygon.point_ids.SetId(6, 6) + quadratic_polygon.point_ids.SetId(7, 7) + + quadratic_polygon.points.SetNumberOfPoints(8) + quadratic_polygon.points.SetPoint(0, 0.0, 0.0, 0.0) + quadratic_polygon.points.SetPoint(1, 2.0, 0.0, 0.0) + quadratic_polygon.points.SetPoint(2, 2.0, 2.0, 0.0) + quadratic_polygon.points.SetPoint(3, 0.0, 2.0, 0.0) + quadratic_polygon.points.SetPoint(4, 1.0, 0.0, 0.0) + quadratic_polygon.points.SetPoint(5, 2.0, 1.0, 0.0) + quadratic_polygon.points.SetPoint(6, 1.0, 2.0, 0.0) + quadratic_polygon.points.SetPoint(7, 0.0, 1.0, 0.0) + quadratic_polygon.points.SetPoint(5, 3.0, 1.0, 0.0) + + ug = vtkUnstructuredGrid(points=quadratic_polygon.points) + ug.InsertNextCell(quadratic_polygon.cell_type, quadratic_polygon.point_ids) + return ug + + +def get_unstructured_grids(): + u_grids = list() + titles = list() + + u_grids.append(make_unstructured_grid( + vtkQuadraticEdge())) + titles.append('VTK_QUADRATIC_EDGE (= 21)') + + u_grids.append(make_unstructured_grid( + vtkQuadraticTriangle())) + titles.append('VTK_QUADRATIC_TRIANGLE (= 22)') + + u_grids.append(make_unstructured_grid( + vtkQuadraticQuad())) + titles.append('VTK_QUADRATIC_QUAD (= 23)') + + u_grids.append(make_quadratic_polygon()) + titles.append('VTK_QUADRATIC_POLYGON (= 36)') + + u_grids.append(make_unstructured_grid( + vtkQuadraticTetra())) + titles.append('VTK_QUADRATIC_TETRA (= 24)') + + u_grids.append(make_unstructured_grid( + vtkQuadraticHexahedron())) + titles.append('VTK_QUADRATIC_HEXAHEDRON (= 25)') + + u_grids.append(make_unstructured_grid( + vtkQuadraticWedge())) + titles.append('VTK_QUADRATIC_WEDGE (= 26)') + + u_grids.append(make_unstructured_grid( + vtkQuadraticPyramid())) + titles.append('VTK_QUADRATIC_PYRAMID (= 27)') + + u_grids.append(make_unstructured_grid( + vtkBiQuadraticQuad())) + titles.append('VTK_BIQUADRATIC_QUAD (= 28)') + + u_grids.append(make_unstructured_grid( + vtkTriQuadraticHexahedron())) + titles.append('VTK_TRIQUADRATIC_HEXAHEDRON (= 29)') + + u_grids.append(make_unstructured_grid( + vtkQuadraticLinearQuad())) + titles.append('VTK_QUADRATIC_LINEAR_QUAD (= 30)') + + u_grids.append(make_unstructured_grid( + vtkQuadraticLinearWedge())) + titles.append('VTK_QUADRATIC_LINEAR_WEDGE (= 31)') + + u_grids.append(make_unstructured_grid( + vtkBiQuadraticQuadraticWedge())) + titles.append('VTK_BIQUADRATIC_QUADRATIC_WEDGE (= 32)') + + u_grids.append(make_unstructured_grid( + vtkBiQuadraticQuadraticHexahedron())) + titles.append('VTK_BIQUADRATIC_QUADRATIC_HEXAHEDRON (= 33)') + + u_grids.append(make_unstructured_grid( + vtkBiQuadraticTriangle())) + titles.append('VTK_BIQUADRATIC_TRIANGLE (= 34)') + + u_grids.append(make_unstructured_grid( + vtkCubicLine())) + titles.append('VTK_CUBIC_LINE (= 35)') + + return u_grids, titles + + +def get_text_positions(names, justification=0, vertical_justification=0, width=0.96, height=0.1): + """ + Get viewport positioning information for a list of names. + + :param names: The list of names. + :param justification: Horizontal justification of the text, default is left. + :param vertical_justification: Vertical justification of the text, default is bottom. + :param width: Width of the bounding_box of the text in screen coordinates. + :param height: Height of the bounding_box of the text in screen coordinates. + :return: A list of positioning information. + """ + # The gap between the left or right edge of the screen and the text. + dx = 0.02 + width = abs(width) + if width > 0.96: + width = 0.96 + + y0 = 0.01 + height = abs(height) + if height > 0.9: + height = 0.9 + dy = height + if vertical_justification == TextProperty.VerticalJustification.VTK_TEXT_TOP: + y0 = 1.0 - (dy + y0) + dy = height + if vertical_justification == TextProperty.VerticalJustification.VTK_TEXT_CENTERED: + y0 = 0.5 - (dy / 2.0 + y0) + dy = height + + name_len_min = 0 + name_len_max = 0 + first = True + for k in names: + sz = len(k) + if first: + name_len_min = name_len_max = sz + first = False + else: + name_len_min = min(name_len_min, sz) + name_len_max = max(name_len_max, sz) + text_positions = dict() + for k in names: + sz = len(k) + delta_sz = width * sz / name_len_max + if delta_sz > width: + delta_sz = width + + if justification == TextProperty.Justification.VTK_TEXT_CENTERED: + x0 = 0.5 - delta_sz / 2.0 + elif justification == TextProperty.Justification.VTK_TEXT_RIGHT: + x0 = 1.0 - dx - delta_sz + else: + # Default is left justification. + x0 = dx + + # For debugging! + # print( + # f'{k:16s}: (x0, y0) = ({x0:3.2f}, {y0:3.2f}), (x1, y1) = ({x0 + delta_sz:3.2f}, {y0 + dy:3.2f})' + # f', width={delta_sz:3.2f}, height={dy:3.2f}') + text_positions[k] = {'p': [x0, y0, 0], 'p2': [delta_sz, dy, 0]} + + return text_positions + + +@dataclass(frozen=True) +class TextProperty: + @dataclass(frozen=True) + class Justification: + VTK_TEXT_LEFT: int = 0 + VTK_TEXT_CENTERED: int = 1 + VTK_TEXT_RIGHT: int = 2 + + @dataclass(frozen=True) + class VerticalJustification: + VTK_TEXT_BOTTOM: int = 0 + VTK_TEXT_CENTERED: int = 1 + VTK_TEXT_TOP: int = 2 + + +if __name__ == '__main__': + main() diff --git a/src/PythonicAPI/GeometricObjects/SourceObjectsDemo.py b/src/PythonicAPI/GeometricObjects/SourceObjectsDemo.py index 86849d1277fc2604d77289623e5f8dcd7f5616cf..c31d2652128729902883260451cde521491272e2 100755 --- a/src/PythonicAPI/GeometricObjects/SourceObjectsDemo.py +++ b/src/PythonicAPI/GeometricObjects/SourceObjectsDemo.py @@ -133,7 +133,7 @@ def main(): render_window.Render() - for i in range(0, len(source_objects)): + for i in range(0, len(text_widgets)): text_widgets[i].On() interactor.Start() diff --git a/src/PythonicAPI/GeometricObjects/TessellatedBoxSource.md b/src/PythonicAPI/GeometricObjects/TessellatedBoxSource.md new file mode 100644 index 0000000000000000000000000000000000000000..59b7b0b92ca3b4e89735ebd3a1ea3012531a06b6 --- /dev/null +++ b/src/PythonicAPI/GeometricObjects/TessellatedBoxSource.md @@ -0,0 +1,7 @@ +### Description + +Generates a box(cube) using vtkTessellatedBoxSource with 6 sides. The faces of the box can be subdivided into multiple +triangles or quads. + +!!! seealso + [Cube](../Cube) generates multiple quads or triangles per side. diff --git a/src/PythonicAPI/GeometricObjects/TessellatedBoxSource.py b/src/PythonicAPI/GeometricObjects/TessellatedBoxSource.py new file mode 100755 index 0000000000000000000000000000000000000000..976ec90a4dbffbf8e1588e433af963c9332d906f --- /dev/null +++ b/src/PythonicAPI/GeometricObjects/TessellatedBoxSource.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkCommonExecutionModel import vtkAlgorithm +from vtkmodules.vtkFiltersGeneral import vtkShrinkFilter +from vtkmodules.vtkFiltersSources import vtkTessellatedBoxSource +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkDataSetMapper, + vtkProperty, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer +) + + +def main(): + colors = vtkNamedColors() + + bounds = [-10.0, 10.0, 10.0, 20.0, -5.0, 5.0] + + box_source = vtkTessellatedBoxSource(level=3, quads=True, bounds=bounds, + output_points_precision=vtkAlgorithm.SINGLE_PRECISION) + + shrink = vtkShrinkFilter(shrink_factor=0.8) + + # Create a mapper and actor. + mapper = vtkDataSetMapper() + box_source >> shrink >> mapper + + back = vtkProperty() + back.color = colors.GetColor3d('Tomato') + + actor = vtkActor(mapper=mapper) + actor.property.edge_visibility = True + actor.property.color = colors.GetColor3d('Banana') + actor.backface_property = back + + # Create a renderer, render window, and interactor. + renderer = vtkRenderer(background=colors.GetColor3d('Silver')) + render_window = vtkRenderWindow(size=(640, 480), window_name='TessellatedBoxSource') + render_window.AddRenderer(renderer) + render_window_interactor = vtkRenderWindowInteractor() + render_window_interactor.render_window = render_window + + # Add the actors to the scene. + renderer.AddActor(actor) + + renderer.ResetCamera() + renderer.GetActiveCamera().Azimuth(30) + renderer.GetActiveCamera().Elevation(30) + renderer.ResetCameraClippingRange() + + # Render and interact. + render_window.Render() + render_window_interactor.Start() + + +if __name__ == '__main__': + main() diff --git a/src/PythonicAPI/IO/3DSImporter.md b/src/PythonicAPI/IO/3DSImporter.md new file mode 100644 index 0000000000000000000000000000000000000000..3f564706aef6a38cf198fd87fa6aa6dfd40d663c --- /dev/null +++ b/src/PythonicAPI/IO/3DSImporter.md @@ -0,0 +1,6 @@ +### Description + +This example illustrates Importing files in VTK. An importer creates a vtkRenderWindow that describes the scene. + +!!! info + See [Figure 4-13](../../../VTKBook/04Chapter4/#Figure%204-13) in [Chapter 4](../../../VTKBook/04Chapter4) the [VTK Textbook](../../../VTKBook/01Chapter1). diff --git a/src/PythonicAPI/IO/3DSImporter.py b/src/PythonicAPI/IO/3DSImporter.py new file mode 100755 index 0000000000000000000000000000000000000000..7975009c31f078ef03d52a2b5167d6a699ca17e4 --- /dev/null +++ b/src/PythonicAPI/IO/3DSImporter.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkIOImport import vtk3DSImporter +from vtkmodules.vtkRenderingCore import ( + vtkCamera, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer +) + + +def main(): + file_name = get_program_parameters() + + importer = vtk3DSImporter(file_name=file_name, compute_normals=True) + + colors = vtkNamedColors() + + renderer = vtkRenderer(gradient_background=True, + background=colors.GetColor3d('Wheat'), + background2=colors.GetColor3d('Gold')) + ren_win = vtkRenderWindow(window_name='3DSImporter') + iren = vtkRenderWindowInteractor() + + ren_win.AddRenderer(renderer) + + iren.render_window = ren_win + importer.render_window = ren_win + # importer.Read() + importer.Update() + + actors = renderer.GetActors() # This is a vtkActorCollection + print('There are', actors.GetNumberOfItems(), 'actors.') + + ren_win.Render() + camera = vtkCamera() + camera.position = (0, -1, 0) + camera.focal_point = (0, 0, 0) + camera.view_up = (0, 0, 1) + camera.Azimuth(150) + camera.Elevation(30) + + renderer.SetActiveCamera(camera) + renderer.ResetCamera() + renderer.ResetCameraClippingRange() + + ren_win.Render() + iren.Start() + + +def get_program_parameters(): + import argparse + description = 'Importing a 3ds file.' + epilogue = ''' + ''' + parser = argparse.ArgumentParser(description=description, epilog=epilogue, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('filename', help='iflamingo.3ds.') + args = parser.parse_args() + return args.filename + + +if __name__ == '__main__': + main() diff --git a/src/PythonicAPI/IO/TransientHDFReader.md b/src/PythonicAPI/IO/TransientHDFReader.md new file mode 100644 index 0000000000000000000000000000000000000000..e2eb9305da68f9b19e883fb0467a2d09b2fb59b0 --- /dev/null +++ b/src/PythonicAPI/IO/TransientHDFReader.md @@ -0,0 +1,3 @@ +### Description + +That example uses a feature of vtk_hdf5 that is only available in [vtk/master](https://gitlab.kitware.com/vtk/vtk) and will be released with VTK 9.3. See [this blog post](https://www.kitware.com/how-to-write-time-dependent-data-in-vtkhdf-files/) for more information. diff --git a/src/PythonicAPI/IO/TransientHDFReader.py b/src/PythonicAPI/IO/TransientHDFReader.py new file mode 100755 index 0000000000000000000000000000000000000000..f83996d1ea211bc1bf97d6681762013427228c0e --- /dev/null +++ b/src/PythonicAPI/IO/TransientHDFReader.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 + +from dataclasses import dataclass + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingContextOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkIOHDF import vtkHDFReader +from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkDiscretizableColorTransferFunction, + vtkPolyDataMapper, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer +) + + +def get_program_parameters(): + import argparse + description = 'Read transient data writen inside a vtkhdf file.' + epilogue = '''''' + parser = argparse.ArgumentParser(description=description, epilog=epilogue, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('file_name', help='warping_spheres.vtkhdf') + args = parser.parse_args() + return args.file_name + + +def main(): + fn = get_program_parameters() + + colors = vtkNamedColors() + + # Read the dataset. + reader = vtkHDFReader(file_name=fn) + reader.update() + print('Number of steps: ', reader.GetNumberOfSteps()) + + # Render the dataset. + mapper = vtkPolyDataMapper(lookup_table=get_ctf(), + scalar_mode=Mapper.ScalarMode.VTK_SCALAR_MODE_USE_POINT_FIELD_DATA) + mapper.SelectColorArray('SpatioTemporalHarmonics') + reader >> mapper + + actor = vtkActor(mapper=mapper) + # actor.SetMapper(mapper) + + renderer = vtkRenderer(background=colors.GetColor3d('Wheat')) + # renderer.SetBackground(colors.GetColor3d('Wheat')) + renderer.UseHiddenLineRemovalOn() + renderer.AddActor(actor) + + ren_win = vtkRenderWindow(size=(1024, 512), window_name='TransientHDFReader') + ren_win.AddRenderer(renderer) + ren_win.Render() + + # Add the interactor. + iren = vtkRenderWindowInteractor() + iren.render_window = ren_win + + # Add the animation callback. + observer = AnimationObserver(iren, reader) + + # You must initialize the vtkRenderWindowInteractor + # before adding the observer and setting the repeating timer. + iren.Initialize() + iren.AddObserver('TimerEvent', observer) + iren.CreateRepeatingTimer(50) + + i_style = vtkInteractorStyleTrackballCamera() + iren.SetInteractorStyle(i_style) + + iren.Start() + + +def get_ctf(): + ctf = vtkDiscretizableColorTransferFunction(color_space=ColorTransferFunction.ColorSpace.VTK_CTF_LAB, + scale=ColorTransferFunction.Scale.VTK_CTF_LINEAR, + number_of_values=46, discretize=False, + ) + + ctf.AddRGBPoint(-30.3399130649763, 0.0862745098039216, 0.00392156862745098, 0.298039215686275) + ctf.AddRGBPoint(-29.3502559661865, 0.113725, 0.0235294, 0.45098) + ctf.AddRGBPoint(-28.5283393859863, 0.105882, 0.0509804, 0.509804) + ctf.AddRGBPoint(-27.958028793335, 0.0392157, 0.0392157, 0.560784) + ctf.AddRGBPoint(-27.4044914245605, 0.0313725, 0.0980392, 0.6) + ctf.AddRGBPoint(-26.8677291870117, 0.0431373, 0.164706, 0.639216) + ctf.AddRGBPoint(-26.096134185791, 0.054902, 0.243137, 0.678431) + ctf.AddRGBPoint(-25.0729293823242, 0.054902, 0.317647, 0.709804) + ctf.AddRGBPoint(-23.8148933330084, 0.0509804, 0.396078, 0.741176) + ctf.AddRGBPoint(-22.9992658665124, 0.0392157, 0.466667, 0.768627) + ctf.AddRGBPoint(-22.1836384000164, 0.0313725, 0.537255, 0.788235) + ctf.AddRGBPoint(-21.3323650360107, 0.0313725, 0.615686, 0.811765) + ctf.AddRGBPoint(-20.4601268768311, 0.0235294, 0.709804, 0.831373) + ctf.AddRGBPoint(-19.5878868103027, 0.0509804, 0.8, 0.85098) + ctf.AddRGBPoint(-18.8666133880615, 0.0705882, 0.854902, 0.870588) + ctf.AddRGBPoint(-18.1956596374512, 0.262745, 0.901961, 0.862745) + ctf.AddRGBPoint(-17.6085758209229, 0.423529, 0.941176, 0.87451) + ctf.AddRGBPoint(-16.7027893066406, 0.572549, 0.964706, 0.835294) + ctf.AddRGBPoint(-16.0989303588867, 0.658824, 0.980392, 0.843137) + ctf.AddRGBPoint(-15.6628112792969, 0.764706, 0.980392, 0.866667) + ctf.AddRGBPoint(-15.1931447982788, 0.827451, 0.980392, 0.886275) + ctf.AddRGBPoint(-14.2705841064453, 0.913725, 0.988235, 0.937255) + ctf.AddRGBPoint(-13.9854288101196, 1, 1, 0.972549019607843) + ctf.AddRGBPoint(-13.7002735137939, 0.988235, 0.980392, 0.870588) + ctf.AddRGBPoint(-13.2809276580811, 0.992156862745098, 0.972549019607843, 0.803921568627451) + ctf.AddRGBPoint(-12.9622249603271, 0.992157, 0.964706, 0.713725) + ctf.AddRGBPoint(-12.4254627227783, 0.988235, 0.956863, 0.643137) + ctf.AddRGBPoint(-11.5699977874756, 0.980392, 0.917647, 0.509804) + ctf.AddRGBPoint(-10.8487224578857, 0.968627, 0.87451, 0.407843) + ctf.AddRGBPoint(-10.1106739044189, 0.94902, 0.823529, 0.321569) + ctf.AddRGBPoint(-9.57391166687012, 0.929412, 0.776471, 0.278431) + ctf.AddRGBPoint(-8.78554153442383, 0.909804, 0.717647, 0.235294) + ctf.AddRGBPoint(-8.08104133605957, 0.890196, 0.658824, 0.196078) + ctf.AddRGBPoint(-7.50234400308847, 0.878431, 0.619608, 0.168627) + ctf.AddRGBPoint(-6.68671653659248, 0.870588, 0.54902, 0.156863) + ctf.AddRGBPoint(-5.87108907009648, 0.85098, 0.47451, 0.145098) + ctf.AddRGBPoint(-5.05546160360049, 0.831373, 0.411765, 0.133333) + ctf.AddRGBPoint(-4.23983413710449, 0.811765, 0.345098, 0.113725) + ctf.AddRGBPoint(-3.4242066706085, 0.788235, 0.266667, 0.0941176) + ctf.AddRGBPoint(-2.6085792041125, 0.741176, 0.184314, 0.0745098) + ctf.AddRGBPoint(-1.79295173761651, 0.690196, 0.12549, 0.0627451) + ctf.AddRGBPoint(-0.977324271120517, 0.619608, 0.0627451, 0.0431373) + ctf.AddRGBPoint(-0.214114964008331, 0.54902, 0.027451, 0.0705882) + ctf.AddRGBPoint(0.456838220357895, 0.470588, 0.0156863, 0.0901961) + ctf.AddRGBPoint(1.21166050434113, 0.4, 0.00392157, 0.101961) + ctf.AddRGBPoint(2.28518559486346, 0.188235294117647, 0, 0.0705882352941176) + + return ctf + + +class AnimationObserver(object): + def __init__(self, interactor, reader): + self.interactor = interactor + self.reader = reader + + def __call__(self, caller, ev): + step = 0 if (self.reader.step == self.reader.GetNumberOfSteps() - 1) else self.reader.step + 1 + self.reader.SetStep(step) + print(f'Current step: {self.reader.step:3d}') + self.reader.update() + self.interactor.Render() + + +@dataclass(frozen=True) +class ColorTransferFunction: + @dataclass(frozen=True) + class ColorSpace: + VTK_CTF_RGB: int = 0 + VTK_CTF_HSV: int = 1 + VTK_CTF_LAB: int = 2 + VTK_CTF_DIVERGING: int = 3 + VTK_CTF_LAB_CIEDE2000: int = 4 + VTK_CTF_STEP: int = 5 + + @dataclass(frozen=True) + class Scale: + VTK_CTF_LINEAR: int = 0 + VTK_CTF_LOG10: int = 1 + + +@dataclass(frozen=True) +class Mapper: + @dataclass(frozen=True) + class ColorMode: + VTK_COLOR_MODE_DEFAULT: int = 0 + VTK_COLOR_MODE_MAP_SCALARS: int = 1 + VTK_COLOR_MODE_DIRECT_SCALARS: int = 2 + + @dataclass(frozen=True) + class ResolveCoincidentTopology: + VTK_RESOLVE_OFF: int = 0 + VTK_RESOLVE_POLYGON_OFFSET: int = 1 + VTK_RESOLVE_SHIFT_ZBUFFER: int = 2 + + @dataclass(frozen=True) + class ScalarMode: + VTK_SCALAR_MODE_DEFAULT: int = 0 + VTK_SCALAR_MODE_USE_POINT_DATA: int = 1 + VTK_SCALAR_MODE_USE_CELL_DATA: int = 2 + VTK_SCALAR_MODE_USE_POINT_FIELD_DATA: int = 3 + VTK_SCALAR_MODE_USE_CELL_FIELD_DATA: int = 4 + VTK_SCALAR_MODE_USE_FIELD_DATA: int = 5 + + +if __name__ == '__main__': + main() diff --git a/src/PythonicAPI/Images/ImageWarp.py b/src/PythonicAPI/Images/ImageWarp.py new file mode 100755 index 0000000000000000000000000000000000000000..02834ce99dd1685d762f350b63f9154c61240f5d --- /dev/null +++ b/src/PythonicAPI/Images/ImageWarp.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkCommonCore import vtkLogger +from vtkmodules.vtkFiltersCore import vtkMergeFilter +from vtkmodules.vtkFiltersGeneral import vtkWarpScalar +from vtkmodules.vtkFiltersGeometry import vtkImageDataGeometryFilter +from vtkmodules.vtkIOImage import vtkBMPReader +from vtkmodules.vtkImagingColor import vtkImageLuminance +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkDataSetMapper, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer +) + + +def main(): + # This turns off the merge filter warnings. + vtkLogger.SetStderrVerbosity(vtkLogger.VERBOSITY_OFF) + + file_name = get_program_parameters() + + colors = vtkNamedColors() + + # Set the background color. + colors.SetColor('BkgColor', 60, 93, 144, 255) + + # Read in an image and compute a luminance value. The image is extracted + # as a set of polygons (vtkImageDataGeometryFilter). We then will + # warp the plane using the scalar (luminance) values. + reader = vtkBMPReader(file_name=file_name) + # Convert the image to a grey scale. + luminance = vtkImageLuminance() + # Pass the data to the pipeline as polygons. + geometry = vtkImageDataGeometryFilter() + # Warp the data in a direction perpendicular to the image plane. + warp = vtkWarpScalar(scale_factor=-0.1) + reader >> luminance >> geometry >> warp + + # Use vtkMergeFilter to combine the original image with the warped geometry. + merge = vtkMergeFilter(geometry_connection=warp.GetOutputPort(), scalars_connection=reader.GetOutputPort()) + mapper = vtkDataSetMapper(scalar_range=(0, 255)) + merge >> mapper + actor = vtkActor(mapper=mapper) + + # Create the rendering window, renderer, and interactive renderer. + ren = vtkRenderer(background=colors.GetColor3d('BkgColor')) + ren_win = vtkRenderWindow(size=(512, 512), window_name='ImageWarp') + ren_win.AddRenderer(ren) + iren = vtkRenderWindowInteractor() + iren.render_window = ren_win + + # Add the actors to the renderer, set the background and size. + ren.AddActor(actor) + ren.ResetCamera() + # ren.active_camera.Azimuth(20) + # ren.active_camera.Elevation(30) + # ren.ResetCameraClippingRange() + # ren.active_camera.Zoom(1.3) + ren.active_camera.position = (-100, -130, 325) + ren.active_camera.focal_point = (105, 114, -29) + ren.active_camera.view_up = (0.51, 0.54, 0.67) + ren.ResetCameraClippingRange() + + # Render the image. + iren.Initialize() + iren.Start() + + +def get_program_parameters(): + import argparse + description = 'ImageWarp.' + epilogue = ''' +This example shows how to combine data from both the imaging + and graphics pipelines. The vtkMergeData filter is used to + merge the data from each together. + ''' + parser = argparse.ArgumentParser(description=description, epilog=epilogue, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument('fileName', help='Path to the masonry.bmp file.') + args = parser.parse_args() + return args.fileName + + +if __name__ == '__main__': + main() diff --git a/src/PythonicAPI/Widgets/BalloonWidget.py b/src/PythonicAPI/Widgets/BalloonWidget.py new file mode 100755 index 0000000000000000000000000000000000000000..92c49f382377e2c783194e2f8c532845129e3dba --- /dev/null +++ b/src/PythonicAPI/Widgets/BalloonWidget.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +from dataclasses import dataclass + +# noinspection PyUnresolvedReferences +import vtkmodules.vtkInteractionStyle +# noinspection PyUnresolvedReferences +import vtkmodules.vtkRenderingOpenGL2 +from vtkmodules.vtkCommonColor import vtkNamedColors +from vtkmodules.vtkFiltersSources import ( + vtkRegularPolygonSource, + vtkSphereSource +) +from vtkmodules.vtkInteractionWidgets import ( + vtkBalloonRepresentation, + vtkBalloonWidget +) +from vtkmodules.vtkRenderingCore import ( + vtkActor, + vtkPolyDataMapper, + vtkRenderWindow, + vtkRenderWindowInteractor, + vtkRenderer, + vtkTextProperty +) + + +def main(): + colors = vtkNamedColors() + + # Sphere. + sphere_source = vtkSphereSource(center=(-4.0, 0.0, 0.0), radius=4.0) + sphere_mapper = vtkPolyDataMapper() + sphere_source >> sphere_mapper + + sphere_actor = vtkActor(mapper=sphere_mapper) + sphere_actor.property.color = colors.GetColor3d('MistyRose') + + # Regular Polygon. + regular_polygon_source = vtkRegularPolygonSource(center=(4.0, 0.0, 0.0), radius=4.0) + regular_polygon_mapper = vtkPolyDataMapper() + + regular_polygon_source >> regular_polygon_mapper + regular_polygon_actor = vtkActor(mapper=regular_polygon_mapper) + regular_polygon_actor.property.color = colors.GetColor3d('Cornsilk') + + # A renderer and render window. + ren = vtkRenderer(background=colors.GetColor3d('SlateGray')) + ren_win = vtkRenderWindow(window_name='BalloonWidget') + ren_win.AddRenderer(ren) + + # An interactor. + iren = vtkRenderWindowInteractor() + iren.SetRenderWindow(ren_win) + + # Create the widget. + # Do not set the justification. + text_property = vtkTextProperty(color=colors.GetColor3d('Black'), + bold=False, italic=False, shadow=False, + font_size=16, + ) + + balloon_rep = vtkBalloonRepresentation(balloon_layout=vtkBalloonRepresentation.ImageRight, + text_property=text_property) + + balloon_widget = vtkBalloonWidget(interactor=iren, representation=balloon_rep) + balloon_widget.AddBalloon(sphere_actor, 'This is a sphere') + balloon_widget.AddBalloon(regular_polygon_actor, 'This is a regular polygon') + + # Add the actors to the scene. + ren.AddActor(sphere_actor) + ren.AddActor(regular_polygon_actor) + + # Render an image (lights and cameras are created automatically). + ren_win.Render() + balloon_widget.enabled = True + + # Begin mouse interaction. + iren.Start() + iren.Initialize() + + +@dataclass(frozen=True) +class TextProperty: + @dataclass(frozen=True) + class Justification: + VTK_TEXT_LEFT: int = 0 + VTK_TEXT_CENTERED: int = 1 + VTK_TEXT_RIGHT: int = 2 + + @dataclass(frozen=True) + class VerticalJustification: + VTK_TEXT_BOTTOM: int = 0 + VTK_TEXT_CENTERED: int = 1 + VTK_TEXT_TOP: int = 2 + + +if __name__ == '__main__': + main() diff --git a/src/Testing/Baseline/PythonicAPI/GeometricObjects/TestIsoparametricCellsDemo.png b/src/Testing/Baseline/PythonicAPI/GeometricObjects/TestIsoparametricCellsDemo.png new file mode 100644 index 0000000000000000000000000000000000000000..cf04637bc3964a0762877bd560862ff6b9833a82 --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/GeometricObjects/TestIsoparametricCellsDemo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89cfa6a6b0a11671bf1a4b3f17889a999dad74ed4d89d64c2eba638597ef904b +size 255538 diff --git a/src/Testing/Baseline/PythonicAPI/GeometricObjects/TestTessellatedBoxSource.png b/src/Testing/Baseline/PythonicAPI/GeometricObjects/TestTessellatedBoxSource.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca1cff6e551b4b708bad47bc9f216adf2cede48 --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/GeometricObjects/TestTessellatedBoxSource.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:33ce26107489c4458b151170100a6ff800c084eda29745c412542c33333908a5 +size 20056 diff --git a/src/Testing/Baseline/PythonicAPI/IO/Test3DSImporter.png b/src/Testing/Baseline/PythonicAPI/IO/Test3DSImporter.png new file mode 100644 index 0000000000000000000000000000000000000000..0efb12b8b09e75a59002baa0f4a6f6ef8f5c3faf --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/IO/Test3DSImporter.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53fe1e5cccd872ea6962d50eb30be7c2ca91d0a5d86899496346f097c9204e22 +size 17659 diff --git a/src/Testing/Baseline/PythonicAPI/IO/TestTransientHDFReader.png b/src/Testing/Baseline/PythonicAPI/IO/TestTransientHDFReader.png new file mode 100644 index 0000000000000000000000000000000000000000..6054c2757dcfe29bfe742561297b99154a381941 --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/IO/TestTransientHDFReader.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d1448e1f0a15e01d7371731bcf1b0d72716af59ac62ff4a90626c9f4892956cb +size 53670 diff --git a/src/Testing/Baseline/PythonicAPI/Images/TestImageWarp.png b/src/Testing/Baseline/PythonicAPI/Images/TestImageWarp.png new file mode 100644 index 0000000000000000000000000000000000000000..4fb73c11d8988160c1ab0944396327840f5b604b --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/Images/TestImageWarp.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:94a4539dea22726bed9e55af61d971c782af3170ea60a61e7ea090ca025244e3 +size 379142 diff --git a/src/Testing/Baseline/PythonicAPI/Widgets/TestBalloonWidget.png b/src/Testing/Baseline/PythonicAPI/Widgets/TestBalloonWidget.png new file mode 100644 index 0000000000000000000000000000000000000000..66405629f2aedef884adaa4472f33e3dea8fd3b1 --- /dev/null +++ b/src/Testing/Baseline/PythonicAPI/Widgets/TestBalloonWidget.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ad42c957a9d4dbc4350f8e30b9a997cefc45ae0c20c6b38b3d98cbcf17ddfbb +size 12016