├── .gitignore ├── LICENSE ├── README.md ├── data ├── exodus │ └── tetrahedron.exo ├── objs │ └── cube.obj ├── open_foam │ └── temp.case ├── stls │ ├── ahmed_body.stl │ ├── airfoil.stl │ ├── cube.stl │ ├── naca0012.stl │ └── naca0012_meshed.stl ├── vtks │ ├── cube_polydata.vtk │ ├── grid_of_mixed_types.vtk │ ├── grid_of_triangles.vtk │ ├── polydata_line.vtk │ └── texture_map.vtk ├── vtms │ ├── grid_of_triangles.vtm │ └── grid_of_triangles │ │ └── grid_of_triangles_0.vtu ├── vtps │ └── naca0012.vtp └── vtus │ └── grid_of_triangles.vtu ├── notes ├── 01_data_types_and_structures.md ├── 02_filters_and_algorithms.md ├── 03_input_and_output.md ├── 04_visualization_techniques.md ├── 05_interactivity.md ├── 06_animations.md ├── 07_performance_optimization_and_parallelism.md ├── 08_integration_with_other_tools.md └── 09_custom_filters_and_algorithms.md ├── requirements.txt ├── src ├── 01_basic_shapes │ ├── __init__.py │ ├── circle.py │ ├── cone.py │ ├── cube.py │ ├── cylinder.py │ ├── glyph.py │ ├── square.py │ └── triangle.py ├── 02_advanced_shapes │ ├── __init__.py │ ├── custom_filter_sphere.py │ ├── enclosing_box.py │ ├── flow_simulation_visualization.py │ ├── isosurface.py │ ├── multiple_dependent_objects.py │ ├── multiple_independent_objects.py │ ├── streamlines.py │ ├── triangulation.py │ ├── visualization_techniques_comparison.py │ └── volume_rendering.py ├── 03_structures_and_datasets │ ├── __init__.py │ ├── ahmed_body_visualization.py │ ├── cells.py │ ├── fields.py │ ├── generate_naca0012.py │ ├── image_data.py │ ├── multiblock_dataset.py │ ├── points.py │ ├── poly_data.py │ ├── rectilinear_grid.py │ ├── structured_grid.py │ ├── structured_mesh.py │ ├── unstructured_grid.py │ └── unstructured_mesh.py ├── 04_input_output │ ├── __init__.py │ ├── io_exodus_ii.py │ ├── io_obj.py │ ├── io_openfoam.py │ ├── io_stl.py │ ├── io_vtk.py │ ├── io_vtm.py │ └── io_vtu.py ├── 05_data_conversion │ ├── __init__.py │ ├── converter_interface.py │ ├── stl_obj.py │ ├── stl_vtk.py │ ├── vtk_obj.py │ ├── vtk_vtm.py │ └── vtk_vtu.py ├── 06_visualization_pipeline │ ├── __init__.py │ ├── actor_mapper_multiple_objects.py │ ├── adding_text_labels.py │ ├── camera_movement.py │ ├── filters_in_action.py │ ├── lighting_and_shadows.py │ ├── pipeline_animation.py │ └── scalar_color_mapping.py ├── 07_interactive_widgets │ ├── __init__.py │ ├── deformation_cylinder.py │ ├── interactive_flower_mesh.py │ ├── orientation_marker.py │ ├── planes_intersection.py │ ├── simple_button.py │ └── slider.py ├── 08_integration_with_ui │ ├── __init__.py │ ├── geospatial_data.py │ ├── matplotlib_sphere.py │ ├── matplotlib_surface_plot.py │ ├── qt_sphere.py │ └── spark_vtk_workflow.py ├── 09_cfd │ ├── __init__.py │ ├── convective_end_heat_transfer_1d.py │ ├── enhanced_heat_transfer_solver_1d.py │ ├── enhanced_heat_transfer_solver_2d.py │ ├── fixed_end_heat_transfer_1d.py │ ├── fluid_flow_simulator.py │ ├── heat_conduction_solver_2d.py │ ├── heat_convection_solver_1d.py │ └── obstacle_flow_simulation.py ├── __init__.py └── common │ ├── __init__.py │ ├── button.py │ └── simple_pipeline.py └── vtk_js └── basic ├── .babelrc ├── README.md ├── index.html ├── package.json ├── src └── main.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Node modules 2 | node_modules/ 3 | package-lock.json 4 | 5 | # Build output 6 | dist/ 7 | 8 | # Environment files 9 | .env 10 | 11 | # Editor directories and files 12 | .vscode/ 13 | .idea/ 14 | *.swp 15 | *.swo 16 | 17 | # System files 18 | .DS_Store 19 | Thumbs.db 20 | 21 | # Logs 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | 27 | # Byte-compiled / optimized / DLL io 28 | __pycache__/ 29 | *.py[cod] 30 | *$py.class 31 | 32 | # C extensions 33 | *.so 34 | .idea 35 | 36 | # Distribution / packaging 37 | .Python 38 | build/ 39 | develop-eggs/ 40 | dist/ 41 | downloads/ 42 | eggs/ 43 | .eggs/ 44 | lib/ 45 | lib64/ 46 | parts/ 47 | sdist/ 48 | var/ 49 | wheels/ 50 | pip-wheel-metadata/ 51 | share/python-wheels/ 52 | *.egg-info/ 53 | .installed.cfg 54 | *.egg 55 | MANIFEST 56 | 57 | # PyInstaller 58 | # Usually these io are written by a python script from a template 59 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 60 | *.manifest 61 | *.spec 62 | 63 | # Installer logs 64 | pip-log.txt 65 | pip-delete-this-directory.txt 66 | 67 | # Unit test / coverage reports 68 | htmlcov/ 69 | .tox/ 70 | .nox/ 71 | .coverage 72 | .coverage.* 73 | .cache 74 | nosetests.xml 75 | coverage.xml 76 | *.cover 77 | *.py,cover 78 | .hypothesis/ 79 | .pytest_cache/ 80 | 81 | # Translations 82 | *.mo 83 | *.pot 84 | 85 | # Django stuff: 86 | *.log 87 | local_settings.py 88 | db.sqlite3 89 | db.sqlite3-journal 90 | 91 | # Flask stuff: 92 | instance/ 93 | .webassets-cache 94 | 95 | # Scrapy stuff: 96 | .scrapy 97 | 98 | # Sphinx documentation 99 | docs/_build/ 100 | 101 | # PyBuilder 102 | target/ 103 | 104 | # Jupyter Notebook 105 | .ipynb_checkpoints 106 | 107 | # IPython 108 | profile_default/ 109 | ipython_config.py 110 | 111 | # pyenv 112 | .python-version 113 | 114 | # pipenv 115 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 116 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 117 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 118 | # install all needed dependencies. 119 | #Pipfile.lock 120 | 121 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 122 | __pypackages__/ 123 | 124 | # Celery stuff 125 | celerybeat-schedule 126 | celerybeat.pid 127 | 128 | # SageMath parsed io 129 | *.sage.py 130 | 131 | # Environments 132 | .env 133 | .venv 134 | env/ 135 | venv/ 136 | ENV/ 137 | env.bak/ 138 | venv.bak/ 139 | 140 | # Spyder project settings 141 | .spyderproject 142 | .spyproject 143 | 144 | # Rope project settings 145 | .ropeproject 146 | 147 | # mkdocs documentation 148 | /site 149 | 150 | # mypy 151 | .mypy_cache/ 152 | .dmypy.json 153 | dmypy.json 154 | 155 | # Pyre type checker 156 | .pyre/ 157 | 158 | 159 | 160 | # vtk 161 | src/**/*.vtk 162 | src/**/*.vtm 163 | src/**/*.vtu 164 | src/**/*.vtp 165 | src/**/*.stl 166 | src/**/*.obj 167 | 168 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Adam Djellouli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /data/exodus/tetrahedron.exo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/data/exodus/tetrahedron.exo -------------------------------------------------------------------------------- /data/objs/cube.obj: -------------------------------------------------------------------------------- 1 | # Generated by Visualization Toolkit 2 | v -134.3502960205078 17.677669525146484 20 3 | v -162.6345672607422 3.535533905029297 20 4 | v -106.0660171508789 3.535533905029297 20 5 | v -134.3502960205078 -10.60660171508789 20 6 | v -106.0660171508789 3.535533905029297 0 7 | v -134.3502960205078 -10.60660171508789 0 8 | v -134.3502960205078 17.677669525146484 0 9 | v -162.6345672607422 3.535533905029297 0 10 | f 1 2 3 11 | f 3 2 4 12 | f 5 6 7 13 | f 7 6 8 14 | f 4 6 3 15 | f 3 6 5 16 | f 2 8 4 17 | f 4 8 6 18 | f 1 7 2 19 | f 2 7 8 20 | f 3 5 1 21 | f 1 5 7 22 | -------------------------------------------------------------------------------- /data/open_foam/temp.case: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/data/open_foam/temp.case -------------------------------------------------------------------------------- /data/stls/airfoil.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/data/stls/airfoil.stl -------------------------------------------------------------------------------- /data/stls/cube.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/data/stls/cube.stl -------------------------------------------------------------------------------- /data/stls/naca0012.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/data/stls/naca0012.stl -------------------------------------------------------------------------------- /data/stls/naca0012_meshed.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/data/stls/naca0012_meshed.stl -------------------------------------------------------------------------------- /data/vtks/cube_polydata.vtk: -------------------------------------------------------------------------------- 1 | # vtk DataFile Version 1.0 2 | vtk output 3 | ASCII 4 | DATASET POLYDATA 5 | POINTS 64 float 6 | 3.449950 7.310000 1.000000 3.510010 5.389980 1.000000 7 | 3.449950 17.450001 1.000000 2.070010 19.580000 1.000000 8 | 0.000000 18.379999 1.000000 0.000000 17.450001 1.000000 9 | 3.719970 3.810000 1.000000 3.940000 21.000000 1.000000 10 | 4.089970 2.540010 1.000000 4.639950 1.560000 1.000000 11 | 5.389950 0.839996 1.000000 5.839970 22.840000 1.000000 12 | 6.339970 0.359985 1.000000 6.880000 23.969999 1.000000 13 | 7.539980 0.079987 1.000000 8.010010 6.470000 1.000000 14 | 8.010010 17.450001 1.000000 8.010010 19.180000 1.000000 15 | 8.010010 25.290001 1.000000 8.130000 4.810000 1.000000 16 | 8.500000 3.720000 1.000000 8.989990 0.000000 1.000000 17 | 9.159970 0.000000 1.000000 9.190000 3.109990 1.000000 18 | 10.220000 2.919980 1.000000 10.870000 3.000000 1.000000 19 | 11.490000 3.250000 1.000000 12.170000 3.729980 1.000000 20 | 13.010000 4.470000 1.000000 13.770000 3.410000 1.000000 21 | 13.010000 17.450001 1.000000 13.770000 19.180000 1.000000 22 | 3.449950 17.450001 0.000000 3.510010 5.389980 0.000000 23 | 3.449950 7.310000 0.000000 0.000000 17.450001 0.000000 24 | 0.000000 18.379999 0.000000 2.070010 19.580000 0.000000 25 | 3.719970 3.810000 0.000000 3.940000 21.000000 0.000000 26 | 4.089970 2.540010 0.000000 4.639950 1.560000 0.000000 27 | 5.389950 0.839996 0.000000 5.839970 22.840000 0.000000 28 | 6.339970 0.359985 0.000000 6.880000 23.969999 0.000000 29 | 7.539980 0.079987 0.000000 8.010010 6.470000 0.000000 30 | 8.010010 17.450001 0.000000 8.010010 19.180000 0.000000 31 | 8.010010 25.290001 0.000000 8.130000 4.810000 0.000000 32 | 8.500000 3.720000 0.000000 8.989990 0.000000 0.000000 33 | 9.159970 0.000000 0.000000 9.190000 3.109990 0.000000 34 | 10.220000 2.919980 0.000000 10.870000 3.000000 0.000000 35 | 11.490000 3.250000 0.000000 12.170000 3.729980 0.000000 36 | 13.010000 4.470000 0.000000 13.770000 3.410000 0.000000 37 | 13.010000 17.450001 0.000000 13.770000 19.180000 0.000000 38 | 39 | POLYGONS 92 400 40 | 3 0 1 2 41 | 3 3 4 5 42 | 3 2 3 5 43 | 3 1 6 2 44 | 3 7 2 6 45 | 3 3 2 7 46 | 3 6 8 7 47 | 3 9 7 8 48 | 3 10 7 9 49 | 3 11 7 10 50 | 3 12 11 10 51 | 3 13 11 12 52 | 3 14 13 12 53 | 3 15 13 14 54 | 3 16 13 15 55 | 3 17 13 16 56 | 3 18 13 17 57 | 3 19 15 14 58 | 3 20 19 14 59 | 3 21 20 14 60 | 3 22 20 21 61 | 3 23 20 22 62 | 3 24 23 22 63 | 3 25 24 22 64 | 3 26 25 22 65 | 3 27 26 22 66 | 3 28 27 22 67 | 3 29 28 22 68 | 3 16 30 17 69 | 3 31 17 30 70 | 3 32 33 34 71 | 3 35 36 37 72 | 3 35 37 32 73 | 3 32 38 33 74 | 3 38 32 39 75 | 3 39 32 37 76 | 3 39 40 38 77 | 3 40 39 41 78 | 3 41 39 42 79 | 3 42 39 43 80 | 3 42 43 44 81 | 3 44 43 45 82 | 3 44 45 46 83 | 3 46 45 47 84 | 3 47 45 48 85 | 3 48 45 49 86 | 3 49 45 50 87 | 3 46 47 51 88 | 3 46 51 52 89 | 3 46 52 53 90 | 3 53 52 54 91 | 3 54 52 55 92 | 3 54 55 56 93 | 3 54 56 57 94 | 3 54 57 58 95 | 3 54 58 59 96 | 3 54 59 60 97 | 3 54 60 61 98 | 3 49 62 48 99 | 3 62 49 63 100 | 4 63 49 17 31 101 | 4 49 50 18 17 102 | 4 50 45 13 18 103 | 4 45 43 11 13 104 | 4 43 39 7 11 105 | 4 39 37 3 7 106 | 4 37 36 4 3 107 | 4 36 35 5 4 108 | 4 35 32 2 5 109 | 4 32 34 0 2 110 | 4 34 33 1 0 111 | 4 33 38 6 1 112 | 4 38 40 8 6 113 | 4 40 41 9 8 114 | 4 41 42 10 9 115 | 4 42 44 12 10 116 | 4 44 46 14 12 117 | 4 46 53 21 14 118 | 4 53 54 22 21 119 | 4 54 61 29 22 120 | 4 61 60 28 29 121 | 4 60 59 27 28 122 | 4 59 58 26 27 123 | 4 58 57 25 26 124 | 4 57 56 24 25 125 | 4 56 55 23 24 126 | 4 55 52 20 23 127 | 4 52 51 19 20 128 | 4 51 47 15 19 129 | 4 47 48 16 15 130 | 4 48 62 30 16 131 | 4 62 63 31 30 -------------------------------------------------------------------------------- /data/vtks/grid_of_mixed_types.vtk: -------------------------------------------------------------------------------- 1 | # vtk DataFile Version 1.0 2 | Unstructured Grid Example 3 | ASCII 4 | 5 | DATASET UNSTRUCTURED_GRID 6 | POINTS 27 float 7 | 0.0 0.0 0.0 8 | 1.0 0.0 0.0 9 | 2.0 0.0 0.0 10 | 0.0 1.0 0.0 11 | 1.0 1.0 0.0 12 | 2.0 1.0 0.0 13 | 0.0 0.0 1.0 14 | 1.0 0.0 1.0 15 | 2.0 0.0 1.0 16 | 0.0 1.0 1.0 17 | 1.0 1.0 1.0 18 | 2.0 1.0 1.0 19 | 0.0 1.0 2.0 20 | 1.0 1.0 2.0 21 | 2.0 1.0 2.0 22 | 0.0 1.0 3.0 23 | 1.0 1.0 3.0 24 | 2.0 1.0 3.0 25 | 0.0 1.0 4.0 26 | 1.0 1.0 4.0 27 | 2.0 1.0 4.0 28 | 0.0 1.0 5.0 29 | 1.0 1.0 5.0 30 | 2.0 1.0 5.0 31 | 0.0 1.0 6.0 32 | 1.0 1.0 6.0 33 | 2.0 1.0 6.0 34 | 35 | CELLS 12 63 36 | 8 0 1 4 3 6 7 10 9 37 | 8 1 2 5 4 7 8 11 10 38 | 4 6 10 9 12 39 | 4 5 11 10 14 40 | 6 15 16 17 14 13 12 41 | 6 18 15 19 16 20 17 42 | 4 22 23 20 19 43 | 3 21 22 18 44 | 3 22 19 18 45 | 2 23 26 46 | 2 21 24 47 | 1 25 48 | 49 | CELL_TYPES 12 50 | 12 51 | 12 52 | 10 53 | 10 54 | 7 55 | 6 56 | 9 57 | 5 58 | 5 59 | 3 60 | 3 61 | 1 62 | 63 | 64 | POINT_DATA 27 65 | SCALARS scalars float 66 | LOOKUP_TABLE default 67 | 0.0 68 | 1.0 69 | 2.0 70 | 3.0 71 | 4.0 72 | 5.0 73 | 6.0 74 | 7.0 75 | 8.0 76 | 9.0 77 | 10.0 78 | 11.0 79 | 12.0 80 | 13.0 81 | 14.0 82 | 15.0 83 | 16.0 84 | 17.0 85 | 18.0 86 | 19.0 87 | 20.0 88 | 21.0 89 | 22.0 90 | 23.0 91 | 24.0 92 | 25.0 93 | 26.0 94 | 95 | VECTORS vectors float 96 | 1 0 0 97 | 1 1 0 98 | 0 2 0 99 | 1 0 0 100 | 1 1 0 101 | 0 2 0 102 | 1 0 0 103 | 1 1 0 104 | 0 2 0 105 | 1 0 0 106 | 1 1 0 107 | 0 2 0 108 | 0 0 1 109 | 0 0 1 110 | 0 0 1 111 | 0 0 1 112 | 0 0 1 113 | 0 0 1 114 | 0 0 1 115 | 0 0 1 116 | 0 0 1 117 | 0 0 1 118 | 0 0 1 119 | 0 0 1 120 | 0 0 1 121 | 0 0 1 122 | 0 0 1 123 | -------------------------------------------------------------------------------- /data/vtks/grid_of_triangles.vtk: -------------------------------------------------------------------------------- 1 | # vtk DataFile Version 1.0 2 | 2D Unstructured Grid of Linear Triangles 3 | ASCII 4 | 5 | DATASET UNSTRUCTURED_GRID 6 | POINTS 8 float 7 | 0.0 0.0 0.0 8 | 1.0 0.0 0.0 9 | 2.0 0.0 0.0 10 | 0.0 1.0 0.0 11 | 1.0 1.0 0.0 12 | 2.0 1.0 0.0 13 | 0.0 2.0 0.0 14 | 1.0 2.0 0.0 15 | 16 | CELLS 6 24 17 | 3 0 1 3 18 | 3 1 4 3 19 | 3 1 2 4 20 | 3 2 5 4 21 | 3 3 4 6 22 | 3 4 7 6 23 | 24 | CELL_TYPES 6 25 | 5 26 | 5 27 | 5 28 | 5 29 | 5 30 | 5 31 | 32 | POINT_DATA 8 33 | SCALARS pressure float 34 | LOOKUP_TABLE default 35 | 0.0 36 | 1.0 37 | 2.0 38 | 1.0 39 | 2.0 40 | 3.0 41 | 2.0 42 | 3.0 43 | 44 | VECTORS velocity float 45 | 1.0 1.0 0.0 46 | 2.0 1.0 0.0 47 | 3.0 1.0 0.0 48 | 1.0 2.0 0.0 49 | 2.0 2.0 0.0 50 | 3.0 2.0 0.0 51 | 1.0 3.0 0.0 52 | 2.0 3.0 0.0 53 | -------------------------------------------------------------------------------- /data/vtks/polydata_line.vtk: -------------------------------------------------------------------------------- 1 | # vtk DataFile Version 1.0 2 | Line representation of vtk 3 | ASCII 4 | 5 | DATASET POLYDATA 6 | POINTS 12 float 7 | 0.0 2.0 0.0 8 | 1.0 0.0 0.0 9 | 2.0 2.0 0.0 10 | 3.0 0.0 0.0 11 | 3.0 3.0 0.0 12 | 2.5 2.0 0.0 13 | 3.5 2.0 0.0 14 | 4.0 0.0 0.0 15 | 4.0 3.0 0.0 16 | 5.0 2.0 0.0 17 | 4.0 1.0 0.0 18 | 5.0 0.0 0.0 19 | 20 | LINES 5 17 21 | 3 0 1 2 22 | 2 3 4 23 | 2 5 6 24 | 2 7 8 25 | 3 9 10 11 26 | -------------------------------------------------------------------------------- /data/vtks/texture_map.vtk: -------------------------------------------------------------------------------- 1 | # vtk DataFile Version 1.0 2 | Texture map for thresholding data (use boolean textures for 2D map) 3 | ASCII 4 | 5 | DATASET STRUCTURED_POINTS 6 | DIMENSIONS 128 1 1 7 | ASPECT_RATIO 1 1 1 8 | ORIGIN 0.0 0.0 0.0 9 | 10 | POINT_DATA 128 11 | COLOR_SCALARS texture 2 12 | 1.0 .5 13 | 1.0 .5 14 | 1.0 .5 15 | 1.0 .5 16 | 1.0 .5 17 | 1.0 .5 18 | 1.0 .5 19 | 1.0 .5 20 | 1.0 .5 21 | 1.0 .5 22 | 1.0 .5 23 | 1.0 .5 24 | 1.0 .5 25 | 1.0 .5 26 | 1.0 .5 27 | 1.0 .5 28 | 1.0 .5 29 | 1.0 .5 30 | 1.0 .5 31 | 1.0 .5 32 | 1.0 .5 33 | 1.0 .5 34 | 1.0 .5 35 | 1.0 .5 36 | 1.0 .5 37 | 1.0 .5 38 | 1.0 .5 39 | 1.0 .5 40 | 1.0 .5 41 | 1.0 .5 42 | 1.0 .5 43 | 1.0 .5 44 | 1.0 .5 45 | 1.0 .5 46 | 1.0 .5 47 | 1.0 .5 48 | 1.0 .5 49 | 1.0 .5 50 | 1.0 .5 51 | 1.0 .5 52 | 1.0 .5 53 | 1.0 .5 54 | 1.0 .5 55 | 1.0 .5 56 | 1.0 .5 57 | 1.0 .5 58 | 1.0 .5 59 | 1.0 .5 60 | 1.0 .5 61 | 1.0 .5 62 | 1.0 .5 63 | 1.0 .5 64 | 1.0 .5 65 | 1.0 .5 66 | 1.0 .5 67 | 1.0 .5 68 | 1.0 .5 69 | 1.0 .5 70 | 1.0 .5 71 | 1.0 .5 72 | 1.0 .5 73 | 1.0 .5 74 | 0.0 0.0 75 | 0.0 1.0 76 | 0.0 1.0 77 | 1.0 1.0 78 | 1.0 1.0 79 | 1.0 1.0 80 | 1.0 1.0 81 | 1.0 1.0 82 | 1.0 1.0 83 | 1.0 1.0 84 | 1.0 1.0 85 | 1.0 1.0 86 | 1.0 1.0 87 | 1.0 1.0 88 | 1.0 1.0 89 | 1.0 1.0 90 | 1.0 1.0 91 | 1.0 1.0 92 | 1.0 1.0 93 | 1.0 1.0 94 | 1.0 1.0 95 | 1.0 1.0 96 | 1.0 1.0 97 | 1.0 1.0 98 | 1.0 1.0 99 | 1.0 1.0 100 | 1.0 1.0 101 | 1.0 1.0 102 | 1.0 1.0 103 | 1.0 1.0 104 | 1.0 1.0 105 | 1.0 1.0 106 | 1.0 1.0 107 | 1.0 1.0 108 | 1.0 1.0 109 | 1.0 1.0 110 | 1.0 1.0 111 | 1.0 1.0 112 | 1.0 1.0 113 | 1.0 1.0 114 | 1.0 1.0 115 | 1.0 1.0 116 | 1.0 1.0 117 | 1.0 1.0 118 | 1.0 1.0 119 | 1.0 1.0 120 | 1.0 1.0 121 | 1.0 1.0 122 | 1.0 1.0 123 | 1.0 1.0 124 | 1.0 1.0 125 | 1.0 1.0 126 | 1.0 1.0 127 | 1.0 1.0 128 | 1.0 1.0 129 | 1.0 1.0 130 | 1.0 1.0 131 | 1.0 1.0 132 | 1.0 1.0 133 | 1.0 1.0 134 | 1.0 1.0 135 | 1.0 1.0 136 | 1.0 1.0 137 | 1.0 1.0 138 | 1.0 1.0 139 | 1.0 1.0 140 | -------------------------------------------------------------------------------- /data/vtms/grid_of_triangles.vtm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /data/vtms/grid_of_triangles/grid_of_triangles_0.vtu: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | _AQAAAACAAAAgAAAAFQAAAA==eJxjYACBBnsg4YCgHRxgNAAvtgM/AQAAAACAAABgAAAANgAAAA==eJzjZ2hYepVlqz0DEIDorYfZHUDs/yymDiAMFd8PE//x//9SJHF7BbckmPoDyOph4gCScRw3AQAAAACAAABgAAAAMwAAAA==eJxjYECAqyxb7b+zmNqD2P9ZTB1AfKj4fpg4P0PDUiRx+62H2R2g6g8gq4eJAwApMBicAQAAAACAAACQAAAAIwAAAA==eJxjYIAARijNjMZnwSHOhCYP47Pi0Afjs6Hx2dHEAQ34AD0=AQAAAACAAAAwAAAAGAAAAA==eJxjZoAANijNCaV5oDQ/lBaC0gAFcABAAQAAAACAAAAGAAAACwAAAA==eJxjZQUBAABvAB8= 23 | 24 | 25 | -------------------------------------------------------------------------------- /data/vtps/naca0012.vtp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | _AQAAAACAAACwBAAADwMAAA==eJxF0n8s1HEYB3ApV0mIrBamH9xoEhaFz/d5ThKqqaTUqchxqKTi+qFfpKzlZmoRWWPMLqwf06wysUnZmbLVzY81V8patFpLtVtLv57P57v89Zrdfe55nvfbyur/X8tpL1bH9Iy7nrUHd5IdwcLW3x8T//eSdD3TpH9OMcdKGSFOEv/MMSltwJ1sflYqZdt5S+Idqc4tgKz3a5UqVoaI7z6TgvNV5JCSt5LTnCjxjkWa+nsDeeKIAozqOPGmIywKTCD3KF2hsDRRvO8FhjNJ5Jr+5TAyXSN+KxSy/bXko0VrwPA7Q54ZlCf2kWODd8AHQ5aYQQM5F7PJnu+yoFd5SN4LDPmHyZPrCiC5KkfMVgQOebnksdpiKPbQybvD8RJu048yiDbqxMxVEP6cuyOuBgqbdPJ9YHYCd1NjIzzszxW73Iatvtzl1i1wakeOfEN4nMTnKVB3wA3VIbFjF+gn+fxZzUbounpAvjNcduQ7brc1gXemvPsQNNRmkiNSzODdni5nATfb0sjLW99DQLVG3OQj1Gn3kBc4TcCoc5KcFzw17CTb7J0EnyVqcasp2F7E87K8nooRL+LlTDFzJs/0k91MHPLZKG44C/2DeO6jq+xR4Rsj547j9mvJQ6nOmGJeLW7rgp+uIbmvdD4qIpncDXQdXkV+3OaOFZogcfOF+GqQ97D1/WKMlfzk/mDYpaXkO3O98ZtJKbJYit0zlpDrVcvwq6+H3DF8EO5KrtofiLFR80RGQTgqOZMvVazEBi8HuYfY+cuWXNTFcJNRIbJDPHDemnzycziman8y0VVU10+QD7tFoal7nPFMY3D46Qg5PXoDHr03yESfsfJcH3lX7ua/N3zCeNbx6GFsI2+p2YagustE5zHxWgM5ujcRpYFqxjuwG69/LyODJRmXWYoZ74MGr7wsIK/w1OIbVTbj3cjAW3o12WfTPqyrjGS8J1n4SOtP9jh5ECe/LGC8MznoL9mQXW7oMOaCOYz35xgqZzeTbU15uFpxPox36RSeHfEjW1nlY7myPvSf/gBqtkEfAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAAAAAACAAAAAAAAAAQAAAACAAAAgAwAArwAAAA==eJwtxdciAgAAAMCQWSFbJCuzsjNDiuyMyo7y///gwd3LBQL/WtzqNgfd7g53usvd7nHIYUfc6z73O+oBD3rIwx7xqMc87pgnPOm4p5zwtGc86znPO+kFL3rJy17xqlNOO+M1r3vDm97ytnec9a73vO8DH/rIOR/7xKfO+8wFF33uC5d86Stf+8a3vvO9y37wo5/87IqrrvnFr37zuz/86S/X/e0fN9z0r/8AXBwTVw==AQAAAACAAAAIAAAACwAAAA==eJxLYYAAAAMoAGU= 32 | 33 | 34 | -------------------------------------------------------------------------------- /data/vtus/grid_of_triangles.vtu: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | _AQAAAACAAAAgAAAAFQAAAA==eJxjYACBBnsg4YCgHRxgNAAvtgM/AQAAAACAAABgAAAANgAAAA==eJzjZ2hYepVlqz0DEIDorYfZHUDs/yymDiAMFd8PE//x//9SJHF7BbckmPoDyOph4gCScRw3AQAAAACAAABgAAAAMwAAAA==eJxjYECAqyxb7b+zmNqD2P9ZTB1AfKj4fpg4P0PDUiRx+62H2R2g6g8gq4eJAwApMBicAQAAAACAAACQAAAAIwAAAA==eJxjYIAARijNjMZnwSHOhCYP47Pi0Afjs6Hx2dHEAQ34AD0=AQAAAACAAAAwAAAAGAAAAA==eJxjZoAANijNCaV5oDQ/lBaC0gAFcABAAQAAAACAAAAGAAAACwAAAA==eJxjZQUBAABvAB8= 23 | 24 | 25 | -------------------------------------------------------------------------------- /notes/03_input_and_output.md: -------------------------------------------------------------------------------- 1 | ## Input and Output 2 | 3 | VTK offers a comprehensive suite of tools for reading and writing a variety of data formats. This includes the native VTK file formats (legacy and XML-based), as well as numerous third-party formats. 4 | 5 | ### Common File Formats 6 | 7 | VTK supports an extensive range of data formats, including: 8 | 9 | I. Legacy VTK File Format 10 | 11 | - **Nature**: ASCII or binary. 12 | - **Features**: Supports various data structures and attributes. 13 | - **Structure**: Composed of five main sections - file version and identifier, header, dataset type, dataset structure, and data attributes. 14 | 15 | Example: 16 | 17 | ``` 18 | # vtk DataFile Version 3.0 19 | VTK Example Data 20 | ASCII 21 | DATASET POLYDATA 22 | POINTS 8 float 23 | 0.0 0.0 0.0 24 | 1.0 0.0 0.0 25 | 1.0 1.0 0.0 26 | 0.0 1.0 0.0 27 | 0.0 0.0 1.0 28 | 1.0 0.0 1.0 29 | 1.0 1.0 1.0 30 | 0.0 1.0 1.0 31 | POLYGONS 6 30 32 | 4 0 1 2 3 33 | ... 34 | ``` 35 | 36 | II. XML-Based VTK File Format 37 | 38 | - **Nature**: ASCII or binary, offering enhanced flexibility and extensibility. 39 | - **Features**: Supports a diverse range of data structures and attributes. 40 | - **File Extensions**: Includes formats like `.vtp` for PolyData, `.vtu` for UnstructuredGrid, and `.vts` for StructuredGrid, among others. 41 | 42 | Example: 43 | 44 | ``` 45 | 46 | 47 | 48 | 49 | 50 | 51 | 0.0 0.0 0.0 1.0 0.0 0.0 1.0 1.0 0.0 0.0 1.0 0.0 ... 52 | 53 | 54 | 55 | 56 | 0 1 2 3 ... 57 | 58 | ... 59 | 60 | 61 | 62 | 63 | ``` 64 | 65 | III. Third-Party File Formats 66 | 67 | - **Scope**: VTK interfaces seamlessly with many popular 3D graphics and scientific visualization file formats. 68 | - **STL**: Predominantly used in 3D printing. 69 | - **PLY**: Specializes in storing polygonal meshes. 70 | - **OBJ**: Capable of holding complex 3D models encompassing geometry, texture, and material data. 71 | 72 | Example (STL): 73 | 74 | ``` 75 | solid vtkGenerated 76 | facet normal 0 0 -1 77 | outer loop 78 | vertex 0.0 0.0 0.0 79 | vertex 1.0 0.0 0.0 80 | vertex 1.0 1.0 0.0 81 | endloop 82 | endfacet 83 | ... 84 | endsolid vtkGenerated 85 | ``` 86 | 87 | Example (PLY): 88 | 89 | ``` 90 | ply 91 | format ascii 1.0 92 | element vertex 8 93 | property float x 94 | property float y 95 | property float z 96 | element face 6 97 | property list uchar int vertex_indices 98 | end_header 99 | 0.0 0.0 0.0 100 | 1.0 0.0 0.0 101 | ... 102 | 3 0 1 2 103 | ... 104 | ``` 105 | 106 | ### Reading and Writing Data 107 | 108 | There is a suite of subclasses derived from `vtkDataReader` and `vtkDataWriter`. These subclasses are specialized for handling various VTK data structures, emphasizing efficient and accurate data manipulation. The design ensures flexibility in reading and writing different types of data while maintaining the robustness of data integrity and format compatibility. 109 | 110 | #### Subclasses for Data Reading and Writing 111 | 112 | Each subclass under `vtkDataReader` and `vtkDataWriter` is tailored for specific data structures, facilitating precise and optimized read/write operations: 113 | 114 | - **vtkPolyDataReader** and **vtkPolyDataWriter**: For handling polygonal data, commonly used in 3D graphics and modeling. 115 | - **vtkStructuredPointsReader** and **vtkStructuredPointsWriter**: Optimized for structured point datasets, where data is arranged in a regular grid. 116 | - **vtkStructuredGridReader** and **vtkStructuredGridWriter**: Suitable for structured grid data, a step above structured points in complexity, allowing for non-uniform grids. 117 | - **vtkUnstructuredGridReader** and **vtkUnstructuredGridWriter**: Designed for unstructured grid data, which is the most flexible, accommodating irregularly spaced data points. 118 | 119 | #### Example 120 | 121 | Below is a Python script demonstrating how to read data from an STL file (common in 3D printing and modeling) and write it into VTK's native format. 122 | 123 | ```python 124 | import vtk 125 | 126 | # Initialize an STL reader and set the file to read 127 | stl_reader = vtk.vtkSTLReader() 128 | stl_reader.SetFileName("input.stl") 129 | 130 | # Set up a VTK writer and connect it to the output of the STL reader 131 | vtk_writer = vtk.vtkPolyDataWriter() 132 | vtk_writer.SetInputConnection(stl_reader.GetOutputPort()) 133 | vtk_writer.SetFileName("output.vtk") 134 | 135 | # Execute the writing process to convert the STL file to a VTK file 136 | vtk_writer.Write() 137 | ``` 138 | 139 | This script shows the straightforward approach of VTK in converting data between different formats, highlighting its powerful data processing capabilities. 140 | 141 | ## Readers and Writers Comparison 142 | 143 | A comparison of various readers and writers for different formats is provided below: 144 | 145 | | Format | Reader Class | Output Data Type | Writer Class | Input Data Type | 146 | |-----------|---------------------------------|-----------------------------|-------------------------------|--------------------------| 147 | | STL | `vtkSTLReader` | `vtkPolyData` | `vtkSTLWriter` | `vtkPolyData` | 148 | | OBJ | `vtkOBJReader` | `vtkPolyData` | `vtkOBJWriter` | `vtkPolyData` | 149 | | VTK (Legacy) | `vtkUnstructuredGridReader` | `vtkUnstructuredGrid` | `vtkUnstructuredGridWriter` | `vtkUnstructuredGrid` | 150 | | | `vtkStructuredGridReader` | `vtkStructuredGrid` | `vtkStructuredGridWriter` | `vtkStructuredGrid` | 151 | | | `vtkPolyDataReader` | `vtkPolyData` | `vtkPolyDataWriter` | `vtkPolyData` | 152 | | | `vtkRectilinearGridReader` | `vtkRectilinearGrid` | `vtkRectilinearGridWriter` | `vtkRectilinearGrid` | 153 | | | `vtkStructuredPointsReader` | `vtkStructuredPoints` | `vtkStructuredPointsWriter` | `vtkStructuredPoints` | 154 | | VTU | `vtkXMLUnstructuredGridReader` | `vtkUnstructuredGrid` | `vtkXMLUnstructuredGridWriter`| `vtkUnstructuredGrid` | 155 | | VTM | `vtkXMLMultiBlockDataReader` | `vtkMultiBlockDataSet` | `vtkXMLMultiBlockDataWriter` | `vtkMultiBlockDataSet` | 156 | | OpenFOAM | `vtkOpenFOAMReader` | `vtkMultiBlockDataSet` | N/A | N/A | 157 | | EnSight | `vtkEnSightGoldReader` | `vtkMultiBlockDataSet` | N/A | N/A | 158 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohappyeyeballs==2.6.1 2 | aiohttp==3.11.18 3 | aiosignal==1.3.2 4 | async-timeout==5.0.1 5 | attrs==25.3.0 6 | charset-normalizer==3.4.1 7 | contourpy==1.3.2 8 | cramjam==2.10.0 9 | cycler==0.12.1 10 | fastparquet==2024.11.0 11 | fonttools==4.57.0 12 | frozenlist==1.6.0 13 | fsspec==2025.3.2 14 | idna==3.10 15 | kiwisolver==1.4.8 16 | matplotlib==3.10.1 17 | msgpack==1.1.0 18 | multidict==6.4.3 19 | numpy==2.2.5 20 | packaging==25.0 21 | pandas==2.2.3 22 | pillow==11.2.1 23 | propcache==0.3.1 24 | py4j==0.10.9.7 25 | pyarrow==19.0.1 26 | pyparsing==3.2.3 27 | PyQt6==6.9.0 28 | PyQt6-Qt6==6.9.0 29 | PyQt6_sip==13.10.0 30 | pyspark==3.5.5 31 | python-dateutil==2.9.0.post0 32 | pytz==2025.2 33 | PyVTK==0.5.18 34 | six==1.17.0 35 | tzdata==2025.2 36 | vtk==9.4.2 37 | wslink==2.3.3 38 | yarl==1.20.0 39 | -------------------------------------------------------------------------------- /src/01_basic_shapes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/01_basic_shapes/__init__.py -------------------------------------------------------------------------------- /src/01_basic_shapes/circle.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import vtk 4 | 5 | from src.common.simple_pipeline import VisualisationPipeline 6 | 7 | 8 | def create_circle_mapper( 9 | radius: float, center: Tuple[float, float, float], resolution: int = 100 10 | ) -> vtk.vtkPolyDataMapper: 11 | circle = vtk.vtkRegularPolygonSource() 12 | circle.SetNumberOfSides(resolution) 13 | circle.SetRadius(radius) 14 | circle.SetCenter(center) 15 | circle.SetNormal(0, 0, 1) 16 | 17 | circle_mapper = vtk.vtkPolyDataMapper() 18 | circle_mapper.SetInputConnection(circle.GetOutputPort()) 19 | 20 | return circle_mapper 21 | 22 | 23 | if __name__ == "__main__": 24 | # Create a circle with different radius and center 25 | circle_mapper1 = create_circle_mapper(radius=1.0, center=(0.0, 0.0, 0.0)) 26 | circle_mapper2 = create_circle_mapper(radius=2.0, center=(4.0, 0.0, 0.0)) 27 | 28 | # Display the circles 29 | pipeline = VisualisationPipeline(mappers=[circle_mapper1, circle_mapper2]) 30 | pipeline.run() 31 | -------------------------------------------------------------------------------- /src/01_basic_shapes/cone.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import vtk 4 | 5 | from src.common.simple_pipeline import VisualisationPipeline 6 | 7 | 8 | def create_cone_mapper( 9 | radius: float, 10 | height: float, 11 | center: Tuple[float, float, float], 12 | resolution: int = 100, 13 | ) -> vtk.vtkPolyDataMapper: 14 | cone = vtk.vtkConeSource() 15 | cone.SetRadius(radius) 16 | cone.SetHeight(height) 17 | cone.SetCenter(center) 18 | cone.SetDirection(0, 0, 1) 19 | cone.SetResolution(resolution) 20 | 21 | cone_mapper = vtk.vtkPolyDataMapper() 22 | cone_mapper.SetInputConnection(cone.GetOutputPort()) 23 | 24 | return cone_mapper 25 | 26 | 27 | if __name__ == "__main__": 28 | # Create cones with different radius, height, and center 29 | cone_mapper1 = create_cone_mapper(radius=1.0, height=2.0, center=(0.0, 0.0, 0.0)) 30 | cone_mapper2 = create_cone_mapper(radius=1.5, height=3.0, center=(4.0, 0.0, 0.0)) 31 | 32 | # Display the cones 33 | pipeline = VisualisationPipeline(mappers=[cone_mapper1, cone_mapper2]) 34 | pipeline.run() 35 | -------------------------------------------------------------------------------- /src/01_basic_shapes/cube.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import vtk 4 | 5 | from src.common.simple_pipeline import VisualisationPipeline 6 | 7 | 8 | def create_cube_mapper(bounds: List[float]) -> vtk.vtkPolyDataMapper: 9 | cube = vtk.vtkCubeSource() 10 | cube.SetBounds(bounds) 11 | 12 | cube_mapper = vtk.vtkPolyDataMapper() 13 | cube_mapper.SetInputConnection(cube.GetOutputPort()) 14 | 15 | return cube_mapper 16 | 17 | 18 | if __name__ == "__main__": 19 | # Create cubes with different bounds 20 | cube_mapper1 = create_cube_mapper(bounds=[0.0, 1.0, 0.0, 1.0, 0.0, 1.0]) 21 | cube_mapper2 = create_cube_mapper(bounds=[2.0, 4.0, 0.0, 1.0, 0.0, 1.0]) 22 | 23 | # Display the cubes 24 | pipeline = VisualisationPipeline(mappers=[cube_mapper1, cube_mapper2]) 25 | pipeline.run() 26 | -------------------------------------------------------------------------------- /src/01_basic_shapes/cylinder.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import vtk 4 | 5 | from src.common.simple_pipeline import VisualisationPipeline 6 | 7 | 8 | def create_cylinder_mapper( 9 | radius: float, 10 | height: float, 11 | center: Tuple[float, float, float], 12 | resolution: int = 100, 13 | ) -> vtk.vtkPolyDataMapper: 14 | cylinder = vtk.vtkCylinderSource() 15 | cylinder.SetRadius(radius) 16 | cylinder.SetHeight(height) 17 | cylinder.SetCenter(center) 18 | cylinder.SetResolution(resolution) 19 | 20 | cylinder_mapper = vtk.vtkPolyDataMapper() 21 | cylinder_mapper.SetInputConnection(cylinder.GetOutputPort()) 22 | 23 | return cylinder_mapper 24 | 25 | 26 | if __name__ == "__main__": 27 | # Create cylinders with different radius, height, and center 28 | cylinder_mapper1 = create_cylinder_mapper( 29 | radius=1.0, height=2.0, center=(0.0, 0.0, 0.0) 30 | ) 31 | cylinder_mapper2 = create_cylinder_mapper( 32 | radius=1.5, height=3.0, center=(4.0, 0.0, 0.0) 33 | ) 34 | 35 | # Display the cylinders 36 | pipeline = VisualisationPipeline(mappers=[cylinder_mapper1, cylinder_mapper2]) 37 | pipeline.run() 38 | -------------------------------------------------------------------------------- /src/01_basic_shapes/glyph.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | from src.common.simple_pipeline import VisualisationPipeline 4 | 5 | 6 | def create_arrow_glyphs(vector_field): 7 | # Create arrow source 8 | arrow_source = vtk.vtkArrowSource() 9 | 10 | # Create glyph points and vectors 11 | glyph_points = vtk.vtkPoints() 12 | glyph_vectors = vtk.vtkDoubleArray() 13 | glyph_vectors.SetNumberOfComponents(3) 14 | glyph_vectors.SetNumberOfTuples(vector_field.shape[0] * vector_field.shape[1]) 15 | 16 | idx = 0 17 | for i in range(vector_field.shape[0]): 18 | for j in range(vector_field.shape[1]): 19 | x, y, z = i, j, 0 20 | u, v, w = vector_field[i, j] 21 | glyph_points.InsertPoint(idx, x, y, z) 22 | glyph_vectors.SetTuple(idx, (u, v, w)) 23 | idx += 1 24 | 25 | # Create glyph polydata 26 | glyph_polydata = vtk.vtkPolyData() 27 | glyph_polydata.SetPoints(glyph_points) 28 | glyph_polydata.GetPointData().SetVectors(glyph_vectors) 29 | 30 | # Create the glyph3D filter 31 | glyph3D = vtk.vtkGlyph3D() 32 | glyph3D.SetSourceConnection(arrow_source.GetOutputPort()) 33 | glyph3D.SetInputData(glyph_polydata) 34 | glyph3D.SetVectorModeToUseVector() 35 | glyph3D.SetScaleModeToScaleByVector() 36 | glyph3D.SetScaleFactor(0.5) 37 | 38 | glyph_mapper = vtk.vtkPolyDataMapper() 39 | glyph_mapper.SetInputConnection(glyph3D.GetOutputPort()) 40 | 41 | return glyph_mapper 42 | 43 | 44 | def generate_vector_field(size, scale): 45 | import numpy as np 46 | 47 | x, y = np.meshgrid( 48 | np.linspace(-scale, scale, size), np.linspace(-scale, scale, size) 49 | ) 50 | u = -y 51 | v = x 52 | vector_field = np.stack((u, v, np.zeros_like(u)), axis=-1) 53 | return vector_field 54 | 55 | 56 | if __name__ == "__main__": 57 | vector_field = generate_vector_field(size=11, scale=5) 58 | glyph_mapper = create_arrow_glyphs(vector_field) 59 | 60 | # Display the glyphs 61 | pipeline = VisualisationPipeline(mappers=[glyph_mapper]) 62 | pipeline.run() 63 | -------------------------------------------------------------------------------- /src/01_basic_shapes/square.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import vtk 4 | 5 | from src.common.simple_pipeline import VisualisationPipeline 6 | 7 | 8 | def create_square_mapper( 9 | origin: Tuple[float, float, float], 10 | point1: Tuple[float, float, float], 11 | point2: Tuple[float, float, float], 12 | ) -> vtk.vtkPolyDataMapper: 13 | square = vtk.vtkPlaneSource() 14 | square.SetOrigin(origin) 15 | square.SetPoint1(point1) 16 | square.SetPoint2(point2) 17 | 18 | square_mapper = vtk.vtkPolyDataMapper() 19 | square_mapper.SetInputConnection(square.GetOutputPort()) 20 | 21 | return square_mapper 22 | 23 | 24 | if __name__ == "__main__": 25 | # Create squares with different positions and sizes 26 | square_mapper1 = create_square_mapper( 27 | origin=(0.0, 0.0, 0.0), point1=(1.0, 0.0, 0.0), point2=(0.0, 1.0, 0.0) 28 | ) 29 | square_mapper2 = create_square_mapper( 30 | origin=(3.0, 0.0, 0.0), point1=(4.0, 0.0, 0.0), point2=(3.0, 1.0, 0.0) 31 | ) 32 | 33 | # Display the squares 34 | pipeline = VisualisationPipeline(mappers=[square_mapper1, square_mapper2]) 35 | pipeline.run() 36 | -------------------------------------------------------------------------------- /src/01_basic_shapes/triangle.py: -------------------------------------------------------------------------------- 1 | from typing import List, Tuple 2 | 3 | import vtk 4 | 5 | from src.common.simple_pipeline import VisualisationPipeline 6 | 7 | 8 | def create_triangle_mapper( 9 | points: List[Tuple[float, float, float]] 10 | ) -> vtk.vtkPolyDataMapper: 11 | triangle = vtk.vtkTriangle() 12 | triangle.GetPointIds().SetId(0, 0) 13 | triangle.GetPointIds().SetId(1, 1) 14 | triangle.GetPointIds().SetId(2, 2) 15 | 16 | points_array = vtk.vtkPoints() 17 | for point in points: 18 | points_array.InsertNextPoint(point) 19 | 20 | triangles = vtk.vtkCellArray() 21 | triangles.InsertNextCell(triangle) 22 | 23 | triangle_polydata = vtk.vtkPolyData() 24 | triangle_polydata.SetPoints(points_array) 25 | triangle_polydata.SetPolys(triangles) 26 | 27 | triangle_mapper = vtk.vtkPolyDataMapper() 28 | triangle_mapper.SetInputData(triangle_polydata) 29 | 30 | return triangle_mapper 31 | 32 | 33 | if __name__ == "__main__": 34 | # Create triangles with different vertex positions 35 | triangle_mapper1 = create_triangle_mapper( 36 | [(0.0, 0.0, 0.0), (1.0, 0.0, 0.0), (0.5, 1.0, 0.0)] 37 | ) 38 | triangle_mapper2 = create_triangle_mapper( 39 | [(3.0, 0.0, 0.0), (4.0, 0.0, 0.0), (3.5, 1.0, 0.0)] 40 | ) 41 | 42 | # Display the triangles 43 | pipeline = VisualisationPipeline(mappers=[triangle_mapper1, triangle_mapper2]) 44 | pipeline.run() 45 | -------------------------------------------------------------------------------- /src/02_advanced_shapes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/02_advanced_shapes/__init__.py -------------------------------------------------------------------------------- /src/02_advanced_shapes/custom_filter_sphere.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import math 3 | from datetime import datetime, UTC 4 | 5 | 6 | class DistanceToPointFilter(vtk.vtkPolyDataAlgorithm): 7 | """ 8 | A VTK filter that computes the Euclidean distance from each point in the input 9 | vtkPolyData to a specified target point. 10 | """ 11 | 12 | def __init__(self): 13 | super().__init__() 14 | self.__TargetPoint = [0.0, 0.0, 0.0] 15 | self.GetExecutive().SetOutputData(0, vtk.vtkPolyData()) 16 | 17 | def SetTargetPoint(self, x, y, z): 18 | try: 19 | self.__TargetPoint = [float(x), float(y), float(z)] 20 | self.Modified() 21 | return True 22 | except ValueError as e: 23 | print(f"Error setting target point: {e}") 24 | return False 25 | 26 | def GetTargetPoint(self): 27 | return tuple(self.__TargetPoint) 28 | 29 | def ProcessDataObject(self, input_data): 30 | if not input_data: 31 | print("No input data provided") 32 | return None 33 | 34 | output_data = vtk.vtkPolyData() 35 | output_data.DeepCopy(input_data) 36 | 37 | num_points = input_data.GetNumberOfPoints() 38 | print(f"Processing {num_points} points...") 39 | 40 | distances = vtk.vtkDoubleArray() 41 | distances.SetName("DistanceToTarget") 42 | distances.SetNumberOfComponents(1) 43 | distances.SetNumberOfTuples(num_points) 44 | 45 | tx, ty, tz = self.__TargetPoint 46 | min_dist = float('inf') 47 | max_dist = float('-inf') 48 | 49 | for i in range(num_points): 50 | point = input_data.GetPoint(i) 51 | dx = point[0] - tx 52 | dy = point[1] - ty 53 | dz = point[2] - tz 54 | distance = math.sqrt(dx * dx + dy * dy + dz * dz) 55 | distances.SetValue(i, distance) 56 | min_dist = min(min_dist, distance) 57 | max_dist = max(max_dist, distance) 58 | 59 | print(f"Distance range: [{min_dist:.3f}, {max_dist:.3f}]") 60 | output_data.GetPointData().SetScalars(distances) 61 | return output_data 62 | 63 | 64 | def create_actor(poly_data, scalar_range=None, color=None): 65 | """Create a VTK actor from polydata with optional scalar coloring or solid color.""" 66 | mapper = vtk.vtkPolyDataMapper() 67 | mapper.SetInputData(poly_data) 68 | 69 | if scalar_range and poly_data.GetPointData().GetScalars(): 70 | mapper.SetScalarRange(scalar_range) 71 | 72 | # Create lookup table for distance visualization 73 | lut = vtk.vtkLookupTable() 74 | lut.SetHueRange(0.667, 0.0) # blue to red 75 | lut.SetSaturationRange(1.0, 1.0) 76 | lut.SetValueRange(1.0, 1.0) 77 | lut.SetTableRange(scalar_range) 78 | lut.Build() 79 | 80 | mapper.SetLookupTable(lut) 81 | mapper.SetScalarVisibility(1) 82 | else: 83 | mapper.SetScalarVisibility(0) 84 | 85 | actor = vtk.vtkActor() 86 | actor.SetMapper(mapper) 87 | 88 | if color: 89 | actor.GetProperty().SetColor(color) 90 | 91 | return actor 92 | 93 | 94 | def create_visualization(): 95 | try: 96 | # Create source 97 | print("Creating sphere source...") 98 | sphere = vtk.vtkSphereSource() 99 | sphere.SetRadius(1.0) 100 | sphere.SetThetaResolution(30) 101 | sphere.SetPhiResolution(30) 102 | sphere.Update() 103 | 104 | input_data = sphere.GetOutput() 105 | print(f"Sphere created with {input_data.GetNumberOfPoints()} points") 106 | 107 | # Process with filter 108 | print("Creating and executing distance filter...") 109 | filter = DistanceToPointFilter() 110 | output_data = filter.ProcessDataObject(input_data) 111 | 112 | if not output_data: 113 | raise RuntimeError("Filter failed to process data") 114 | 115 | print(f"Filter output has {output_data.GetNumberOfPoints()} points") 116 | 117 | # Get scalar range for coloring 118 | scalars = output_data.GetPointData().GetScalars() 119 | if not scalars: 120 | raise RuntimeError("No scalar data in filter output") 121 | 122 | scalar_range = scalars.GetRange() 123 | print(f"Scalar range: [{scalar_range[0]:.3f}, {scalar_range[1]:.3f}]") 124 | 125 | # Create actors for both spheres 126 | original_actor = create_actor(input_data, color=(0.8, 0.8, 1.0)) # Light blue 127 | filtered_actor = create_actor(output_data, scalar_range=scalar_range) 128 | 129 | # Create renderers for split view 130 | left_renderer = vtk.vtkRenderer() 131 | right_renderer = vtk.vtkRenderer() 132 | 133 | # Set viewport (x1, y1, x2, y2) - split screen in half 134 | left_renderer.SetViewport(0.0, 0.0, 0.5, 1.0) 135 | right_renderer.SetViewport(0.5, 0.0, 1.0, 1.0) 136 | 137 | # Add actors to respective renderers 138 | left_renderer.AddActor(original_actor) 139 | right_renderer.AddActor(filtered_actor) 140 | 141 | # Set background colors 142 | left_renderer.SetBackground(0.1, 0.1, 0.1) 143 | right_renderer.SetBackground(0.2, 0.2, 0.2) 144 | 145 | # Create render window 146 | render_window = vtk.vtkRenderWindow() 147 | render_window.AddRenderer(left_renderer) 148 | render_window.AddRenderer(right_renderer) 149 | render_window.SetSize(1200, 600) # Wider window for side-by-side view 150 | 151 | # Create interactor 152 | interactor = vtk.vtkRenderWindowInteractor() 153 | interactor.SetRenderWindow(render_window) 154 | 155 | # Add orientation widgets to both views 156 | for renderer, viewport_coords in [(left_renderer, (0.0, 0.0, 0.2, 0.2)), 157 | (right_renderer, (0.5, 0.0, 0.7, 0.2))]: 158 | axes = vtk.vtkAxesActor() 159 | widget = vtk.vtkOrientationMarkerWidget() 160 | widget.SetOrientationMarker(axes) 161 | widget.SetInteractor(interactor) 162 | widget.SetViewport(*viewport_coords) 163 | widget.SetEnabled(1) 164 | widget.InteractiveOn() 165 | 166 | # Add titles 167 | left_text = vtk.vtkTextActor() 168 | left_text.SetInput("Original Sphere") 169 | left_text.GetTextProperty().SetFontSize(24) 170 | left_text.SetPosition(10, 10) 171 | left_renderer.AddActor2D(left_text) 172 | 173 | right_text = vtk.vtkTextActor() 174 | right_text.SetInput("Distance-Colored Sphere") 175 | right_text.GetTextProperty().SetFontSize(24) 176 | right_text.SetPosition(10, 10) 177 | right_renderer.AddActor2D(right_text) 178 | 179 | # Initialize view 180 | left_renderer.ResetCamera() 181 | right_renderer.ResetCamera() 182 | 183 | # Link cameras 184 | right_renderer.SetActiveCamera(left_renderer.GetActiveCamera()) 185 | 186 | render_window.Render() 187 | interactor.Initialize() 188 | 189 | print("Visualization setup complete") 190 | return interactor 191 | 192 | except Exception as e: 193 | print(f"Error in visualization setup: {str(e)}") 194 | import traceback 195 | print(f"Traceback:\n{traceback.format_exc()}") 196 | return None 197 | 198 | 199 | if __name__ == "__main__": 200 | print("Current Date and Time (UTC - YYYY-MM-DD HH:MM:SS formatted):", 201 | datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S')) 202 | print("Current User's Login: djeada") 203 | 204 | interactor = create_visualization() 205 | if interactor: 206 | print("Starting interaction...") 207 | interactor.Start() 208 | else: 209 | print("Failed to setup visualization.") -------------------------------------------------------------------------------- /src/02_advanced_shapes/enclosing_box.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module demonstrates the workflow of creating and visualizing a set of randomly positioned spheres within an enclosing box using the Visualization Toolkit (VTK). It highlights the use of VTK's capabilities for generating and displaying 3D objects in a defined space, showcasing fundamental concepts in computational geometry and 3D visualization. 3 | 4 | Workflow Overview: 5 | 6 | 1. Sphere Creation (create_random_sphere): 7 | - Generates individual spheres with specified centers and radii. 8 | - Illustrates how to create basic 3D objects (spheres) in VTK. 9 | 10 | 2. Random Spheres Mapper (create_random_spheres_mapper): 11 | - Constructs multiple spheres, each positioned randomly within a specified box size. 12 | - Utilizes vtkAppendPolyData to combine multiple vtkSphereSources into a single data structure. 13 | - Creates a vtkPolyDataMapper for the set of spheres, preparing them for visualization. 14 | 15 | 3. Enclosing Box Mapper (create_enclosing_box_mapper): 16 | - Generates an enclosing box (using vtkCubeSource) that defines the boundary for the random spheres. 17 | - Applies vtkOutlineFilter to create an outline of the box, enhancing spatial understanding. 18 | - Produces a vtkPolyDataMapper for the box, allowing it to be rendered alongside the spheres. 19 | 20 | 4. Visualization Pipeline: 21 | - The module uses a predefined 'VisualisationPipeline' class to manage the rendering process. 22 | - Both the random spheres and the enclosing box are visualized together, providing context and enhancing the perception of the 3D space. 23 | """ 24 | 25 | import random 26 | from typing import Tuple 27 | 28 | import vtk 29 | 30 | from src.common.simple_pipeline import VisualisationPipeline 31 | 32 | 33 | def create_random_sphere( 34 | center: Tuple[float, float, float], radius: float 35 | ) -> vtk.vtkSphereSource: 36 | """ 37 | Create a sphere source with specified center and radius. 38 | 39 | Args: 40 | center (tuple): The center of the sphere. 41 | radius (float): The radius of the sphere. 42 | 43 | Returns: 44 | vtkSphereSource: A VTK sphere source. 45 | """ 46 | sphere = vtk.vtkSphereSource() 47 | sphere.SetCenter(*center) 48 | sphere.SetRadius(radius) 49 | sphere.Update() 50 | return sphere 51 | 52 | 53 | def create_random_spheres_mapper( 54 | n_spheres: int, box_size: float, sphere_radius: float = 0.2 55 | ) -> vtk.vtkPolyDataMapper: 56 | """ 57 | Create a mapper for a set of randomly positioned spheres within a box. 58 | 59 | Args: 60 | n_spheres (int): Number of spheres to create. 61 | box_size (float): Size of the box in which spheres are contained. 62 | sphere_radius (float): Radius of each sphere. 63 | 64 | Returns: 65 | vtkPolyDataMapper: A mapper for the random spheres. 66 | """ 67 | append_filter = vtk.vtkAppendPolyData() 68 | 69 | for _ in range(n_spheres): 70 | center = ( 71 | random.uniform(-box_size / 2, box_size / 2), 72 | random.uniform(-box_size / 2, box_size / 2), 73 | random.uniform(-box_size / 2, box_size / 2), 74 | ) 75 | sphere = create_random_sphere(center, sphere_radius) 76 | append_filter.AddInputConnection(sphere.GetOutputPort()) 77 | 78 | append_filter.Update() 79 | 80 | mapper = vtk.vtkPolyDataMapper() 81 | mapper.SetInputConnection(append_filter.GetOutputPort()) 82 | return mapper 83 | 84 | 85 | def create_enclosing_box_mapper(box_size: float) -> vtk.vtkPolyDataMapper: 86 | """ 87 | Create a mapper for an enclosing box. 88 | 89 | Args: 90 | box_size (float): Size of the box. 91 | 92 | Returns: 93 | vtkPolyDataMapper: A mapper for the enclosing box. 94 | """ 95 | box = vtk.vtkCubeSource() 96 | box.SetXLength(box_size) 97 | box.SetYLength(box_size) 98 | box.SetZLength(box_size) 99 | box.Update() 100 | 101 | outline = vtk.vtkOutlineFilter() 102 | outline.SetInputConnection(box.GetOutputPort()) 103 | 104 | mapper = vtk.vtkPolyDataMapper() 105 | mapper.SetInputConnection(outline.GetOutputPort()) 106 | return mapper 107 | 108 | 109 | if __name__ == "__main__": 110 | n_spheres = 50 111 | box_size = 5.0 112 | 113 | spheres_mapper = create_random_spheres_mapper(n_spheres, box_size) 114 | box_mapper = create_enclosing_box_mapper(box_size) 115 | 116 | pipeline = VisualisationPipeline(mappers=[spheres_mapper, box_mapper]) 117 | pipeline.run() 118 | -------------------------------------------------------------------------------- /src/02_advanced_shapes/isosurface.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module demonstrates the process of creating and visualizing a 3D scalar dataset using the Visualization Toolkit (VTK) and NumPy. It is structured into several key functions, each performing a distinct step in the visualization workflow. 3 | 4 | Workflow: 5 | 1. Creation of Sample Data (`create_sample_data`): 6 | - Generates a 3D scalar dataset based on a mathematical function. 7 | - Utilizes NumPy for efficient computation of scalar values within the dataset. 8 | - The dataset is represented as VTK's vtkImageData, which stores the 3D scalar values. 9 | 10 | 2. Isosurface Creation (`create_isosurface`): 11 | - Generates an isosurface from the vtkImageData. 12 | - An isosurface represents a 3D surface that connects points of equal scalar value (isovalue). 13 | - This function takes a range of isovalues and creates corresponding contours in the dataset. 14 | 15 | 3. Color Mapping (`apply_color_map`): 16 | - Applies a color map to the isosurface actor. 17 | - The color mapping is based on the scalar values, enhancing the visualization of the isosurface. 18 | - This step involves creating a vtkColorTransferFunction that maps scalar values to specific colors. 19 | 20 | 4. Visualization (`visualize_actor`): 21 | - Sets up a VTK renderer, render window, and interactor to display the isosurface. 22 | - The isosurface actor, created and colored in previous steps, is added to the VTK renderer for visualization. 23 | - The background color and other rendering settings are configured for optimal display. 24 | """ 25 | 26 | from typing import List, Tuple 27 | 28 | import numpy as np 29 | import vtk 30 | 31 | # Constants 32 | BACKGROUND_COLOR = (0.1, 0.2, 0.3) # Background color for the visualization 33 | 34 | 35 | def create_sample_data(dimensions: Tuple[int, int, int]) -> vtk.vtkImageData: 36 | """ 37 | Create a sample 3D scalar dataset using a mathematical function. 38 | 39 | Args: 40 | dimensions (Tuple[int, int, int]): Dimensions of the dataset (x, y, z). 41 | 42 | Returns: 43 | vtk.vtkImageData: The created 3D scalar dataset. 44 | """ 45 | if not all(d > 0 for d in dimensions): 46 | raise ValueError("Dimensions must be positive integers") 47 | 48 | # Create an empty image data object 49 | imageData = vtk.vtkImageData() 50 | imageData.SetDimensions(dimensions) 51 | imageData.SetSpacing(1.0, 1.0, 1.0) 52 | imageData.SetOrigin(0, 0, 0) 53 | 54 | # Efficiently fill the image data with scalar values using NumPy 55 | x, y, z = np.indices(dimensions) 56 | values = np.sin(np.sqrt(x**2 + y**2 + z**2)).ravel() 57 | 58 | # Convert numpy array to VTK array 59 | scalars = vtk.vtkFloatArray() 60 | scalars.SetNumberOfValues(len(values)) 61 | scalars.SetVoidArray(values, len(values), 1) 62 | 63 | imageData.GetPointData().SetScalars(scalars) 64 | return imageData 65 | 66 | 67 | def create_isosurface( 68 | data: vtk.vtkImageData, isovalue_range: List[float] 69 | ) -> vtk.vtkActor: 70 | """ 71 | Create an isosurface with a range of isovalues from the given data. 72 | 73 | Args: 74 | data (vtk.vtkImageData): The input dataset. 75 | isovalue_range (List[float]): Range of isovalues. 76 | 77 | Returns: 78 | vtk.vtkActor: The actor representing the isosurface. 79 | """ 80 | # Generate an isosurface 81 | contour = vtk.vtkContourFilter() 82 | contour.SetInputData(data) 83 | contour.GenerateValues(len(isovalue_range), isovalue_range[0], isovalue_range[-1]) 84 | 85 | # Map the contours to graphical primitives 86 | mapper = vtk.vtkPolyDataMapper() 87 | mapper.SetInputConnection(contour.GetOutputPort()) 88 | mapper.SetScalarRange(isovalue_range[0], isovalue_range[-1]) 89 | 90 | # Create an actor for the contours 91 | actor = vtk.vtkActor() 92 | actor.SetMapper(mapper) 93 | 94 | return actor 95 | 96 | 97 | def apply_color_map(actor: vtk.vtkActor) -> None: 98 | """ 99 | Apply a color map to the actor. 100 | 101 | Args: 102 | actor (vtk.vtkActor): The actor to apply the color map to. 103 | """ 104 | # Create a color transfer function 105 | colorTransferFunction = vtk.vtkColorTransferFunction() 106 | colorTransferFunction.AddRGBPoint(-1.0, 0, 0, 1) # Blue for low values 107 | colorTransferFunction.AddRGBPoint(0, 0, 1, 0) # Green for mid values 108 | colorTransferFunction.AddRGBPoint(1.0, 1, 0, 0) # Red for high values 109 | 110 | # Apply the color transfer function to the actor 111 | actor.GetMapper().SetLookupTable(colorTransferFunction) 112 | 113 | 114 | def visualize_actor(actor: vtk.vtkActor) -> None: 115 | """ 116 | Visualize the given actor in a render window. 117 | 118 | Args: 119 | actor (vtk.vtkActor): The actor to visualize. 120 | """ 121 | # Create a renderer and render window 122 | renderer = vtk.vtkRenderer() 123 | renderWindow = vtk.vtkRenderWindow() 124 | renderWindow.AddRenderer(renderer) 125 | 126 | # Create a render window interactor 127 | renderWindowInteractor = vtk.vtkRenderWindowInteractor() 128 | renderWindowInteractor.SetRenderWindow(renderWindow) 129 | 130 | # Add the actor to the scene 131 | renderer.AddActor(actor) 132 | renderer.SetBackground(*BACKGROUND_COLOR) 133 | 134 | # Start the visualization 135 | renderWindow.Render() 136 | renderWindowInteractor.Start() 137 | 138 | 139 | # Main script 140 | if __name__ == "__main__": 141 | try: 142 | data = create_sample_data((50, 50, 50)) 143 | iso_actor = create_isosurface( 144 | data, np.linspace(-1, 1, 10).tolist() 145 | ) # Isovalue range 146 | apply_color_map(iso_actor) 147 | visualize_actor(iso_actor) 148 | except Exception as e: 149 | print(f"Error: {e}") 150 | -------------------------------------------------------------------------------- /src/02_advanced_shapes/multiple_dependent_objects.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | 4 | def create_cube_mapper(center: tuple, length: float) -> vtk.vtkPolyDataMapper: 5 | cube_source = vtk.vtkCubeSource() 6 | cube_source.SetCenter(center) 7 | cube_source.SetXLength(length) 8 | cube_source.SetYLength(length) 9 | cube_source.SetZLength(length) 10 | 11 | cube_mapper = vtk.vtkPolyDataMapper() 12 | cube_mapper.SetInputConnection(cube_source.GetOutputPort()) 13 | 14 | return cube_mapper 15 | 16 | 17 | def create_cone_mapper( 18 | center: tuple, height: float, radius: float, resolution: int = 30 19 | ) -> vtk.vtkPolyDataMapper: 20 | cone_source = vtk.vtkConeSource() 21 | cone_source.SetCenter(center) 22 | cone_source.SetHeight(height) 23 | cone_source.SetRadius(radius) 24 | cone_source.SetResolution(resolution) 25 | 26 | cone_mapper = vtk.vtkPolyDataMapper() 27 | cone_mapper.SetInputConnection(cone_source.GetOutputPort()) 28 | 29 | return cone_mapper 30 | 31 | 32 | if __name__ == "__main__": 33 | cube_mapper = create_cube_mapper(center=(0, 0, 0), length=1.0) 34 | cone_mapper = create_cone_mapper(center=(0, 1.5, 0), height=1.5, radius=0.5) 35 | 36 | cube_actor = vtk.vtkActor() 37 | cube_actor.SetMapper(cube_mapper) 38 | 39 | cone_actor = vtk.vtkActor() 40 | cone_actor.SetMapper(cone_mapper) 41 | 42 | assembly = vtk.vtkAssembly() 43 | assembly.AddPart(cube_actor) 44 | assembly.AddPart(cone_actor) 45 | 46 | renderer = vtk.vtkRenderer() 47 | renderer.AddActor(assembly) 48 | renderer.SetBackground(0, 0, 0) 49 | 50 | window = vtk.vtkRenderWindow() 51 | window.AddRenderer(renderer) 52 | window.SetSize(800, 600) 53 | 54 | interactor = vtk.vtkRenderWindowInteractor() 55 | interactor.SetRenderWindow(window) 56 | interactor.Initialize() 57 | 58 | interactor.Start() 59 | -------------------------------------------------------------------------------- /src/02_advanced_shapes/multiple_independent_objects.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import vtk 4 | from vtkmodules.util.numpy_support import vtk_to_numpy 5 | 6 | 7 | def create_cone(height: float, radius: float, resolution: int) -> vtk.vtkConeSource: 8 | cone = vtk.vtkConeSource() 9 | cone.SetHeight(height) 10 | cone.SetRadius(radius) 11 | cone.SetResolution(resolution) 12 | return cone 13 | 14 | 15 | def create_cube(length: float) -> vtk.vtkCubeSource: 16 | cube = vtk.vtkCubeSource() 17 | cube.SetXLength(length) 18 | cube.SetYLength(length) 19 | cube.SetZLength(length) 20 | return cube 21 | 22 | 23 | def create_sphere( 24 | radius: float, phi_resolution: int, theta_resolution: int 25 | ) -> vtk.vtkSphereSource: 26 | sphere = vtk.vtkSphereSource() 27 | sphere.SetRadius(radius) 28 | sphere.SetPhiResolution(phi_resolution) 29 | sphere.SetThetaResolution(theta_resolution) 30 | return sphere 31 | 32 | 33 | if __name__ == "__main__": 34 | # define sources 35 | cone = create_cone(height=5.0, radius=2.0, resolution=10) 36 | cube = create_cube(length=5.0) 37 | sphere = create_sphere(radius=3.0, phi_resolution=10, theta_resolution=10) 38 | 39 | sources = (cone, cube, sphere) 40 | 41 | mappers = [] 42 | for source in sources: 43 | mapper = vtk.vtkPolyDataMapper() 44 | mapper.SetInputConnection(source.GetOutputPort()) 45 | mappers.append(mapper) 46 | 47 | actors = [] 48 | for mapper in mappers: 49 | actor = vtk.vtkActor() 50 | actor.SetMapper(mapper) 51 | actors.append(actor) 52 | 53 | renderers = [] 54 | for i, actor in enumerate(actors): 55 | renderer = vtk.vtkRenderer() 56 | renderer.AddActor(actor) 57 | renderer.SetBackground(random.random(), random.random(), random.random()) 58 | renderer.SetViewport( 59 | 0 + i * 1 / len(actors), 0.0, (i + 1) * 1 / len(actors), 1.0 60 | ) # x, y, width, height 61 | renderers.append(renderer) 62 | 63 | renderWindow = vtk.vtkRenderWindow() 64 | renderWindow.SetSize(800, 400) 65 | 66 | for renderer in renderers: 67 | renderWindow.AddRenderer(renderer) 68 | 69 | interactor = vtk.vtkRenderWindowInteractor() 70 | interactor.SetRenderWindow(renderWindow) 71 | interactor.Initialize() 72 | interactor.Start() 73 | -------------------------------------------------------------------------------- /src/02_advanced_shapes/streamlines.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module demonstrates the visualization of a dipole field in a three-dimensional space using the Visualization Toolkit (VTK). A dipole field is a vector field that is typically created by two equal but opposite charges separated by a distance. 3 | 4 | Workflow: 5 | 1. Generate a structured grid of points in a 3D space. 6 | 2. Calculate the dipole field vectors at each point in the grid. 7 | 3. Combine these points and vectors into a vtkStructuredGrid object. 8 | 4. Create seed points for streamline initiation. 9 | 5. Generate streamlines representing the flow lines of the dipole field using vtkStreamTracer. 10 | 6. Visualize these streamlines using vtkPolyDataMapper, vtkActor, and vtkRenderer. 11 | 12 | Mathematics: 13 | - The dipole field at a point in space is calculated using the formula for the electric field due to point charges. The field due to each charge is \vec{E} = \frac{q \vec{r}}{4 \pi \epsilon_0 r^3}, where \vec{r} is the position vector relative to the charge, q is the charge magnitude, and \epsilon_0 is the vacuum permittivity. 14 | - The net field at any point is the vector sum of the fields due to both charges. 15 | - Streamlines are generated using vtkStreamTracer, which integrates the vector field to trace the paths of particles in the flow. 16 | """ 17 | 18 | import numpy as np 19 | import vtk 20 | 21 | 22 | class DipoleFieldVisualization: 23 | def __init__(self, num_seed_points=30): 24 | self.num_seed_points = num_seed_points 25 | self.grid = self.create_structured_grid() 26 | self.seeds = self.create_seeds() 27 | self.streamer = self.create_streamlines() 28 | 29 | def create_structured_grid(self): 30 | points, vectors = self.generate_points_and_vectors() 31 | grid = vtk.vtkStructuredGrid() 32 | grid.SetDimensions(21, 21, 21) 33 | grid.SetPoints(points) 34 | grid.GetPointData().SetVectors(vectors) 35 | return grid 36 | 37 | def generate_points_and_vectors(self): 38 | points = vtk.vtkPoints() 39 | vectors = vtk.vtkDoubleArray() 40 | vectors.SetNumberOfComponents(3) 41 | 42 | for i in np.linspace(-10, 10, 21): 43 | for j in np.linspace(-10, 10, 21): 44 | for k in np.linspace(-10, 10, 21): 45 | points.InsertNextPoint(i, j, k) 46 | x, y, z = i, j, k 47 | r1 = np.sqrt((x - 1) ** 2 + y**2 + z**2) + 1e-2 48 | r2 = np.sqrt((x + 1) ** 2 + y**2 + z**2) + 1e-2 49 | vectors.InsertNextTuple3( 50 | (x - 1) / r1**3 - (x + 1) / r2**3, 51 | y / r1**3 - y / r2**3, 52 | z / r1**3 - z / r2**3, 53 | ) 54 | 55 | return points, vectors 56 | 57 | def create_seeds(self): 58 | seeds = vtk.vtkPointSource() 59 | seeds.SetCenter(0, 0, 0) 60 | seeds.SetRadius(10) 61 | seeds.SetNumberOfPoints(self.num_seed_points) 62 | return seeds 63 | 64 | def create_streamlines(self): 65 | streamer = vtk.vtkStreamTracer() 66 | streamer.SetInputData(self.grid) 67 | streamer.SetSourceConnection(self.seeds.GetOutputPort()) 68 | streamer.SetMaximumPropagation(500) 69 | streamer.SetIntegrationStepUnit(vtk.vtkStreamTracer.LENGTH_UNIT) 70 | streamer.SetInitialIntegrationStep(0.1) 71 | streamer.SetIntegrationDirectionToBoth() 72 | streamer.SetComputeVorticity(False) 73 | return streamer 74 | 75 | def visualize(self): 76 | mapper = vtk.vtkPolyDataMapper() 77 | mapper.SetInputConnection(self.streamer.GetOutputPort()) 78 | actor = vtk.vtkActor() 79 | actor.SetMapper(mapper) 80 | 81 | renderer = vtk.vtkRenderer() 82 | renderer.AddActor(actor) 83 | renderer.SetBackground(0, 0, 0) 84 | 85 | render_window = vtk.vtkRenderWindow() 86 | render_window.AddRenderer(renderer) 87 | 88 | interactor = vtk.vtkRenderWindowInteractor() 89 | interactor.SetRenderWindow(render_window) 90 | interactor.Initialize() 91 | interactor.Start() 92 | 93 | 94 | if __name__ == "__main__": 95 | visualization = DipoleFieldVisualization() 96 | visualization.visualize() 97 | -------------------------------------------------------------------------------- /src/02_advanced_shapes/triangulation.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module demonstrates the process of 3D triangulation and its visualization using the Visualization Toolkit (VTK). Triangulation is a fundamental operation in computational geometry, where a surface or volume is divided into simpler units, specifically triangles in 2D or tetrahedrons in 3D. These simple shapes facilitate easier rendering and enable complex geometrical shapes to be approximated with high accuracy. 3 | 4 | Workflow: 5 | 1. Generate a set of random points in 3D space. 6 | 2. Use the vtkDelaunay3D filter to perform Delaunay triangulation on these points. 7 | 3. Convert the output vtkUnstructuredGrid to vtkPolyData using vtkGeometryFilter. 8 | 4. Pass this vtkPolyData to vtkTriangleFilter to process and prepare it for visualization. 9 | 5. Create a vtkPolyDataMapper and vtkActor to render the triangulated geometry. 10 | 6. Set up a VTK renderer, render window, and interactor to display the result. 11 | 12 | Mathematics: 13 | - Delaunay Triangulation: For a given set of points in a space (R^3), Delaunay triangulation generates a mesh of tetrahedra such that no point is inside the circum-hypersphere of any tetrahedra. It maximizes the minimum angle of all the angles of the triangles in the triangulation, helping avoid skinny triangles. 14 | - 3D Space Representation: Points are randomly generated in a 3D space, each defined by (x, y, z) coordinates. 15 | - vtkDelaunay3D: This VTK filter computes the Delaunay triangulation in 3D. It outputs a vtkUnstructuredGrid representing the tetrahedral mesh. 16 | - vtkGeometryFilter: Converts the vtkUnstructuredGrid (tetrahedral mesh) to vtkPolyData, which is a suitable format for further processing and rendering. 17 | - vtkTriangleFilter: Processes the vtkPolyData to ensure that the geometry is represented purely with triangles, a requirement for many rendering and processing operations. 18 | 19 | """ 20 | 21 | import random 22 | 23 | import vtk 24 | 25 | 26 | class Triangulation3D: 27 | def __init__(self, num_points=25): 28 | self.num_points = num_points 29 | self.points = vtk.vtkPoints() 30 | self.generate_random_points() 31 | self.triangulate() 32 | 33 | def generate_random_points(self): 34 | for _ in range(self.num_points): 35 | x, y, z = ( 36 | random.uniform(-1, 1), 37 | random.uniform(-1, 1), 38 | random.uniform(-1, 1), 39 | ) 40 | self.points.InsertNextPoint(x, y, z) 41 | 42 | def triangulate(self): 43 | input_polydata = vtk.vtkPolyData() 44 | input_polydata.SetPoints(self.points) 45 | 46 | delaunay = vtk.vtkDelaunay3D() 47 | delaunay.SetInputData(input_polydata) 48 | delaunay.Update() 49 | 50 | # Convert vtkUnstructuredGrid to vtkPolyData 51 | geometry_filter = vtk.vtkGeometryFilter() 52 | geometry_filter.SetInputConnection(delaunay.GetOutputPort()) 53 | geometry_filter.Update() 54 | 55 | self.triangle_filter = vtk.vtkTriangleFilter() 56 | self.triangle_filter.SetInputConnection(geometry_filter.GetOutputPort()) 57 | self.triangle_filter.PassLinesOn() 58 | self.triangle_filter.PassVertsOn() 59 | self.triangle_filter.Update() 60 | 61 | def get_actor(self): 62 | mapper = vtk.vtkPolyDataMapper() 63 | mapper.SetInputConnection(self.triangle_filter.GetOutputPort()) 64 | 65 | actor = vtk.vtkActor() 66 | actor.SetMapper(mapper) 67 | actor.GetProperty().SetRepresentationToWireframe() 68 | 69 | return actor 70 | 71 | 72 | def main(): 73 | triangulation = Triangulation3D() 74 | 75 | renderer = vtk.vtkRenderer() 76 | renderer.AddActor(triangulation.get_actor()) 77 | renderer.SetBackground(0, 0, 0) 78 | 79 | render_window = vtk.vtkRenderWindow() 80 | render_window.AddRenderer(renderer) 81 | 82 | interactor = vtk.vtkRenderWindowInteractor() 83 | interactor.SetRenderWindow(render_window) 84 | 85 | interactor.Initialize() 86 | interactor.Start() 87 | 88 | 89 | if __name__ == "__main__": 90 | main() 91 | -------------------------------------------------------------------------------- /src/02_advanced_shapes/visualization_techniques_comparison.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import vtk 4 | 5 | 6 | def create_render_window(): 7 | render_window = vtk.vtkRenderWindow() 8 | render_window.SetSize(800, 600) 9 | interactor = vtk.vtkRenderWindowInteractor() 10 | interactor.SetRenderWindow(render_window) 11 | return render_window, interactor 12 | 13 | 14 | def create_data_source(): 15 | volume_source = vtk.vtkRTAnalyticSource() 16 | 17 | vector_source = vtk.vtkPointSource() 18 | vector_source.SetNumberOfPoints(10) 19 | vector_source.Update() 20 | 21 | vectors = vtk.vtkFloatArray() 22 | vectors.SetNumberOfComponents(3) 23 | vectors.SetNumberOfTuples(vector_source.GetOutput().GetNumberOfPoints()) 24 | 25 | for i in range(vectors.GetNumberOfTuples()): 26 | vectors.SetTuple3(i, 1, 2, 3) 27 | 28 | vector_source.GetOutput().GetPointData().SetVectors(vectors) 29 | return volume_source, vector_source 30 | 31 | 32 | def create_structured_grid(): 33 | grid_dimensions = [10, 10, 10] 34 | 35 | structured_grid = vtk.vtkStructuredGrid() 36 | structured_grid.SetDimensions(grid_dimensions) 37 | 38 | points = vtk.vtkPoints() 39 | 40 | for z in range(grid_dimensions[2]): 41 | for y in range(grid_dimensions[1]): 42 | for x in range(grid_dimensions[0]): 43 | points.InsertNextPoint(x, y, z) 44 | 45 | structured_grid.SetPoints(points) 46 | return structured_grid 47 | 48 | 49 | def create_point_source(): 50 | point_source = vtk.vtkPointSource() 51 | point_source.SetNumberOfPoints(50) 52 | point_source.SetRadius(3) 53 | point_source.Update() 54 | return point_source 55 | 56 | 57 | def create_visualizations( 58 | render_window, 59 | xmins, 60 | ymins, 61 | xmaxs, 62 | ymaxs, 63 | volume_source, 64 | structured_grid, 65 | point_source, 66 | vector_source, 67 | ): 68 | for i in range(4): 69 | renderer = vtk.vtkRenderer() 70 | render_window.AddRenderer(renderer) 71 | renderer.SetViewport(xmins[i], ymins[i], xmaxs[i], ymaxs[i]) 72 | 73 | if i == 0: # Volume rendering 74 | create_volume_rendering(renderer, volume_source) 75 | elif i == 1: # Streamlines 76 | create_streamlines(renderer, structured_grid, point_source) 77 | elif i == 2: # Glyphs 78 | create_glyphs(renderer, vector_source) 79 | elif i == 3: # Contouring 80 | create_contouring(renderer, volume_source) 81 | 82 | 83 | def create_volume_rendering(renderer, volume_source): 84 | volume_mapper = vtk.vtkSmartVolumeMapper() 85 | volume_mapper.SetInputConnection(volume_source.GetOutputPort()) 86 | volume = vtk.vtkVolume() 87 | volume.SetMapper(volume_mapper) 88 | renderer.AddVolume(volume) 89 | 90 | # Add text annotation 91 | text_actor = vtk.vtkTextActor() 92 | text_actor.SetInput("Volume Rendering") 93 | text_actor.GetTextProperty().SetFontSize(24) 94 | text_actor.GetTextProperty().SetColor(1, 1, 1) # White text 95 | renderer.AddActor2D(text_actor) 96 | 97 | 98 | def create_streamlines(renderer, structured_grid, point_source): 99 | vector_data_array = vtk.vtkDoubleArray() 100 | vector_data_array.SetNumberOfComponents(3) 101 | vector_data_array.SetNumberOfTuples(structured_grid.GetNumberOfPoints()) 102 | 103 | for j in range(structured_grid.GetNumberOfPoints()): 104 | vector_data_array.SetTuple3( 105 | j, random.random(), random.random(), random.random() 106 | ) 107 | 108 | vector_data_array.SetName("VectorField") 109 | structured_grid.GetPointData().SetVectors(vector_data_array) 110 | 111 | stream_tracer = vtk.vtkStreamTracer() 112 | stream_tracer.SetInputData(structured_grid) 113 | stream_tracer.SetSourceConnection(point_source.GetOutputPort()) 114 | stream_tracer.SetMaximumPropagation(500) 115 | stream_tracer.SetInitialIntegrationStep(0.1) 116 | stream_tracer.SetIntegratorType(2) 117 | 118 | tube_filter = vtk.vtkTubeFilter() 119 | tube_filter.SetInputConnection(stream_tracer.GetOutputPort()) 120 | tube_filter.SetRadius(0.1) 121 | tube_filter.SetNumberOfSides(6) 122 | 123 | streamline_mapper = vtk.vtkPolyDataMapper() 124 | streamline_mapper.SetInputConnection(tube_filter.GetOutputPort()) 125 | streamline_actor = vtk.vtkActor() 126 | streamline_actor.SetMapper(streamline_mapper) 127 | 128 | renderer.AddActor(streamline_actor) 129 | 130 | # Add text annotation 131 | text_actor = vtk.vtkTextActor() 132 | text_actor.SetInput("Streamlines") 133 | text_actor.GetTextProperty().SetFontSize(24) 134 | text_actor.GetTextProperty().SetColor(1, 1, 1) # White text 135 | renderer.AddActor2D(text_actor) 136 | 137 | 138 | def create_glyphs(renderer, vector_source): 139 | # Create a glyph source and mapper 140 | glyph_source = vtk.vtkArrowSource() 141 | glyph3D = vtk.vtkGlyph3D() 142 | glyph3D.SetSourceConnection(glyph_source.GetOutputPort()) 143 | glyph3D.SetInputConnection(vector_source.GetOutputPort()) 144 | glyph3D.SetVectorModeToUseVector() 145 | glyph3D.SetScaleModeToScaleByVector() 146 | glyph3D.SetScaleFactor(0.1) 147 | glyph_mapper = vtk.vtkPolyDataMapper() 148 | glyph_mapper.SetInputConnection(glyph3D.GetOutputPort()) 149 | # Create an actor 150 | glyph_actor = vtk.vtkActor() 151 | glyph_actor.SetMapper(glyph_mapper) 152 | renderer.AddActor(glyph_actor) 153 | 154 | # Add text annotation 155 | text_actor = vtk.vtkTextActor() 156 | text_actor.SetInput("Glyphs") 157 | text_actor.GetTextProperty().SetFontSize(24) 158 | text_actor.GetTextProperty().SetColor(1, 1, 1) # White text 159 | renderer.AddActor2D(text_actor) 160 | 161 | 162 | def create_contouring(renderer, volume_source): 163 | contour_filter = vtk.vtkContourFilter() 164 | contour_filter.SetInputConnection(volume_source.GetOutputPort()) 165 | contour_filter.SetValue(0, 150) 166 | 167 | contour_mapper = vtk.vtkPolyDataMapper() 168 | contour_mapper.SetInputConnection(contour_filter.GetOutputPort()) 169 | 170 | contour_actor = vtk.vtkActor() 171 | contour_actor.SetMapper(contour_mapper) 172 | renderer.AddActor(contour_actor) 173 | 174 | # Add text annotation 175 | text_actor = vtk.vtkTextActor() 176 | text_actor.SetInput("Contouring") 177 | text_actor.GetTextProperty().SetFontSize(24) 178 | text_actor.GetTextProperty().SetColor(1, 1, 1) # White text 179 | renderer.AddActor2D(text_actor) 180 | 181 | 182 | def main(): 183 | xmins = [0, 0.5, 0, 0.5] 184 | xmaxs = [0.5, 1, 0.5, 1] 185 | ymins = [0, 0, 0.5, 0.5] 186 | ymaxs = [0.5, 0.5, 1, 1] 187 | 188 | render_window, interactor = create_render_window() 189 | volume_source, vector_source = create_data_source() 190 | structured_grid = create_structured_grid() 191 | point_source = create_point_source() 192 | 193 | create_visualizations( 194 | render_window, 195 | xmins, 196 | ymins, 197 | xmaxs, 198 | ymaxs, 199 | volume_source, 200 | structured_grid, 201 | point_source, 202 | vector_source, 203 | ) 204 | 205 | interactor.Initialize() 206 | interactor.Start() 207 | 208 | 209 | if __name__ == "__main__": 210 | main() 211 | -------------------------------------------------------------------------------- /src/02_advanced_shapes/volume_rendering.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module demonstrates volume rendering in three-dimensional space using the Visualization Toolkit (VTK). Volume rendering is a technique used to display a 3D volume of data, typically visualizing scalar fields within a given space. 3 | 4 | Workflow: 5 | 1. Generate synthetic volume data as a 3D grid of scalars (voxels). 6 | 2. Define opacity and color transfer functions to map scalar values to opacity and color. 7 | 3. Combine these transfer functions into volume properties. 8 | 4. Set up a volume mapper to map the 3D volume data to 2D screen space. 9 | 5. Create a volume actor to position and orient the volume in the scene. 10 | 6. Initialize a renderer, render window, and interactor to display the volume. 11 | 12 | Mathematics: 13 | - Scalar Field: The module creates a synthetic scalar field where each voxel's scalar value is determined by its coordinates (x, y, z). 14 | - Opacity Transfer Function: This function maps scalar values to opacity levels, controlling how transparent or opaque each voxel appears. Typically, lower scalar values are more transparent, and higher values are more opaque. 15 | - Color Transfer Function: Similar to opacity, this function maps scalar values to colors, allowing for visual differentiation based on the scalar value. 16 | - Volume Rendering: The process involves casting rays through the volume data and accumulating color and opacity along the way based on the transfer functions. The final image is a composite of these contributions, creating a 3D representation of the scalar field. 17 | """ 18 | 19 | import vtk 20 | 21 | 22 | class VolumeRenderer: 23 | def __init__(self): 24 | self.volume_data = self.create_volume_data() 25 | self.opacity_transfer_function = self.create_opacity_transfer_function() 26 | self.color_transfer_function = self.create_color_transfer_function() 27 | self.volume_properties = self.create_volume_properties() 28 | self.volume_mapper = self.create_volume_mapper() 29 | self.volume_actor = self.create_volume_actor() 30 | 31 | def create_volume_data(self): 32 | volume_data = vtk.vtkImageData() 33 | volume_data.SetDimensions(50, 50, 50) 34 | volume_data.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 1) 35 | 36 | for z in range(50): 37 | for y in range(50): 38 | for x in range(50): 39 | scalar_value = x + y + z 40 | volume_data.SetScalarComponentFromDouble(x, y, z, 0, scalar_value) 41 | return volume_data 42 | 43 | def create_opacity_transfer_function(self): 44 | opacity_tf = vtk.vtkPiecewiseFunction() 45 | opacity_tf.AddPoint(0, 0.0) 46 | opacity_tf.AddPoint(255, 1.0) 47 | return opacity_tf 48 | 49 | def create_color_transfer_function(self): 50 | color_tf = vtk.vtkColorTransferFunction() 51 | color_tf.AddRGBPoint(0.0, 0.0, 0.0, 1.0) 52 | color_tf.AddRGBPoint(255.0, 1.0, 0.0, 0.0) 53 | return color_tf 54 | 55 | def create_volume_properties(self): 56 | volume_properties = vtk.vtkVolumeProperty() 57 | volume_properties.SetColor(self.color_transfer_function) 58 | volume_properties.SetScalarOpacity(self.opacity_transfer_function) 59 | volume_properties.ShadeOn() 60 | return volume_properties 61 | 62 | def create_volume_mapper(self): 63 | volume_mapper = vtk.vtkSmartVolumeMapper() 64 | volume_mapper.SetInputData(self.volume_data) 65 | return volume_mapper 66 | 67 | def create_volume_actor(self): 68 | volume_actor = vtk.vtkVolume() 69 | volume_actor.SetMapper(self.volume_mapper) 70 | volume_actor.SetProperty(self.volume_properties) 71 | return volume_actor 72 | 73 | def render(self): 74 | renderer = vtk.vtkRenderer() 75 | render_window = vtk.vtkRenderWindow() 76 | render_window_interactor = vtk.vtkRenderWindowInteractor() 77 | 78 | render_window.AddRenderer(renderer) 79 | render_window_interactor.SetRenderWindow(render_window) 80 | 81 | renderer.AddVolume(self.volume_actor) 82 | 83 | render_window_interactor.Initialize() 84 | render_window.Render() 85 | render_window.SetWindowName("Volume Rendering - Cube") 86 | render_window_interactor.Start() 87 | 88 | 89 | if __name__ == "__main__": 90 | volume_renderer = VolumeRenderer() 91 | volume_renderer.render() 92 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/03_structures_and_datasets/__init__.py -------------------------------------------------------------------------------- /src/03_structures_and_datasets/ahmed_body_visualization.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import numpy as np 3 | 4 | 5 | # Load the STL file into VTK 6 | def load_stl_geometry(file_path): 7 | reader = vtk.vtkSTLReader() 8 | reader.SetFileName(file_path) 9 | reader.Update() 10 | return reader.GetOutput() 11 | 12 | 13 | # Apply scalar values to the geometry 14 | def apply_scalar_values(geometry): 15 | scalar_values = vtk.vtkDoubleArray() 16 | scalar_values.SetName("StaticPressure") 17 | scalar_values.SetNumberOfComponents(1) 18 | 19 | num_points = geometry.GetNumberOfPoints() 20 | for i in range(num_points): 21 | scalar_value = np.sin(i / num_points * np.pi * 2) * 300 # Example values 22 | scalar_values.InsertNextValue(scalar_value) 23 | 24 | geometry.GetPointData().SetScalars(scalar_values) 25 | 26 | 27 | # Create a color legend bar 28 | def create_color_legend(mapper): 29 | scalar_bar = vtk.vtkScalarBarActor() 30 | scalar_bar.SetLookupTable(mapper.GetLookupTable()) 31 | scalar_bar.SetTitle("Static Pressure") 32 | scalar_bar.GetLabelTextProperty().SetColor(0, 0, 0) 33 | scalar_bar.GetTitleTextProperty().SetColor(0, 0, 0) 34 | scalar_bar.SetNumberOfLabels(5) 35 | return scalar_bar 36 | 37 | 38 | # Visualize the geometry with scalar values 39 | def visualize_geometry(geometry): 40 | mapper = vtk.vtkPolyDataMapper() 41 | mapper.SetInputData(geometry) 42 | mapper.SetScalarRange(-300, 300) 43 | mapper.SetScalarModeToUsePointData() 44 | 45 | actor = vtk.vtkActor() 46 | actor.SetMapper(mapper) 47 | 48 | renderer = vtk.vtkRenderer() 49 | renderer.AddActor(actor) 50 | renderer.SetBackground(1, 1, 1) 51 | 52 | # Create and add the color legend bar 53 | scalar_bar = create_color_legend(mapper) 54 | renderer.AddActor2D(scalar_bar) 55 | 56 | render_window = vtk.vtkRenderWindow() 57 | render_window.AddRenderer(renderer) 58 | render_window.SetSize(800, 600) 59 | 60 | render_window_interactor = vtk.vtkRenderWindowInteractor() 61 | render_window_interactor.SetRenderWindow(render_window) 62 | 63 | # Set up the title and labels 64 | title = vtk.vtkTextActor() 65 | title.SetInput("Ahmed Body CFD Simulation") 66 | title.GetTextProperty().SetFontSize(24) 67 | title.GetTextProperty().SetColor(0, 0, 0) 68 | title.SetPosition2(10, 570) 69 | renderer.AddActor2D(title) 70 | 71 | x_label = vtk.vtkTextActor() 72 | x_label.SetInput("X-Axis") 73 | x_label.GetTextProperty().SetFontSize(14) 74 | x_label.GetTextProperty().SetColor(0, 0, 0) 75 | x_label.SetPosition2(700, 30) 76 | renderer.AddActor2D(x_label) 77 | 78 | y_label = vtk.vtkTextActor() 79 | y_label.SetInput("Y-Axis") 80 | y_label.GetTextProperty().SetFontSize(14) 81 | y_label.GetTextProperty().SetColor(0, 0, 0) 82 | y_label.SetPosition2(30, 550) 83 | renderer.AddActor2D(y_label) 84 | 85 | render_window.Render() 86 | render_window_interactor.Start() 87 | 88 | 89 | # Main function to download, load, and visualize the Ahmed body 90 | def main(): 91 | save_path = "../../data/stls/ahmed_body.stl" 92 | 93 | # Load the STL file 94 | car_geometry = load_stl_geometry(save_path) 95 | 96 | # Apply scalar values to the geometry 97 | apply_scalar_values(car_geometry) 98 | 99 | # Visualize the geometry with scalar values 100 | visualize_geometry(car_geometry) 101 | 102 | 103 | if __name__ == "__main__": 104 | main() 105 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/cells.py: -------------------------------------------------------------------------------- 1 | """ 2 | The cells in VTK represent a topology or a type of connectivity between points. 3 | They do not hold any positional data of their own but refer to points which are separately stored. 4 | They can be of various types: for example, a line (connecting two points), a triangle (connecting three points), 5 | or a tetrahedron (connecting four points). 6 | """ 7 | 8 | import math 9 | 10 | import vtk 11 | 12 | from src.common.simple_pipeline import VisualisationPipeline 13 | 14 | 15 | def create_points_and_cell(cell_type, offset): 16 | points = vtk.vtkPoints() 17 | cell = None 18 | 19 | if cell_type == "triangle": 20 | points.InsertNextPoint(offset, 0, 0) 21 | points.InsertNextPoint(offset + 1, 0, 0) 22 | points.InsertNextPoint(offset + 0.5, 1, 0) 23 | cell = vtk.vtkTriangle() 24 | for i in range(3): 25 | cell.GetPointIds().SetId(i, i) 26 | 27 | elif cell_type == "quad": 28 | points.InsertNextPoint(offset + 2, 0, 0) 29 | points.InsertNextPoint(offset + 3, 0, 0) 30 | points.InsertNextPoint(offset + 3, 1, 0) 31 | points.InsertNextPoint(offset + 2, 1, 0) 32 | cell = vtk.vtkQuad() 33 | for i in range(4): 34 | cell.GetPointIds().SetId(i, i) 35 | 36 | elif cell_type == "line": 37 | points.InsertNextPoint(offset + 2, 0, 0) 38 | points.InsertNextPoint(offset + 7, 0, 0) 39 | cell = vtk.vtkLine() 40 | for i in range(2): 41 | cell.GetPointIds().SetId(i, i) 42 | 43 | elif cell_type == "vertex": 44 | points.InsertNextPoint(offset + 6, 0, 0) 45 | cell = vtk.vtkVertex() 46 | cell.GetPointIds().SetId(0, 0) 47 | 48 | elif cell_type == "polygon": 49 | for i in range(5): 50 | angle = 2 * math.pi * i / 5 51 | x = math.cos(angle) + offset + 7 52 | y = math.sin(angle) 53 | points.InsertNextPoint(x, y, 0) 54 | cell = vtk.vtkPolygon() 55 | cell.GetPointIds().SetNumberOfIds(5) 56 | for i in range(5): 57 | cell.GetPointIds().SetId(i, i) 58 | 59 | elif cell_type == "tetra": 60 | points.InsertNextPoint(offset + 9, 0, 0) 61 | points.InsertNextPoint(offset + 10, 0, 0) 62 | points.InsertNextPoint(offset + 9.5, 1, 0) 63 | points.InsertNextPoint(offset + 9.75, 0.5, 1) 64 | cell = vtk.vtkTetra() 65 | for i in range(4): 66 | cell.GetPointIds().SetId(i, i) 67 | 68 | return points, cell 69 | 70 | 71 | def main(): 72 | cell_types = ["triangle", "quad", "line", "vertex", "polygon", "tetra"] 73 | offsets = [0, 3, 6, 9, 12, 15] 74 | 75 | all_points = vtk.vtkPoints() 76 | all_cells = vtk.vtkCellArray() 77 | 78 | for cell_type, offset in zip(cell_types, offsets): 79 | points, cell = create_points_and_cell(cell_type, offset) 80 | point_ids = [ 81 | all_points.InsertNextPoint(points.GetPoint(i)) 82 | for i in range(points.GetNumberOfPoints()) 83 | ] 84 | for i, pid in enumerate(point_ids): 85 | cell.GetPointIds().SetId(i, pid) 86 | all_cells.InsertNextCell(cell) 87 | 88 | polydata = vtk.vtkPolyData() 89 | polydata.SetPoints(all_points) 90 | 91 | # Set appropriate data for each cell type 92 | polydata.SetVerts(all_cells) # For vertices 93 | polydata.SetLines(all_cells) # For lines 94 | polydata.SetPolys(all_cells) # For polygons 95 | 96 | mapper = vtk.vtkPolyDataMapper() 97 | mapper.SetInputData(polydata) 98 | 99 | pipeline = VisualisationPipeline(mappers=[mapper]) 100 | pipeline.run() 101 | 102 | 103 | if __name__ == "__main__": 104 | main() 105 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/fields.py: -------------------------------------------------------------------------------- 1 | """ 2 | Fields in VTK can be attached to both points and cells. In this example, I will demonstrate how to attach a scalar field to points and a vector field to cells. We can create a simple situation where we assign random scalar values to points and random vector values to cells. 3 | in VTK, you can store physical properties such as pressure, temperature, or any scalar or vector quantity associated with the points or cells in your dataset. These are often referred to as point data or cell data, respectively. 4 | 5 | Point Data: These are data attributes that are associated with the points of a dataset. For example, in a computational fluid dynamics (CFD) simulation, you might store the velocity vector at each point in the mesh as point data. 6 | 7 | Cell Data: These are data attributes that are associated with the cells of a dataset. For example, you might store the pressure or temperature within each cell of the mesh as cell data. 8 | 9 | Workflow Overview: 10 | 11 | 1. Point Creation (create_points): 12 | - Initializes a set of points in 3D space, laying the groundwork for constructing geometric shapes. 13 | - In this case, points defining the corners of a quad are created. 14 | 15 | 2. Quad Creation (create_quad): 16 | - Utilizes the previously defined points to create a quad cell, a basic polygonal element. 17 | - Demonstrates how cells are constructed from points to form geometric shapes. 18 | 19 | 3. Scalar Field Attachment (attach_scalar_field): 20 | - Attaches a scalar field to the points, assigning a random scalar value to each point. 21 | - This highlights how to associate data with geometric entities in VTK. 22 | 23 | 4. Vector Field Attachment (attach_vector_field): 24 | - Similar to the scalar field, a random vector field is attached to the cells of the polydata. 25 | - Shows the capability of VTK to handle complex data associations, including vectorial data. 26 | 27 | 5. Polydata Assembly (create_polydata): 28 | - Integrates the points and the quad cell into a vtkPolyData object, a versatile format for representing and manipulating geometric data in VTK. 29 | 30 | 6. Visualization Process: 31 | - The vtkPolyDataMapper maps the polydata to graphical primitives for rendering. 32 | - A visualization pipeline, provided by the 'VisualisationPipeline' class, is employed to render the polydata, showcasing the scalar and vector fields attached to it. 33 | """ 34 | 35 | import numpy as np 36 | import vtk 37 | 38 | from src.common.simple_pipeline import VisualisationPipeline 39 | 40 | 41 | def create_points(): 42 | """ 43 | Create a set of points for the polydata. 44 | """ 45 | points = vtk.vtkPoints() 46 | points.InsertNextPoint(0, 0, 0) 47 | points.InsertNextPoint(1, 0, 0) 48 | points.InsertNextPoint(0, 1, 0) 49 | points.InsertNextPoint(1, 1, 0) 50 | return points 51 | 52 | 53 | def create_quad(points): 54 | """ 55 | Create a quad cell using the provided points. 56 | """ 57 | quad = vtk.vtkQuad() 58 | # Assign points to the quad corners 59 | quad.GetPointIds().SetId(0, 0) 60 | quad.GetPointIds().SetId(1, 1) 61 | quad.GetPointIds().SetId(2, 3) 62 | quad.GetPointIds().SetId(3, 2) 63 | return quad 64 | 65 | 66 | def attach_scalar_field(points): 67 | """ 68 | Attach a random scalar field to the points. 69 | """ 70 | scalars = vtk.vtkFloatArray() 71 | scalars.SetName("Scalars") 72 | for i in range(points.GetNumberOfPoints()): 73 | scalars.InsertNextValue(np.random.rand()) 74 | return scalars 75 | 76 | 77 | def attach_vector_field(cells): 78 | """ 79 | Attach a random vector field to the cells. 80 | """ 81 | vectors = vtk.vtkFloatArray() 82 | vectors.SetNumberOfComponents(3) 83 | vectors.SetName("Vectors") 84 | for i in range(cells.GetNumberOfCells()): 85 | vectors.InsertNextTuple3(np.random.rand(), np.random.rand(), np.random.rand()) 86 | return vectors 87 | 88 | 89 | def create_polydata(points, quad): 90 | """ 91 | Create polydata to hold the points and cells. 92 | """ 93 | cells = vtk.vtkCellArray() 94 | cells.InsertNextCell(quad) 95 | 96 | polydata = vtk.vtkPolyData() 97 | polydata.SetPoints(points) 98 | polydata.SetPolys(cells) 99 | return polydata, cells 100 | 101 | 102 | def main(): 103 | points = create_points() 104 | quad = create_quad(points) 105 | polydata, cells = create_polydata(points, quad) 106 | 107 | polydata.GetPointData().SetScalars(attach_scalar_field(points)) 108 | polydata.GetCellData().SetVectors(attach_vector_field(cells)) 109 | 110 | # Visualizing the fields 111 | mapper = vtk.vtkPolyDataMapper() 112 | mapper.SetInputData(polydata) 113 | mapper.SetScalarModeToUsePointData() 114 | mapper.SetColorModeToMapScalars() 115 | mapper.SelectColorArray("Scalars") 116 | 117 | pipeline = VisualisationPipeline(mappers=[mapper]) 118 | pipeline.run() 119 | 120 | 121 | if __name__ == "__main__": 122 | main() 123 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/generate_naca0012.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import numpy as np 3 | 4 | 5 | def naca0012(x): 6 | """Calculate the NACA 0012 airfoil shape.""" 7 | m = 0 8 | p = 0 9 | t = 0.12 10 | c = 1.0 11 | y_t = ( 12 | 5 13 | * t 14 | * c 15 | * ( 16 | 0.2969 * np.sqrt(x / c) 17 | - 0.1260 * (x / c) 18 | - 0.3516 * (x / c) ** 2 19 | + 0.2843 * (x / c) ** 3 20 | - 0.1015 * (x / c) ** 4 21 | ) 22 | ) 23 | return y_t 24 | 25 | 26 | # Generate airfoil points 27 | x_coords = np.linspace(0, 1, 100) 28 | y_coords = naca0012(x_coords) 29 | 30 | # Create VTK points 31 | points = vtk.vtkPoints() 32 | for x, y in zip(x_coords, y_coords): 33 | points.InsertNextPoint(x, y, 0) 34 | 35 | # Create a polygon 36 | polygon = vtk.vtkPolygon() 37 | polygon.GetPointIds().SetNumberOfIds(len(x_coords)) 38 | for i in range(len(x_coords)): 39 | polygon.GetPointIds().SetId(i, i) 40 | 41 | # Create a cell array to store the polygon 42 | polygons = vtk.vtkCellArray() 43 | polygons.InsertNextCell(polygon) 44 | 45 | # Create a polydata object 46 | polydata = vtk.vtkPolyData() 47 | polydata.SetPoints(points) 48 | polydata.SetPolys(polygons) 49 | 50 | # Write the polydata to a file 51 | writer = vtk.vtkXMLPolyDataWriter() 52 | writer.SetFileName("naca0012.vtp") 53 | writer.SetInputData(polydata) 54 | writer.Write() 55 | 56 | # Now, visualize the airfoil 57 | mapper = vtk.vtkPolyDataMapper() 58 | mapper.SetInputData(polydata) 59 | 60 | actor = vtk.vtkActor() 61 | actor.SetMapper(mapper) 62 | 63 | renderer = vtk.vtkRenderer() 64 | renderWindow = vtk.vtkRenderWindow() 65 | renderWindow.AddRenderer(renderer) 66 | renderWindowInteractor = vtk.vtkRenderWindowInteractor() 67 | renderWindowInteractor.SetRenderWindow(renderWindow) 68 | 69 | renderer.AddActor(actor) 70 | renderer.SetBackground(1, 1, 1) 71 | 72 | renderWindow.Render() 73 | renderWindowInteractor.Start() 74 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/image_data.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | import numpy as np 3 | import vtk 4 | 5 | 6 | def create_gradient_image(width, height, filename="gradient_image.png"): 7 | """ 8 | Create a gradient image and save it. 9 | """ 10 | # Create a gradient from blue to green 11 | gradient = np.zeros((height, width, 3), dtype=np.uint8) 12 | for i in range(height): 13 | color = int(255 * i / height) # Gradient factor 14 | gradient[i, :, 0] = 255 - color 15 | gradient[i, :, 1] = color 16 | 17 | image = Image.fromarray(gradient, "RGB") 18 | image.save(filename) 19 | return filename 20 | 21 | 22 | def load_image_as_vtk_image_data(filename): 23 | """ 24 | Load an image and convert it into vtkImageData. 25 | """ 26 | reader = vtk.vtkPNGReader() 27 | reader.SetFileName(filename) 28 | reader.Update() 29 | return reader.GetOutput() 30 | 31 | 32 | def visualize_vtk_image_data(vtk_image_data): 33 | """ 34 | Visualize vtkImageData. 35 | """ 36 | # Map the image data through a lookup table 37 | color = vtk.vtkImageMapToColors() 38 | color.SetOutputFormatToRGB() 39 | color.SetInputData(vtk_image_data) 40 | 41 | # Create an actor 42 | actor = vtk.vtkImageActor() 43 | actor.GetMapper().SetInputConnection(color.GetOutputPort()) 44 | 45 | # Create a renderer 46 | renderer = vtk.vtkRenderer() 47 | renderer.AddActor(actor) 48 | renderer.SetBackground(0, 0, 0) # Set black background 49 | 50 | # Create a render window 51 | render_window = vtk.vtkRenderWindow() 52 | render_window.AddRenderer(renderer) 53 | 54 | # Create a render window interactor 55 | render_window_interactor = vtk.vtkRenderWindowInteractor() 56 | render_window_interactor.SetRenderWindow(render_window) 57 | 58 | # Start the interaction 59 | render_window.Render() 60 | render_window_interactor.Start() 61 | 62 | 63 | def main(): 64 | filename = create_gradient_image(256, 256) 65 | vtk_image_data = load_image_as_vtk_image_data(filename) 66 | visualize_vtk_image_data(vtk_image_data) 67 | 68 | 69 | if __name__ == "__main__": 70 | main() 71 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/multiblock_dataset.py: -------------------------------------------------------------------------------- 1 | """ 2 | A multiblock dataset in VTK is a composite dataset that can store other datasets including other composite datasets. 3 | - It is used to represent complex data where different regions can be meshed differently. 4 | - It is also used to group multiple datasets into one. 5 | 6 | Workflow Overview: 7 | 8 | 1. Geometric Source Creation: 9 | - The process begins with the dynamic creation of various geometric shapes such as spheres, cylinders, cones, and cubes. 10 | - Each shape is generated based on specific parameters (like radius, height, and dimensions), illustrating how VTK can be used to create a wide range of 3D objects. 11 | 12 | 2. Multiblock Dataset Assembly: 13 | - Once individual geometric shapes are created, they are assembled into a vtkMultiBlockDataSet. 14 | - This dataset serves as a container that can hold multiple disparate data sources, showcasing its capability to manage complex collections of 3D objects. 15 | 16 | 3. Conversion to PolyData: 17 | - The vtkMultiBlockDataSet is then converted into vtkPolyData, a versatile format in VTK used for rendering and visualizing geometric data. 18 | - This step is crucial as it transforms the multiblock dataset into a format that can be easily rendered by VTK's visualization pipeline. 19 | 20 | 4. Visualization Pipeline: 21 | - Finally, the polydata is fed into a pre-defined visualization pipeline, which is responsible for rendering the 3D objects on the screen. 22 | - This pipeline not only displays the assembled 3D shapes but also allows for interactive exploration of the scene, such as zooming and rotating the objects. 23 | """ 24 | 25 | import vtk 26 | 27 | from src.common.simple_pipeline import VisualisationPipeline 28 | 29 | 30 | def create_geometric_source(source_type, **params): 31 | """ 32 | Create and return a geometric source based on the specified type and parameters. 33 | Supported types: 'Sphere', 'Cylinder', 'Cone', 'Cube'. 34 | """ 35 | if source_type == "Sphere": 36 | source = vtk.vtkSphereSource() 37 | source.SetRadius(params.get("radius", 1.0)) 38 | source.SetCenter(params.get("center", [0.0, 0.0, 0.0])) 39 | elif source_type == "Cylinder": 40 | source = vtk.vtkCylinderSource() 41 | source.SetHeight(params.get("height", 2.0)) 42 | source.SetRadius(params.get("radius", 0.5)) 43 | elif source_type == "Cone": 44 | source = vtk.vtkConeSource() 45 | source.SetHeight(params.get("height", 2.0)) 46 | source.SetRadius(params.get("radius", 0.5)) 47 | elif source_type == "Cube": 48 | source = vtk.vtkCubeSource() 49 | source.SetXLength(params.get("length", 1.0)) 50 | source.SetYLength(params.get("width", 1.0)) 51 | source.SetZLength(params.get("height", 1.0)) 52 | else: 53 | raise ValueError("Unsupported source type") 54 | 55 | source.Update() 56 | return source.GetOutput() 57 | 58 | 59 | def create_multiblock_dataset(sources): 60 | """ 61 | Create a multiblock dataset from a list of VTK data sources. 62 | """ 63 | multiBlock = vtk.vtkMultiBlockDataSet() 64 | multiBlock.SetNumberOfBlocks(len(sources)) 65 | for i, source in enumerate(sources): 66 | multiBlock.SetBlock(i, source) 67 | return multiBlock 68 | 69 | 70 | def convert_to_polydata(multiBlock): 71 | """ 72 | Convert the multiblock dataset to polydata. 73 | """ 74 | geometryFilter = vtk.vtkCompositeDataGeometryFilter() 75 | geometryFilter.SetInputDataObject(multiBlock) 76 | geometryFilter.Update() 77 | return geometryFilter.GetOutput() 78 | 79 | 80 | def main(): 81 | # Create various geometric sources 82 | sphere = create_geometric_source("Sphere", radius=1.0) 83 | cylinder = create_geometric_source("Cylinder", height=2.0, radius=0.5) 84 | cone = create_geometric_source("Cone", height=2.0, radius=0.5) 85 | cube = create_geometric_source("Cube", length=1.0, width=1.0, height=1.0) 86 | 87 | # Create a multiblock dataset containing all sources 88 | sources = [sphere, cylinder, cone, cube] 89 | multiBlock = create_multiblock_dataset(sources) 90 | polydata = convert_to_polydata(multiBlock) 91 | 92 | # Create a mapper 93 | mapper = vtk.vtkPolyDataMapper() 94 | mapper.SetInputData(polydata) 95 | 96 | # Run the visualization pipeline 97 | pipeline = VisualisationPipeline(mappers=[mapper], point_size=30) 98 | pipeline.run() 99 | 100 | 101 | if __name__ == "__main__": 102 | main() 103 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/points.py: -------------------------------------------------------------------------------- 1 | """ 2 | n VTK, a point is a location in space. Points are used to define the geometry of graphical primitives. You can think of points as the vertices of graphical primitives such as lines, polygons, and volumes. 3 | 4 | To store and manipulate points, VTK provides the vtkPoints class. This class stores an array of 3D points, and provides methods for inserting points, retrieving points, and other point-related operations. 5 | """ 6 | 7 | import numpy as np 8 | import vtk 9 | import vtk.util.numpy_support as vtk_np 10 | 11 | from src.common.simple_pipeline import VisualisationPipeline 12 | 13 | 14 | def create_vtk_points(): 15 | """ 16 | Create a vtkPoints object and insert some points. 17 | """ 18 | points = vtk.vtkPoints() 19 | points.InsertNextPoint(0.0, 0.0, 0.0) 20 | points.InsertNextPoint(1.0, 0.0, 0.0) 21 | points.InsertNextPoint(0.0, 1.0, 0.0) 22 | return points 23 | 24 | 25 | def print_points_info(points): 26 | """ 27 | Print information about the vtkPoints object. 28 | """ 29 | print("Number of points:", points.GetNumberOfPoints()) 30 | for i in range(points.GetNumberOfPoints()): 31 | point = points.GetPoint(i) 32 | print(f"Point {i}: {point}") 33 | 34 | 35 | def vtk_points_to_numpy(points): 36 | """ 37 | Convert vtkPoints to a NumPy array. 38 | """ 39 | return vtk_np.vtk_to_numpy(points.GetData()) 40 | 41 | 42 | def numpy_to_vtk_points(numpy_array): 43 | """ 44 | Convert a NumPy array to vtkPoints. 45 | """ 46 | vtk_points = vtk.vtkPoints() 47 | vtk_points.SetData(vtk_np.numpy_to_vtk(numpy_array)) 48 | return vtk_points 49 | 50 | 51 | def create_and_visualize_polydata(points): 52 | """ 53 | Create polydata from vtkPoints and visualize them. 54 | """ 55 | polydata = vtk.vtkPolyData() 56 | polydata.SetPoints(points) 57 | 58 | glyphFilter = vtk.vtkVertexGlyphFilter() 59 | glyphFilter.SetInputData(polydata) 60 | glyphFilter.Update() 61 | 62 | mapper = vtk.vtkPolyDataMapper() 63 | mapper.SetInputConnection(glyphFilter.GetOutputPort()) 64 | 65 | pipeline = VisualisationPipeline(mappers=[mapper], point_size=30) 66 | pipeline.run() 67 | 68 | 69 | def main(): 70 | vtk_points = create_vtk_points() 71 | print_points_info(vtk_points) 72 | 73 | numpy_points = vtk_points_to_numpy(vtk_points) 74 | print("Numpy array:\n", numpy_points) 75 | 76 | new_numpy_points = np.array([[0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]]) 77 | new_vtk_points = numpy_to_vtk_points(new_numpy_points) 78 | print_points_info(new_vtk_points) 79 | 80 | create_and_visualize_polydata(vtk_points) 81 | 82 | 83 | if __name__ == "__main__": 84 | main() 85 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/poly_data.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module demonstrates the creation and visualization of a simple triangle using the Visualization Toolkit (VTK). It is structured into several distinct steps, each utilizing specific VTK components for 3D graphics and visualization: 3 | 4 | 1. Point Creation (vtkPoints): 5 | - Responsible for defining and storing the coordinates of vertices in a 3D space. 6 | - In this example, three points are created to represent the vertices of a triangle. 7 | 8 | 2. Triangle Geometry (vtkTriangle): 9 | - Defines the geometry of a triangle by specifying the connectivity between the points. 10 | - It uses the points' indices to create a triangular cell. 11 | 12 | 3. Cell Array (vtkCellArray): 13 | - A collection of cells (in this case, just one triangle). 14 | - Used to store the triangle geometry and facilitates the handling of multiple cells. 15 | 16 | 4. PolyData Creation (vtkPolyData): 17 | - A data object that holds geometric and topological data. 18 | - In this example, it stores the points and the triangle cell, representing the complete geometry of the triangle. 19 | 20 | 5. Data Mapping (vtkPolyDataMapper): 21 | - Maps the polydata (geometric data) to graphical primitives. 22 | - Essential for rendering the data in a window. 23 | 24 | 6. Actor Creation (vtkActor): 25 | - Represents an entity in the rendering process. 26 | - It is linked with the data mapper and controls the rendering of the polydata. 27 | 28 | 7. Renderer and Render Window: 29 | - The renderer (vtkRenderer) adds the actor to the scene. 30 | - The render window (vtkRenderWindow) displays the rendered graphics. 31 | 32 | 8. Interaction: 33 | - The render window interactor (vtkRenderWindowInteractor) allows user interaction with the visualization, such as rotating and zooming. 34 | 35 | The module serves as an educational example to illustrate the basic components and workflow in VTK for creating and displaying simple geometric shapes in 3D. It highlights the use of polydata as a versatile structure for representing and manipulating geometric data in VTK, which is a cornerstone for more complex 3D visualizations in scientific and engineering applications. 36 | """ 37 | 38 | import vtk 39 | 40 | from src.common.simple_pipeline import VisualisationPipeline 41 | 42 | 43 | def create_points(): 44 | """ 45 | Create and return a vtkPoints object with predefined points. 46 | """ 47 | points = vtk.vtkPoints() 48 | points.InsertNextPoint([0.0, 0.0, 0.0]) # Point 1 49 | points.InsertNextPoint([1.0, 0.0, 0.0]) # Point 2 50 | points.InsertNextPoint([0.5, 0.866, 0.0]) # Point 3 51 | return points 52 | 53 | 54 | def create_triangle(): 55 | """ 56 | Create and return a vtkTriangle. 57 | """ 58 | triangle = vtk.vtkTriangle() 59 | triangle.GetPointIds().SetId(0, 0) # Vertex 1 60 | triangle.GetPointIds().SetId(1, 1) # Vertex 2 61 | triangle.GetPointIds().SetId(2, 2) # Vertex 3 62 | return triangle 63 | 64 | 65 | def create_polydata(points, triangle): 66 | """ 67 | Create and return a vtkPolyData object containing the points and triangle. 68 | """ 69 | triangles = vtk.vtkCellArray() 70 | triangles.InsertNextCell(triangle) 71 | 72 | polydata = vtk.vtkPolyData() 73 | polydata.SetPoints(points) 74 | polydata.SetPolys(triangles) 75 | return polydata 76 | 77 | 78 | def main(): 79 | points = create_points() 80 | triangle = create_triangle() 81 | polydata = create_polydata(points, triangle) 82 | 83 | mapper = vtk.vtkPolyDataMapper() 84 | mapper.SetInputData(polydata) 85 | 86 | pipeline = VisualisationPipeline(mappers=[mapper]) 87 | pipeline.run() 88 | 89 | 90 | if __name__ == "__main__": 91 | main() 92 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/rectilinear_grid.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import vtk 3 | 4 | from src.common.simple_pipeline import VisualisationPipeline 5 | 6 | 7 | def create_rectilinear_grid(x_coords, y_coords, z_coords): 8 | """ 9 | Create and return a rectilinear grid. 10 | """ 11 | rgrid = vtk.vtkRectilinearGrid() 12 | rgrid.SetDimensions(len(x_coords), len(y_coords), len(z_coords)) 13 | 14 | # Set X coordinates 15 | x_array = vtk.vtkFloatArray() 16 | for x in x_coords: 17 | x_array.InsertNextValue(x) 18 | rgrid.SetXCoordinates(x_array) 19 | 20 | # Set Y coordinates 21 | y_array = vtk.vtkFloatArray() 22 | for y in y_coords: 23 | y_array.InsertNextValue(y) 24 | rgrid.SetYCoordinates(y_array) 25 | 26 | # Set Z coordinates 27 | z_array = vtk.vtkFloatArray() 28 | for z in z_coords: 29 | z_array.InsertNextValue(z) 30 | rgrid.SetZCoordinates(z_array) 31 | 32 | return rgrid 33 | 34 | 35 | def attach_fields_to_grid(rgrid): 36 | """ 37 | Attach scalar and vector fields to the rectilinear grid. 38 | """ 39 | # Attach a scalar field 40 | scalars = vtk.vtkFloatArray() 41 | scalars.SetName("Scalars") 42 | num_points = rgrid.GetNumberOfPoints() 43 | for i in range(num_points): 44 | scalars.InsertNextValue(np.random.rand()) 45 | rgrid.GetPointData().SetScalars(scalars) 46 | 47 | # Attach a vector field 48 | vectors = vtk.vtkFloatArray() 49 | vectors.SetNumberOfComponents(3) 50 | vectors.SetName("Vectors") 51 | for i in range(num_points): 52 | vectors.InsertNextTuple3(np.random.rand(), np.random.rand(), np.random.rand()) 53 | rgrid.GetPointData().SetVectors(vectors) 54 | 55 | 56 | def visualize_rectilinear_grid(rgrid): 57 | """ 58 | Visualize the rectilinear grid with scalar and vector fields. 59 | """ 60 | geometry_filter = vtk.vtkRectilinearGridGeometryFilter() 61 | geometry_filter.SetInputData(rgrid) 62 | 63 | mapper = vtk.vtkPolyDataMapper() 64 | mapper.SetInputConnection(geometry_filter.GetOutputPort()) 65 | mapper.SetScalarModeToUsePointData() 66 | mapper.SetColorModeToMapScalars() 67 | mapper.SelectColorArray("Scalars") 68 | 69 | pipeline = VisualisationPipeline(mappers=[mapper], point_size=30) 70 | pipeline.run() 71 | 72 | 73 | def main(): 74 | x_coords = np.linspace(0, 10, 11) 75 | y_coords = np.linspace(0, 5, 6) 76 | z_coords = np.linspace(0, 3, 4) 77 | rgrid = create_rectilinear_grid(x_coords, y_coords, z_coords) 78 | attach_fields_to_grid(rgrid) 79 | visualize_rectilinear_grid(rgrid) 80 | 81 | 82 | if __name__ == "__main__": 83 | main() 84 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/structured_grid.py: -------------------------------------------------------------------------------- 1 | """ 2 | Structured grids in VTK represent a mesh in which points are arranged in a regular lattice in 3D space. It is best suited for problems where the domain can be discretized as a regular grid. For example, in computational fluid dynamics, it is common to use a structured grid to represent the fluid domain. 3 | 4 | Workflow Overview: 5 | 6 | 1. Structured Grid Creation (create_structured_grid): 7 | - Initializes a vtkStructuredGrid with specified dimensions (nx, ny, nz), representing the grid's resolution in each direction. 8 | - Populates the grid with points in a regular, lattice-like arrangement using vtkPoints, illustrating how to define spatial coordinates in a structured grid. 9 | - Returns a fully defined vtkStructuredGrid, ready for visualization. 10 | 11 | 2. Visualization (visualize_structured_grid): 12 | - Takes the created structured grid as input and sets up a vtkDataSetMapper for it. The mapper translates the grid data into a format suitable for rendering. 13 | - Utilizes a predefined 'VisualisationPipeline' to handle the rendering process. This pipeline is configured to make the edges of the grid visible, enhancing the perception of the grid structure in 3D space. 14 | 15 | 3. Main Function (main): 16 | - Defines the dimensions for the structured grid. 17 | - Calls the grid creation and visualization functions, orchestrating the process from grid setup to rendering. 18 | """ 19 | 20 | import vtk 21 | 22 | from src.common.simple_pipeline import VisualisationPipeline 23 | 24 | 25 | def create_structured_grid(nx, ny, nz): 26 | """ 27 | Create a structured grid with specified dimensions. 28 | 29 | Args: 30 | nx, ny, nz (int): Dimensions of the grid in the x, y, and z directions. 31 | 32 | Returns: 33 | vtkStructuredGrid: A structured grid with the specified dimensions. 34 | """ 35 | structuredGrid = vtk.vtkStructuredGrid() 36 | structuredGrid.SetDimensions(nx, ny, nz) 37 | 38 | points = vtk.vtkPoints() 39 | for k in range(nz): 40 | for j in range(ny): 41 | for i in range(nx): 42 | points.InsertNextPoint(i, j, k) 43 | 44 | structuredGrid.SetPoints(points) 45 | return structuredGrid 46 | 47 | 48 | def visualize_structured_grid(structuredGrid): 49 | """ 50 | Visualize the given structured grid using a predefined visualization pipeline. 51 | 52 | Args: 53 | structuredGrid (vtkStructuredGrid): The structured grid to be visualized. 54 | """ 55 | mapper = vtk.vtkDataSetMapper() 56 | mapper.SetInputData(structuredGrid) 57 | 58 | # Configure and run the visualization pipeline 59 | pipeline = VisualisationPipeline(mappers=[mapper], edges_visible=True) 60 | pipeline.run() 61 | 62 | 63 | def main(): 64 | # Define dimensions for the structured grid 65 | nx, ny, nz = 6, 6, 2 66 | 67 | # Create and visualize the structured grid 68 | structuredGrid = create_structured_grid(nx, ny, nz) 69 | visualize_structured_grid(structuredGrid) 70 | 71 | 72 | if __name__ == "__main__": 73 | main() 74 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/structured_mesh.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | 4 | # Enhanced grid creation with function 5 | def create_structured_grid(dimensions): 6 | grid = vtk.vtkStructuredGrid() 7 | grid.SetDimensions(dimensions) 8 | 9 | points = vtk.vtkPoints() 10 | for z in range(dimensions[2]): 11 | for y in range(dimensions[1]): 12 | for x in range(dimensions[0]): 13 | points.InsertNextPoint(x, y, z) 14 | grid.SetPoints(points) 15 | return grid 16 | 17 | 18 | # Function to create a standard mapper and actor 19 | def create_actor(source, color=None, point_size=None, line_width=None): 20 | mapper = vtk.vtkPolyDataMapper() 21 | mapper.SetInputConnection(source.GetOutputPort()) 22 | 23 | actor = vtk.vtkActor() 24 | actor.SetMapper(mapper) 25 | 26 | if color: 27 | actor.GetProperty().SetColor(color) 28 | if point_size: 29 | actor.GetProperty().SetPointSize(point_size) 30 | if line_width: 31 | actor.GetProperty().SetLineWidth(line_width) 32 | 33 | return actor 34 | 35 | 36 | # Grid dimensions 37 | dimensions = [10, 10, 10] 38 | structuredGrid = create_structured_grid(dimensions) 39 | 40 | # Outline creation 41 | outline = vtk.vtkStructuredGridOutlineFilter() 42 | outline.SetInputData(structuredGrid) 43 | outlineActor = create_actor(outline) 44 | 45 | # Points visualization 46 | pointGlyph = vtk.vtkVertexGlyphFilter() 47 | pointGlyph.SetInputData(structuredGrid) 48 | pointActor = create_actor(pointGlyph, point_size=1) 49 | 50 | # Highlight node 51 | highlightNode = vtk.vtkSphereSource() 52 | highlightNode.SetCenter(5, 5, 5) 53 | highlightNode.SetRadius(0.2) 54 | highlightNodeActor = create_actor(highlightNode, color=(1, 0, 0)) 55 | 56 | # Edges visualization 57 | edgeFilter = vtk.vtkExtractEdges() 58 | edgeFilter.SetInputData(structuredGrid) 59 | edgeActor = create_actor(edgeFilter, color=(0.5, 0.5, 0.5), line_width=1) 60 | 61 | # Highlight edge 62 | highlightEdge = vtk.vtkLineSource() 63 | highlightEdge.SetPoint1(5, 5, 5) 64 | highlightEdge.SetPoint2(6, 5, 5) 65 | highlightEdgeActor = create_actor(highlightEdge, color=(0, 1, 0), line_width=3) 66 | 67 | # Highlight cell 68 | highlightCell = vtk.vtkCubeSource() 69 | highlightCell.SetCenter(7.5, 7.5, 7.5) 70 | highlightCell.SetXLength(1) 71 | highlightCell.SetYLength(1) 72 | highlightCell.SetZLength(1) 73 | highlightCellActor = create_actor(highlightCell, color=(0, 0, 1)) 74 | 75 | # Legend creation 76 | legend = vtk.vtkLegendBoxActor() 77 | legend.SetNumberOfEntries(3) 78 | legend.SetEntry(0, vtk.vtkPolyData(), "Node (Red)", [1, 0, 0]) 79 | legend.SetEntry(1, vtk.vtkPolyData(), "Edge (Green)", [0, 1, 0]) 80 | legend.SetEntry(2, vtk.vtkPolyData(), "Cell (Blue)", [0, 0, 1]) 81 | 82 | # Renderer and Render Window setup 83 | renderer = vtk.vtkRenderer() 84 | renderWindow = vtk.vtkRenderWindow() 85 | renderWindow.AddRenderer(renderer) 86 | renderWindow.SetSize(800, 600) 87 | renderer.SetBackground(0.2, 0.3, 0.4) 88 | 89 | # Render Window Interactor 90 | renderWindowInteractor = vtk.vtkRenderWindowInteractor() 91 | renderWindowInteractor.SetRenderWindow(renderWindow) 92 | 93 | # Adding actors and legend to renderer 94 | actors = [ 95 | outlineActor, 96 | pointActor, 97 | edgeActor, 98 | highlightNodeActor, 99 | highlightEdgeActor, 100 | highlightCellActor, 101 | legend, 102 | ] 103 | for actor in actors: 104 | renderer.AddActor(actor) 105 | 106 | 107 | # Visibility toggle functions 108 | def toggle_visibility(actor): 109 | actor.SetVisibility(not actor.GetVisibility()) 110 | renderWindow.Render() 111 | 112 | 113 | # Button creation and setup 114 | from src.common.button import Button2D 115 | 116 | # Create a 2D button for toggling points 117 | pointsButton = Button2D(renderWindowInteractor, "Points", (10, 10), (100, 40)) 118 | pointsButton.add_click_callback(lambda: toggle_visibility(pointActor)) 119 | 120 | # Create a 2D button for toggling edges 121 | edgesButton = Button2D(renderWindowInteractor, "Edges", (120, 10), (100, 40)) 122 | edgesButton.add_click_callback(lambda: toggle_visibility(edgeActor)) 123 | 124 | # Start the interaction 125 | renderWindow.Render() 126 | renderWindowInteractor.Start() 127 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/unstructured_grid.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module demonstrates the creation, manipulation, and visualization of an unstructured grid using the Visualization Toolkit (VTK). An unstructured grid is a versatile data structure in VTK that allows for representing complex geometries composed of various types of cells. In this example, a hexahedron and a tetrahedron are created, along with their associated points, and then combined into a single unstructured grid. Additionally, scalar and vector fields are attached to this grid to illustrate the concept of data association with grid points and cells. 3 | 4 | Key Components and Workflow: 5 | 6 | 1. Hexahedron and Tetrahedron Creation: 7 | - Hexahedron (vtkHexahedron) and tetrahedron (vtkTetra) cells are created to represent two different 3D geometric shapes. 8 | - The point ids for each cell are set to define the geometry of these cells. 9 | 10 | 2. Points Creation (vtkPoints): 11 | - A vtkPoints object is created to store the coordinates of the vertices for both the hexahedron and tetrahedron. 12 | 13 | 3. Unstructured Grid (vtkUnstructuredGrid): 14 | - An unstructured grid is defined to hold the created cells. 15 | - This grid type is chosen for its ability to handle diverse cell types within a single data structure. 16 | 17 | 4. Scalar and Vector Fields: 18 | - Scalar values (random) are attached to the points of the grid, demonstrating how to associate data with grid points. 19 | - Vector values (random) are attached to the cells of the grid, showing data association with grid cells. 20 | 21 | 5. Visualization: 22 | - A vtkDataSetMapper is used to map the unstructured grid data to graphical primitives. 23 | - The visualization pipeline, encapsulated in the 'VisualisationPipeline' class, is then utilized to render the grid with the scalar and vector fields. The pipeline is configured to highlight the edges of the grid and enhance the visual understanding of its structure. 24 | 25 | """ 26 | 27 | import numpy as np 28 | import vtk 29 | 30 | from src.common.simple_pipeline import VisualisationPipeline 31 | 32 | 33 | def create_hexahedron(): 34 | """ 35 | Create and return a hexahedron cell. 36 | """ 37 | hexahedron = vtk.vtkHexahedron() 38 | for i in range(8): 39 | hexahedron.GetPointIds().SetId(i, i) 40 | return hexahedron 41 | 42 | 43 | def create_tetrahedron(): 44 | """ 45 | Create and return a tetrahedron cell. 46 | """ 47 | tetrahedron = vtk.vtkTetra() 48 | for i in range(4): 49 | tetrahedron.GetPointIds().SetId(i, i + 8) 50 | return tetrahedron 51 | 52 | 53 | def create_points(): 54 | """ 55 | Create and return vtkPoints for the hexahedron and tetrahedron. 56 | """ 57 | points = vtk.vtkPoints() 58 | # Hexahedron points 59 | for i in range(8): 60 | points.InsertNextPoint(i % 2, (i // 2) % 2, i // 4) 61 | # Tetrahedron points 62 | points.InsertNextPoint(2, 2, 2) 63 | points.InsertNextPoint(2, 3, 2) 64 | points.InsertNextPoint(3, 2, 2) 65 | points.InsertNextPoint(2, 2, 3) 66 | return points 67 | 68 | 69 | def create_unstructured_grid(points, hexahedron, tetrahedron): 70 | """ 71 | Create and return an unstructured grid containing the hexahedron and tetrahedron. 72 | """ 73 | ugrid = vtk.vtkUnstructuredGrid() 74 | ugrid.SetPoints(points) 75 | ugrid.InsertNextCell(hexahedron.GetCellType(), hexahedron.GetPointIds()) 76 | ugrid.InsertNextCell(tetrahedron.GetCellType(), tetrahedron.GetPointIds()) 77 | return ugrid 78 | 79 | 80 | def attach_fields_to_grid(ugrid, points): 81 | """ 82 | Attach scalar and vector fields to the unstructured grid. 83 | """ 84 | # Attach a scalar field to the points 85 | scalars = vtk.vtkFloatArray() 86 | scalars.SetName("Scalars") 87 | for i in range(points.GetNumberOfPoints()): 88 | scalars.InsertNextValue(np.random.rand()) 89 | ugrid.GetPointData().SetScalars(scalars) 90 | 91 | # Attach a vector field to the cells 92 | vectors = vtk.vtkFloatArray() 93 | vectors.SetNumberOfComponents(3) 94 | vectors.SetName("Vectors") 95 | for i in range(ugrid.GetNumberOfCells()): 96 | vectors.InsertNextTuple3(np.random.rand(), np.random.rand(), np.random.rand()) 97 | ugrid.GetCellData().SetVectors(vectors) 98 | 99 | 100 | def visualize_unstructured_grid(ugrid): 101 | """ 102 | Visualize the unstructured grid with scalar and vector fields. 103 | """ 104 | mapper = vtk.vtkDataSetMapper() 105 | mapper.SetInputData(ugrid) 106 | mapper.SetScalarModeToUsePointData() 107 | mapper.SetColorModeToMapScalars() 108 | mapper.SelectColorArray("Scalars") 109 | 110 | pipeline = VisualisationPipeline(mappers=[mapper], point_size=30) 111 | pipeline.run() 112 | 113 | 114 | def main(): 115 | hexahedron = create_hexahedron() 116 | tetrahedron = create_tetrahedron() 117 | points = create_points() 118 | ugrid = create_unstructured_grid(points, hexahedron, tetrahedron) 119 | attach_fields_to_grid(ugrid, points) 120 | visualize_unstructured_grid(ugrid) 121 | 122 | 123 | if __name__ == "__main__": 124 | main() 125 | -------------------------------------------------------------------------------- /src/03_structures_and_datasets/unstructured_mesh.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import vtk 4 | 5 | 6 | # Function to create an unstructured grid with a variety of cell types 7 | def create_unstructured_grid(): 8 | grid = vtk.vtkUnstructuredGrid() 9 | points = vtk.vtkPoints() 10 | 11 | # Define points for a larger structure 12 | point_ids = [ 13 | points.InsertNextPoint(x, y, z) 14 | for x in range(4) 15 | for y in range(4) 16 | for z in range(4) 17 | ] 18 | 19 | for x in range(4): 20 | for y in range(4): 21 | for z in range(4): 22 | # Add some randomness to the node positions 23 | dx, dy, dz = ( 24 | random.uniform(-0.2, 0.2), 25 | random.uniform(-0.2, 0.2), 26 | random.uniform(-0.2, 0.2), 27 | ) 28 | points.InsertNextPoint(x + dx, y + dy, z + dz) 29 | 30 | grid.SetPoints(points) 31 | 32 | # Add different types of cells to the unstructured grid 33 | for i in range(0, len(point_ids), 4): 34 | # Adding a hexahedron cell 35 | hexahedron = vtk.vtkHexahedron() 36 | for j in range(8): 37 | hexahedron.GetPointIds().SetId(j, (i + j) % len(point_ids)) 38 | grid.InsertNextCell(hexahedron.GetCellType(), hexahedron.GetPointIds()) 39 | 40 | # Adding a tetrahedron cell 41 | tetra = vtk.vtkTetra() 42 | for j in range(4): 43 | tetra.GetPointIds().SetId(j, (i + j) % len(point_ids)) 44 | grid.InsertNextCell(tetra.GetCellType(), tetra.GetPointIds()) 45 | 46 | return grid 47 | 48 | 49 | # Function to create a standard mapper and actor 50 | def create_actor(source, color=None, point_size=None, line_width=None): 51 | mapper = vtk.vtkPolyDataMapper() 52 | mapper.SetInputConnection(source.GetOutputPort()) 53 | 54 | actor = vtk.vtkActor() 55 | actor.SetMapper(mapper) 56 | 57 | if color: 58 | actor.GetProperty().SetColor(color) 59 | if point_size: 60 | actor.GetProperty().SetPointSize(point_size) 61 | if line_width: 62 | actor.GetProperty().SetLineWidth(line_width) 63 | 64 | return actor 65 | 66 | 67 | # Create an unstructured grid 68 | unstructuredGrid = create_unstructured_grid() 69 | 70 | # Nodes visualization with smaller size 71 | nodeGlyph = vtk.vtkGlyph3D() 72 | nodeGlyph.SetInputData(unstructuredGrid) 73 | sphereSource = vtk.vtkSphereSource() 74 | sphereSource.SetRadius(0.05) # Smaller radius for nodes 75 | nodeGlyph.SetSourceConnection(sphereSource.GetOutputPort()) 76 | nodeActor = create_actor(nodeGlyph, point_size=1) 77 | 78 | # Edges visualization with smaller width 79 | edgeFilter = vtk.vtkExtractEdges() 80 | edgeFilter.SetInputData(unstructuredGrid) 81 | edgeActor = create_actor(edgeFilter, line_width=0.5) 82 | 83 | # Highlight node 84 | highlightNode = vtk.vtkSphereSource() 85 | highlightNode.SetCenter(2, 2, 2) 86 | highlightNode.SetRadius(0.1) 87 | highlightNodeActor = create_actor(highlightNode, color=(1, 0, 0)) 88 | 89 | # Highlight edge 90 | highlightEdge = vtk.vtkLineSource() 91 | highlightEdge.SetPoint1(1, 1, 1) 92 | highlightEdge.SetPoint2(2, 1, 1) 93 | highlightEdgeActor = create_actor(highlightEdge, color=(0, 1, 0), line_width=2) 94 | 95 | # Highlight cell 96 | highlightCell = vtk.vtkCubeSource() 97 | highlightCell.SetCenter(1.5, 1.5, 1.5) 98 | highlightCell.SetXLength(1) 99 | highlightCell.SetYLength(1) 100 | highlightCell.SetZLength(1) 101 | highlightCellActor = create_actor(highlightCell, color=(0, 0, 1)) 102 | 103 | # Legend creation 104 | legend = vtk.vtkLegendBoxActor() 105 | legend.SetNumberOfEntries(3) 106 | legend.SetEntry(0, vtk.vtkPolyData(), "Node (Red)", [1, 0, 0]) 107 | legend.SetEntry(1, vtk.vtkPolyData(), "Edge (Green)", [0, 1, 0]) 108 | legend.SetEntry(2, vtk.vtkPolyData(), "Cell (Blue)", [0, 0, 1]) 109 | 110 | # Renderer and Render Window setup 111 | renderer = vtk.vtkRenderer() 112 | renderWindow = vtk.vtkRenderWindow() 113 | renderWindow.AddRenderer(renderer) 114 | renderWindow.SetSize(800, 600) 115 | renderer.SetBackground(0.2, 0.3, 0.4) 116 | 117 | # Render Window Interactor 118 | renderWindowInteractor = vtk.vtkRenderWindowInteractor() 119 | renderWindowInteractor.SetRenderWindow(renderWindow) 120 | 121 | # Adding actors to renderer 122 | actors = [ 123 | nodeActor, 124 | edgeActor, 125 | highlightNodeActor, 126 | highlightEdgeActor, 127 | highlightCellActor, 128 | legend, 129 | ] 130 | for actor in actors: 131 | renderer.AddActor(actor) 132 | 133 | 134 | # Visibility toggle functions 135 | def toggle_visibility(actor): 136 | actor.SetVisibility(not actor.GetVisibility()) 137 | renderWindow.Render() 138 | 139 | 140 | # Button creation and setup 141 | from src.common.button import Button2D 142 | 143 | # Create a 2D button for toggling nodes 144 | nodesButton = Button2D(renderWindowInteractor, "Nodes", (10, 10), (100, 40)) 145 | nodesButton.add_click_callback(lambda: toggle_visibility(nodeActor)) 146 | 147 | # Create a 2D button for toggling edges 148 | edgesButton = Button2D(renderWindowInteractor, "Edges", (120, 10), (100, 40)) 149 | edgesButton.add_click_callback(lambda: toggle_visibility(edgeActor)) 150 | 151 | # Start the interaction 152 | renderWindow.Render() 153 | renderWindowInteractor.Start() 154 | -------------------------------------------------------------------------------- /src/04_input_output/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/04_input_output/__init__.py -------------------------------------------------------------------------------- /src/04_input_output/io_exodus_ii.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | from vtkmodules.vtkCommonDataModel import vtkMultiBlockDataSet 3 | 4 | from src.common.simple_pipeline import VisualisationPipeline 5 | 6 | FILE_NAME = "../../data/exodus/tetrahedron.exo" 7 | 8 | 9 | def read_exodus(filename: str) -> vtkMultiBlockDataSet: 10 | """Read an Exodus II file.""" 11 | reader = vtk.vtkExodusIIReader() 12 | reader.SetFileName(filename) 13 | reader.UpdateInformation() 14 | reader.SetAllArrayStatus( 15 | vtk.vtkExodusIIReader.NODAL, 1 16 | ) # Enables the reading of all nodal fields. 17 | reader.Update() 18 | return reader.GetOutput() 19 | 20 | 21 | def write_exodus(data: vtkMultiBlockDataSet, filename: str) -> None: 22 | """Write an Exodus II file.""" 23 | writer = vtk.vtkExodusIIWriter() 24 | writer.SetFileName(filename) 25 | writer.SetInputData(data) 26 | writer.Write() 27 | 28 | 29 | def translate_mesh(input_block, dx, dy, dz): 30 | if isinstance(input_block, vtk.vtkMultiBlockDataSet): 31 | for i in range(input_block.GetNumberOfBlocks()): 32 | sub_block = input_block.GetBlock(i) 33 | if sub_block is not None: 34 | translate_mesh(sub_block, dx, dy, dz) 35 | 36 | elif isinstance(input_block, vtk.vtkPointSet): 37 | points = input_block.GetPoints() 38 | for i in range(points.GetNumberOfPoints()): 39 | x, y, z = points.GetPoint(i) 40 | points.SetPoint(i, x + dx, y + dy, z + dz) 41 | 42 | 43 | if __name__ == "__main__": 44 | # Read Exodus II file 45 | exodus_data = read_exodus(FILE_NAME) 46 | 47 | # Use vtkCompositeDataGeometryFilter to convert the multiblock dataset to polydata 48 | geometryFilter = vtk.vtkCompositeDataGeometryFilter() 49 | geometryFilter.SetInputDataObject(exodus_data) 50 | geometryFilter.Update() 51 | 52 | # Create a mapper and actor for the polydata 53 | mapper = vtk.vtkPolyDataMapper() 54 | mapper.SetInputConnection(geometryFilter.GetOutputPort()) 55 | # Display 56 | pipeline = VisualisationPipeline(mappers=[mapper]) 57 | pipeline.run() 58 | 59 | # Translate the mesh along the x-axis by 10 units 60 | translate_mesh(exodus_data, 10.0, 0.0, 0.0) 61 | 62 | # Write Exodus II file 63 | write_exodus(exodus_data, "output.exo") 64 | -------------------------------------------------------------------------------- /src/04_input_output/io_obj.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | from src.common.simple_pipeline import VisualisationPipeline 4 | 5 | FILE_NAME = "../../data/objs/cube.obj" 6 | 7 | 8 | def write_obj(data: vtk.vtkPolyData, filename: str): 9 | writer = vtk.vtkOBJWriter() 10 | writer.SetFileName(filename) 11 | writer.SetInputData(data) 12 | writer.Write() 13 | 14 | 15 | def read_obj(filename: str) -> vtk.vtkPolyData: 16 | reader = vtk.vtkOBJReader() 17 | reader.SetFileName(filename) 18 | reader.Update() 19 | return reader.GetOutput() 20 | 21 | 22 | def transform_polydata(polydata: vtk.vtkPolyData, transform: vtk.vtkTransform): 23 | transform_filter = vtk.vtkTransformPolyDataFilter() 24 | transform_filter.SetInputData(polydata) 25 | transform_filter.SetTransform(transform) 26 | transform_filter.Update() 27 | return transform_filter.GetOutput() 28 | 29 | 30 | if __name__ == "__main__": 31 | 32 | # Read OBJ file 33 | obj_data = read_obj(FILE_NAME) 34 | 35 | # Display for verification 36 | mapper = vtk.vtkPolyDataMapper() 37 | mapper.SetInputData(obj_data) 38 | 39 | # Display 40 | pipeline = VisualisationPipeline(mappers=[mapper]) 41 | pipeline.run() 42 | 43 | # Apply a translation transform 44 | transform = vtk.vtkTransform() 45 | transform.Scale(2.0, 1.0, 1.0) # Double the size along the x-axis 46 | transform.RotateZ(45.0) # Rotate 45 degrees about the z-axis 47 | obj_data = transform_polydata(obj_data, transform) 48 | 49 | # Write OBJ file 50 | write_obj(obj_data, "../../data/objs/cube.obj") 51 | -------------------------------------------------------------------------------- /src/04_input_output/io_openfoam.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | from src.common.simple_pipeline import VisualisationPipeline 4 | 5 | FOAM_CASE_PATH = "../../data/open_foam/temp.case" 6 | 7 | 8 | def write_vtk(data: vtk.vtkMultiBlockDataSet, filename: str): 9 | writer = vtk.vtkXMLMultiBlockDataWriter() 10 | writer.SetFileName(filename) 11 | writer.SetInputData(data) 12 | writer.Write() 13 | 14 | 15 | def read_foam(case_path: str) -> vtk.vtkMultiBlockDataSet: 16 | reader = vtk.vtkOpenFOAMReader() 17 | reader.SetFileName(case_path + "/system/controlDict") 18 | reader.Update() 19 | return reader.GetOutput() 20 | 21 | 22 | def transform_block(block: vtk.vtkMultiBlockDataSet, transform: vtk.vtkTransform): 23 | transform_filter = vtk.vtkTransformFilter() 24 | transform_filter.SetInputData(block) 25 | transform_filter.SetTransform(transform) 26 | transform_filter.Update() 27 | return transform_filter.GetOutput() 28 | 29 | 30 | if __name__ == "__main__": 31 | 32 | # Read OpenFOAM case 33 | foam_data = read_foam(FOAM_CASE_PATH) 34 | 35 | # Display for verification 36 | mapper = vtk.vtkCompositePolyDataMapper2() 37 | mapper.SetInputData(foam_data) 38 | 39 | # Display 40 | pipeline = VisualisationPipeline(mappers=[mapper]) 41 | pipeline.run() 42 | 43 | # Apply a translation transform 44 | transform = vtk.vtkTransform() 45 | transform.Scale(2.0, 1.0, 1.0) # Double the size along the x-axis 46 | transform.RotateZ(45.0) # Rotate 45 degrees about the z-axis 47 | foam_data = transform_block(foam_data, transform) 48 | 49 | # Write VTK file 50 | write_vtk(foam_data, "test.vtk") 51 | -------------------------------------------------------------------------------- /src/04_input_output/io_stl.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | from src.common.simple_pipeline import VisualisationPipeline 4 | 5 | FILE_NAME = "../../data/stls/cube.stl" 6 | 7 | 8 | def write_stl(data: vtk.vtkUnstructuredGrid, filename: str): 9 | writer = vtk.vtkSTLWriter() 10 | writer.SetFileName(filename) 11 | writer.SetInputData(data) 12 | writer.Write() 13 | 14 | 15 | def read_stl(filename: str) -> vtk.vtkPolyData: 16 | reader = vtk.vtkSTLReader() 17 | reader.SetFileName(filename) 18 | reader.Update() 19 | return reader.GetOutput() 20 | 21 | 22 | def transform_grid(grid: vtk.vtkUnstructuredGrid, transform: vtk.vtkTransform): 23 | transform_filter = vtk.vtkTransformFilter() 24 | transform_filter.SetInputData(grid) 25 | transform_filter.SetTransform(transform) 26 | transform_filter.Update() 27 | return transform_filter.GetOutput() 28 | 29 | 30 | if __name__ == "__main__": 31 | 32 | # Read STL file 33 | stl_data = read_stl(FILE_NAME) 34 | 35 | # Display for verification 36 | mapper = vtk.vtkDataSetMapper() 37 | mapper.SetInputData(stl_data) 38 | 39 | # Display 40 | pipeline = VisualisationPipeline(mappers=[mapper]) 41 | pipeline.run() 42 | 43 | # Apply a translation transform 44 | transform = vtk.vtkTransform() 45 | transform.Scale(2.0, 1.0, 1.0) # Double the size along the x-axis 46 | transform.RotateZ(45.0) # Rotate 45 degrees about the z-axis 47 | stl_data = transform_grid(stl_data, transform) 48 | 49 | # Write STL file 50 | write_stl(stl_data, "test.stl") 51 | -------------------------------------------------------------------------------- /src/04_input_output/io_vtk.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | from src.common.simple_pipeline import VisualisationPipeline 4 | 5 | FILE_NAME = "../../data/vtks/grid_of_triangles.vtk" 6 | 7 | 8 | def write_vtk(data: vtk.vtkUnstructuredGrid, filename: str): 9 | writer = vtk.vtkUnstructuredGridWriter() 10 | writer.SetFileName(filename) 11 | writer.SetInputData(data) 12 | writer.Write() 13 | 14 | 15 | def read_vtk(filename: str) -> vtk.vtkUnstructuredGrid: 16 | reader = vtk.vtkUnstructuredGridReader() 17 | reader.SetFileName(filename) 18 | reader.Update() 19 | return reader.GetOutput() 20 | 21 | 22 | def transform_grid(grid: vtk.vtkUnstructuredGrid, transform: vtk.vtkTransform): 23 | transform_filter = vtk.vtkTransformFilter() 24 | transform_filter.SetInputData(grid) 25 | transform_filter.SetTransform(transform) 26 | transform_filter.Update() 27 | return transform_filter.GetOutput() 28 | 29 | 30 | def print_dataset_info(dataset: vtk.vtkUnstructuredGrid): 31 | point_data = dataset.GetPointData() 32 | cell_data = dataset.GetCellData() 33 | 34 | print(f"Number of point data arrays: {point_data.GetNumberOfArrays()}") 35 | for j in range(point_data.GetNumberOfArrays()): 36 | array = point_data.GetArray(j) 37 | print(f" Point data array {j}: {point_data.GetArrayName(j)}") 38 | print(f" Number of components: {array.GetNumberOfComponents()}") 39 | print(f" Number of tuples: {array.GetNumberOfTuples()}") 40 | print(f" Range: {array.GetRange()}") 41 | 42 | print(f"Number of cell data arrays: {cell_data.GetNumberOfArrays()}") 43 | for j in range(cell_data.GetNumberOfArrays()): 44 | array = cell_data.GetArray(j) 45 | print(f" Cell data array {j}: {cell_data.GetArrayName(j)}") 46 | print(f" Number of components: {array.GetNumberOfComponents()}") 47 | print(f" Number of tuples: {array.GetNumberOfTuples()}") 48 | print(f" Range: {array.GetRange()}") 49 | 50 | 51 | if __name__ == "__main__": 52 | 53 | # Read VTK file 54 | vtk_data = read_vtk(FILE_NAME) 55 | 56 | # Print dataset info 57 | print_dataset_info(vtk_data) 58 | 59 | # Display for verification 60 | mapper = vtk.vtkDataSetMapper() 61 | mapper.SetInputData(vtk_data) 62 | 63 | # Display 64 | pipeline = VisualisationPipeline(mappers=[mapper]) 65 | pipeline.run() 66 | 67 | # Apply a translation transform 68 | transform = vtk.vtkTransform() 69 | transform.Scale(2.0, 1.0, 1.0) # Double the size along the x-axis 70 | transform.RotateZ(45.0) # Rotate 45 degrees about the z-axis 71 | vtk_data = transform_grid(vtk_data, transform) 72 | 73 | # Write VTK file 74 | write_vtk(vtk_data, "test.vtk") 75 | -------------------------------------------------------------------------------- /src/04_input_output/io_vtm.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | from src.common.simple_pipeline import VisualisationPipeline 4 | 5 | FILE_NAME = "../../data/vtms/grid_of_triangles.vtm" 6 | 7 | 8 | def write_vtm(data: vtk.vtkMultiBlockDataSet, filename: str): 9 | writer = vtk.vtkXMLMultiBlockDataWriter() 10 | writer.SetFileName(filename) 11 | writer.SetInputData(data) 12 | writer.Write() 13 | 14 | 15 | def read_vtm(filename: str) -> vtk.vtkMultiBlockDataSet: 16 | reader = vtk.vtkXMLMultiBlockDataReader() 17 | reader.SetFileName(filename) 18 | reader.Update() 19 | return reader.GetOutput() 20 | 21 | 22 | def print_dataset_info(dataset: vtk.vtkMultiBlockDataSet): 23 | for i in range(dataset.GetNumberOfBlocks()): 24 | block = dataset.GetBlock(i) 25 | if block: 26 | point_data = block.GetPointData() 27 | cell_data = block.GetCellData() 28 | 29 | print(f"Block {i}:") 30 | print(f" Number of point data arrays: {point_data.GetNumberOfArrays()}") 31 | for j in range(point_data.GetNumberOfArrays()): 32 | array = point_data.GetArray(j) 33 | print(f" Point data array {j}: {point_data.GetArrayName(j)}") 34 | print(f" Number of components: {array.GetNumberOfComponents()}") 35 | print(f" Number of tuples: {array.GetNumberOfTuples()}") 36 | print(f" Range: {array.GetRange()}") 37 | 38 | print(f" Number of cell data arrays: {cell_data.GetNumberOfArrays()}") 39 | for j in range(cell_data.GetNumberOfArrays()): 40 | array = cell_data.GetArray(j) 41 | print(f" Cell data array {j}: {cell_data.GetArrayName(j)}") 42 | print(f" Number of components: {array.GetNumberOfComponents()}") 43 | print(f" Number of tuples: {array.GetNumberOfTuples()}") 44 | print(f" Range: {array.GetRange()}") 45 | 46 | 47 | if __name__ == "__main__": 48 | 49 | # Read VTM file 50 | vtm_data = read_vtm(FILE_NAME) 51 | 52 | # Print dataset info 53 | print_dataset_info(vtm_data) 54 | 55 | # Use vtkCompositeDataGeometryFilter to convert the multiblock dataset to polydata 56 | geometryFilter = vtk.vtkCompositeDataGeometryFilter() 57 | geometryFilter.SetInputDataObject(vtm_data) 58 | geometryFilter.Update() 59 | 60 | # Create a mapper and actor for the polydata 61 | mapper = vtk.vtkPolyDataMapper() 62 | mapper.SetInputConnection(geometryFilter.GetOutputPort()) 63 | 64 | # Display 65 | pipeline = VisualisationPipeline(mappers=[mapper]) 66 | pipeline.run() 67 | 68 | # Write VTM file 69 | write_vtm(vtm_data, "test.vtm") 70 | -------------------------------------------------------------------------------- /src/04_input_output/io_vtu.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | from src.common.simple_pipeline import VisualisationPipeline 4 | 5 | FILE_NAME = "../../data/vtus/grid_of_triangles.vtu" 6 | 7 | 8 | def write_vtu(data: vtk.vtkUnstructuredGrid, filename: str): 9 | writer = vtk.vtkXMLUnstructuredGridWriter() 10 | writer.SetFileName(filename) 11 | writer.SetInputData(data) 12 | writer.Write() 13 | 14 | 15 | def read_vtu(filename: str) -> vtk.vtkUnstructuredGrid: 16 | reader = vtk.vtkXMLUnstructuredGridReader() 17 | reader.SetFileName(filename) 18 | reader.Update() 19 | return reader.GetOutput() 20 | 21 | 22 | def transform_grid(grid: vtk.vtkUnstructuredGrid, transform: vtk.vtkTransform): 23 | transform_filter = vtk.vtkTransformFilter() 24 | transform_filter.SetInputData(grid) 25 | transform_filter.SetTransform(transform) 26 | transform_filter.Update() 27 | return transform_filter.GetOutput() 28 | 29 | 30 | def print_dataset_info(dataset: vtk.vtkUnstructuredGrid): 31 | point_data = dataset.GetPointData() 32 | cell_data = dataset.GetCellData() 33 | 34 | print(f"Number of point data arrays: {point_data.GetNumberOfArrays()}") 35 | for j in range(point_data.GetNumberOfArrays()): 36 | array = point_data.GetArray(j) 37 | print(f" Point data array {j}: {point_data.GetArrayName(j)}") 38 | print(f" Number of components: {array.GetNumberOfComponents()}") 39 | print(f" Number of tuples: {array.GetNumberOfTuples()}") 40 | print(f" Range: {array.GetRange()}") 41 | 42 | print(f"Number of cell data arrays: {cell_data.GetNumberOfArrays()}") 43 | for j in range(cell_data.GetNumberOfArrays()): 44 | array = cell_data.GetArray(j) 45 | print(f" Cell data array {j}: {cell_data.GetArrayName(j)}") 46 | print(f" Number of components: {array.GetNumberOfComponents()}") 47 | print(f" Number of tuples: {array.GetNumberOfTuples()}") 48 | print(f" Range: {array.GetRange()}") 49 | 50 | 51 | if __name__ == "__main__": 52 | 53 | # Read VTU file 54 | vtu_data = read_vtu(FILE_NAME) 55 | 56 | # Print dataset info 57 | print_dataset_info(vtu_data) 58 | 59 | # Display for verification 60 | mapper = vtk.vtkDataSetMapper() 61 | mapper.SetInputData(vtu_data) 62 | 63 | # Display 64 | pipeline = VisualisationPipeline(mappers=[mapper]) 65 | pipeline.run() 66 | 67 | # Apply a translation transform 68 | transform = vtk.vtkTransform() 69 | transform.Scale(2.0, 1.0, 1.0) # Double the size along the x-axis 70 | transform.RotateZ(45.0) # Rotate 45 degrees about the z-axis 71 | vtu_data = transform_grid(vtu_data, transform) 72 | 73 | # Write VTU file 74 | write_vtu(vtu_data, "test.vtu") 75 | -------------------------------------------------------------------------------- /src/05_data_conversion/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/05_data_conversion/__init__.py -------------------------------------------------------------------------------- /src/05_data_conversion/converter_interface.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | 4 | class Converter(ABC): 5 | @abstractmethod 6 | def convert(self, input_filename: str, output_filename: str): 7 | pass 8 | -------------------------------------------------------------------------------- /src/05_data_conversion/stl_obj.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import logging 3 | from converter_interface import Converter 4 | 5 | 6 | class StlToObjConverter(Converter): 7 | def convert(self, input_filename: str, output_filename: str): 8 | if not input_filename or not output_filename: 9 | raise ValueError("Input and output filenames must be provided.") 10 | 11 | if not ( 12 | input_filename.lower().endswith(".stl") 13 | and output_filename.lower().endswith(".obj") 14 | ): 15 | raise ValueError("Invalid file extensions. Expected '.stl' and '.obj'.") 16 | 17 | try: 18 | # Read STL File 19 | reader = vtk.vtkSTLReader() 20 | reader.SetFileName(input_filename) 21 | reader.Update() 22 | 23 | # Write OBJ File 24 | writer = vtk.vtkOBJWriter() 25 | writer.SetFileName(output_filename) 26 | writer.SetInputConnection(reader.GetOutputPort()) 27 | writer.Write() 28 | logging.info( 29 | f"Conversion successful: {input_filename} to {output_filename}" 30 | ) 31 | except Exception as e: 32 | logging.error(f"Error during conversion: {e}") 33 | raise 34 | 35 | 36 | class ObjToStlConverter(Converter): 37 | def convert(self, input_filename: str, output_filename: str): 38 | if not input_filename or not output_filename: 39 | raise ValueError("Input and output filenames must be provided.") 40 | 41 | if not ( 42 | input_filename.lower().endswith(".obj") 43 | and output_filename.lower().endswith(".stl") 44 | ): 45 | raise ValueError("Invalid file extensions. Expected '.obj' and '.stl'.") 46 | 47 | try: 48 | # Read OBJ File 49 | reader = vtk.vtkOBJReader() 50 | reader.SetFileName(input_filename) 51 | reader.Update() 52 | 53 | # Write STL File 54 | writer = vtk.vtkSTLWriter() 55 | writer.SetFileName(output_filename) 56 | writer.SetInputConnection(reader.GetOutputPort()) 57 | writer.Write() 58 | logging.info( 59 | f"Conversion successful: {input_filename} to {output_filename}" 60 | ) 61 | except Exception as e: 62 | logging.error(f"Error during conversion: {e}") 63 | raise 64 | -------------------------------------------------------------------------------- /src/05_data_conversion/stl_vtk.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import logging 3 | from converter_interface import Converter 4 | 5 | 6 | class VtkToStlConverter(Converter): 7 | def convert(self, input_filename: str, output_filename: str): 8 | if not input_filename or not output_filename: 9 | raise ValueError("Input and output filenames must be provided.") 10 | 11 | if not ( 12 | input_filename.lower().endswith(".vtk") 13 | and output_filename.lower().endswith(".stl") 14 | ): 15 | raise ValueError("Invalid file extensions. Expected '.vtk' and '.stl'.") 16 | 17 | try: 18 | # Read VTK File 19 | reader = vtk.vtkGenericDataObjectReader() 20 | reader.SetFileName(input_filename) 21 | reader.Update() 22 | 23 | # Write STL File 24 | writer = vtk.vtkSTLWriter() 25 | writer.SetFileName(output_filename) 26 | writer.SetInputConnection(reader.GetOutputPort()) 27 | writer.Write() 28 | logging.info( 29 | f"Conversion successful: {input_filename} to {output_filename}" 30 | ) 31 | except Exception as e: 32 | logging.error(f"Error during conversion: {e}") 33 | raise 34 | 35 | 36 | class StlToVtkConverter(Converter): 37 | def convert(self, input_filename: str, output_filename: str): 38 | if not input_filename or not output_filename: 39 | raise ValueError("Input and output filenames must be provided.") 40 | 41 | if not ( 42 | input_filename.lower().endswith(".stl") 43 | and output_filename.lower().endswith(".vtk") 44 | ): 45 | raise ValueError("Invalid file extensions. Expected '.stl' and '.vtk'.") 46 | 47 | try: 48 | # Read STL File 49 | reader = vtk.vtkSTLReader() 50 | reader.SetFileName(input_filename) 51 | reader.Update() 52 | 53 | # Write VTK File 54 | writer = vtk.vtkPolyDataWriter() 55 | writer.SetFileName(output_filename) 56 | writer.SetInputConnection(reader.GetOutputPort()) 57 | writer.Write() 58 | logging.info( 59 | f"Conversion successful: {input_filename} to {output_filename}" 60 | ) 61 | except Exception as e: 62 | logging.error(f"Error during conversion: {e}") 63 | raise 64 | -------------------------------------------------------------------------------- /src/05_data_conversion/vtk_obj.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import logging 3 | from converter_interface import Converter 4 | 5 | 6 | class VtkToObjConverter(Converter): 7 | def convert(self, input_filename: str, output_filename: str): 8 | if not input_filename or not output_filename: 9 | raise ValueError("Input and output filenames must be provided.") 10 | 11 | if not ( 12 | input_filename.lower().endswith(".vtk") 13 | and output_filename.lower().endswith(".obj") 14 | ): 15 | raise ValueError("Invalid file extensions. Expected '.vtk' and '.obj'.") 16 | 17 | try: 18 | # Read VTK File 19 | reader = vtk.vtkGenericDataObjectReader() 20 | reader.SetFileName(input_filename) 21 | reader.Update() 22 | 23 | # Write OBJ File 24 | writer = vtk.vtkOBJWriter() 25 | writer.SetFileName(output_filename) 26 | writer.SetInputConnection(reader.GetOutputPort()) 27 | writer.Write() 28 | logging.info( 29 | f"Conversion successful: {input_filename} to {output_filename}" 30 | ) 31 | except Exception as e: 32 | logging.error(f"Error during conversion: {e}") 33 | raise 34 | 35 | 36 | class ObjToVtkConverter(Converter): 37 | def convert(self, input_filename: str, output_filename: str): 38 | if not input_filename or not output_filename: 39 | raise ValueError("Input and output filenames must be provided.") 40 | 41 | if not ( 42 | input_filename.lower().endswith(".obj") 43 | and output_filename.lower().endswith(".vtk") 44 | ): 45 | raise ValueError("Invalid file extensions. Expected '.obj' and '.vtk'.") 46 | 47 | try: 48 | # Read OBJ File 49 | reader = vtk.vtkOBJReader() 50 | reader.SetFileName(input_filename) 51 | reader.Update() 52 | 53 | # Write VTK File 54 | writer = vtk.vtkDataSetWriter() 55 | writer.SetFileName(output_filename) 56 | writer.SetInputConnection(reader.GetOutputPort()) 57 | writer.Write() 58 | logging.info( 59 | f"Conversion successful: {input_filename} to {output_filename}" 60 | ) 61 | except Exception as e: 62 | logging.error(f"Error during conversion: {e}") 63 | raise 64 | -------------------------------------------------------------------------------- /src/05_data_conversion/vtk_vtm.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import logging 3 | from converter_interface import Converter 4 | 5 | 6 | class VtkToVtmConverter(Converter): 7 | def convert(self, input_filename: str, output_filename: str): 8 | if not input_filename or not output_filename: 9 | raise ValueError("Input and output filenames must be provided.") 10 | 11 | if not ( 12 | input_filename.lower().endswith(".vtk") 13 | and output_filename.lower().endswith(".vtm") 14 | ): 15 | raise ValueError("Invalid file extensions. Expected '.vtk' and '.vtm'.") 16 | 17 | try: 18 | # Read VTK File 19 | reader = vtk.vtkGenericDataObjectReader() 20 | reader.SetFileName(input_filename) 21 | reader.Update() 22 | 23 | # Create a multiblock dataset and add the output to it 24 | mbds = vtk.vtkMultiBlockDataSet() 25 | mbds.SetNumberOfBlocks(1) 26 | mbds.SetBlock(0, reader.GetOutput()) 27 | 28 | # Write VTM File 29 | writer = vtk.vtkXMLMultiBlockDataWriter() 30 | writer.SetFileName(output_filename) 31 | writer.SetInputData(mbds) 32 | writer.Write() 33 | logging.info( 34 | f"Conversion successful: {input_filename} to {output_filename}" 35 | ) 36 | except Exception as e: 37 | logging.error(f"Error during conversion: {e}") 38 | raise 39 | 40 | 41 | class VtmToVtkConverter(Converter): 42 | def convert(self, input_filename: str, output_filename: str): 43 | if not input_filename or not output_filename: 44 | raise ValueError("Input and output filenames must be provided.") 45 | 46 | if not ( 47 | input_filename.lower().endswith(".vtm") 48 | and output_filename.lower().endswith(".vtk") 49 | ): 50 | raise ValueError("Invalid file extensions. Expected '.vtm' and '.vtk'.") 51 | 52 | try: 53 | # Read VTM File 54 | reader = vtk.vtkXMLMultiBlockDataReader() 55 | reader.SetFileName(input_filename) 56 | reader.Update() 57 | 58 | # Write VTK File 59 | writer = vtk.vtkDataSetWriter() 60 | writer.SetFileName(output_filename) 61 | writer.SetInputConnection(reader.GetOutputPort()) 62 | writer.Write() 63 | logging.info( 64 | f"Conversion successful: {input_filename} to {output_filename}" 65 | ) 66 | except Exception as e: 67 | logging.error(f"Error during conversion: {e}") 68 | raise 69 | -------------------------------------------------------------------------------- /src/05_data_conversion/vtk_vtu.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import logging 3 | from converter_interface import Converter 4 | 5 | 6 | class VtkToVtuConverter(Converter): 7 | def convert(self, input_filename: str, output_filename: str): 8 | if not input_filename or not output_filename: 9 | raise ValueError("Input and output filenames must be provided.") 10 | 11 | if not ( 12 | input_filename.lower().endswith(".vtk") 13 | and output_filename.lower().endswith(".vtu") 14 | ): 15 | raise ValueError("Invalid file extensions. Expected '.vtk' and '.vtu'.") 16 | 17 | try: 18 | # Read VTK File 19 | reader = vtk.vtkGenericDataObjectReader() 20 | reader.SetFileName(input_filename) 21 | reader.Update() 22 | 23 | # Write VTU File 24 | writer = vtk.vtkXMLUnstructuredGridWriter() 25 | writer.SetFileName(output_filename) 26 | writer.SetInputConnection(reader.GetOutputPort()) 27 | writer.Write() 28 | logging.info( 29 | f"Conversion successful: {input_filename} to {output_filename}" 30 | ) 31 | except Exception as e: 32 | logging.error(f"Error during conversion: {e}") 33 | raise 34 | 35 | 36 | class VtuToVtkConverter(Converter): 37 | def convert(self, input_filename: str, output_filename: str): 38 | if not input_filename or not output_filename: 39 | raise ValueError("Input and output filenames must be provided.") 40 | 41 | if not ( 42 | input_filename.lower().endswith(".vtu") 43 | and output_filename.lower().endswith(".vtk") 44 | ): 45 | raise ValueError("Invalid file extensions. Expected '.vtu' and '.vtk'.") 46 | 47 | try: 48 | # Read VTU File 49 | reader = vtk.vtkXMLUnstructuredGridReader() 50 | reader.SetFileName(input_filename) 51 | reader.Update() 52 | 53 | # Write VTK File 54 | writer = vtk.vtkDataSetWriter() 55 | writer.SetFileName(output_filename) 56 | writer.SetInputConnection(reader.GetOutputPort()) 57 | writer.Write() 58 | logging.info( 59 | f"Conversion successful: {input_filename} to {output_filename}" 60 | ) 61 | except Exception as e: 62 | logging.error(f"Error during conversion: {e}") 63 | raise 64 | -------------------------------------------------------------------------------- /src/06_visualization_pipeline/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/06_visualization_pipeline/__init__.py -------------------------------------------------------------------------------- /src/06_visualization_pipeline/actor_mapper_multiple_objects.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | # create a sphere source 4 | sphereSource = vtk.vtkSphereSource() 5 | sphereSource.SetCenter(0, 0, 0) 6 | sphereSource.SetRadius(1) 7 | 8 | # create a cube source 9 | cubeSource = vtk.vtkCubeSource() 10 | cubeSource.SetCenter(2, 0, 0) 11 | cubeSource.SetXLength(1) 12 | cubeSource.SetYLength(1) 13 | cubeSource.SetZLength(1) 14 | 15 | # create mappers 16 | sphereMapper = vtk.vtkPolyDataMapper() 17 | sphereMapper.SetInputConnection(sphereSource.GetOutputPort()) 18 | 19 | cubeMapper = vtk.vtkPolyDataMapper() 20 | cubeMapper.SetInputConnection(cubeSource.GetOutputPort()) 21 | 22 | # create actors 23 | sphereActor = vtk.vtkActor() 24 | sphereActor.SetMapper(sphereMapper) 25 | 26 | cubeActor = vtk.vtkActor() 27 | cubeActor.SetMapper(cubeMapper) 28 | 29 | # create a renderer and add both actors 30 | renderer = vtk.vtkRenderer() 31 | renderer.AddActor(sphereActor) 32 | renderer.AddActor(cubeActor) 33 | 34 | # create a render window and add the renderer 35 | renderWindow = vtk.vtkRenderWindow() 36 | renderWindow.AddRenderer(renderer) 37 | 38 | # create an interactor and set it up to work with the render window 39 | interactor = vtk.vtkRenderWindowInteractor() 40 | interactor.SetRenderWindow(renderWindow) 41 | 42 | # initialize the interactor and start the rendering loop 43 | interactor.Initialize() 44 | interactor.Start() 45 | -------------------------------------------------------------------------------- /src/06_visualization_pipeline/adding_text_labels.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | # Create a sphere 4 | sphereSource = vtk.vtkSphereSource() 5 | sphereSource.SetCenter(0.0, 0.0, 0.0) 6 | sphereSource.SetRadius(0.5) 7 | 8 | # Create a mapper 9 | mapper = vtk.vtkPolyDataMapper() 10 | mapper.SetInputConnection(sphereSource.GetOutputPort()) 11 | 12 | # Create an actor 13 | actor = vtk.vtkActor() 14 | actor.SetMapper(mapper) 15 | 16 | # Create a renderer 17 | renderer = vtk.vtkRenderer() 18 | renderer.AddActor(actor) 19 | 20 | # Create a render window 21 | renderWindow = vtk.vtkRenderWindow() 22 | renderWindow.AddRenderer(renderer) 23 | 24 | # Create a text actor 25 | textActor = vtk.vtkTextActor() 26 | textActor.SetInput("This is a sphere") 27 | textActor.GetTextProperty().SetFontSize(24) 28 | textActor.GetTextProperty().SetColor(1.0, 0.0, 0.0) # Red text 29 | textActor.SetPosition(20, 20) 30 | 31 | # Add the text actor to the renderer 32 | renderer.AddActor2D(textActor) 33 | 34 | # Create an interactor 35 | interactor = vtk.vtkRenderWindowInteractor() 36 | interactor.SetRenderWindow(renderWindow) 37 | 38 | # Start the rendering loop 39 | interactor.Initialize() 40 | interactor.Start() 41 | -------------------------------------------------------------------------------- /src/06_visualization_pipeline/camera_movement.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | import vtk 4 | 5 | # Create a VTK renderer and render window 6 | renderer = vtk.vtkRenderer() 7 | render_window = vtk.vtkRenderWindow() 8 | render_window.AddRenderer(renderer) 9 | 10 | # Create a VTK render window interactor 11 | interactor = vtk.vtkRenderWindowInteractor() 12 | interactor.SetRenderWindow(render_window) 13 | 14 | # Create a VTK cone source and mapper 15 | cone_source = vtk.vtkConeSource() 16 | cone_mapper = vtk.vtkPolyDataMapper() 17 | cone_mapper.SetInputConnection(cone_source.GetOutputPort()) 18 | 19 | # Create a VTK actor and set the mapper 20 | cone_actor = vtk.vtkActor() 21 | cone_actor.SetMapper(cone_mapper) 22 | 23 | # Add the actor to the renderer 24 | renderer.AddActor(cone_actor) 25 | 26 | # Set up the camera 27 | camera = vtk.vtkCamera() 28 | renderer.SetActiveCamera(camera) 29 | 30 | # Set initial camera parameters 31 | camera.SetPosition(0, 0, 5) 32 | camera.SetFocalPoint(0, 0, 0) 33 | camera.SetViewUp(0, 1, 0) 34 | 35 | # Define camera animation parameters 36 | num_frames = 100 37 | delta_angle = 360.0 / num_frames 38 | 39 | 40 | def animate_camera(): 41 | for frame in range(num_frames): 42 | angle = frame * delta_angle 43 | rad_angle = math.radians(angle) # Convert angle to radians 44 | 45 | # Update camera position 46 | camera.SetPosition(5 * math.cos(rad_angle), 0, 5 * math.sin(rad_angle)) 47 | 48 | # Update the render window 49 | render_window.Render() 50 | 51 | 52 | animate_camera() 53 | 54 | # Start the interactor 55 | interactor.Start() 56 | -------------------------------------------------------------------------------- /src/06_visualization_pipeline/filters_in_action.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | # create a cube source 4 | cubeSource = vtk.vtkCubeSource() 5 | cubeSource.SetCenter(-2, 0, 0) # Move the cube to the left 6 | cubeSource.SetXLength(1) 7 | cubeSource.SetYLength(1) 8 | cubeSource.SetZLength(1) 9 | 10 | # create a mapper for the original cube 11 | cubeMapper = vtk.vtkPolyDataMapper() 12 | cubeMapper.SetInputConnection(cubeSource.GetOutputPort()) 13 | 14 | # create an actor for the original cube 15 | cubeActor = vtk.vtkActor() 16 | cubeActor.SetMapper(cubeMapper) 17 | 18 | # create an elevation filter 19 | elevationFilter = vtk.vtkElevationFilter() 20 | elevationFilter.SetInputConnection(cubeSource.GetOutputPort()) 21 | elevationFilter.SetLowPoint(-1, -1, -1) 22 | elevationFilter.SetHighPoint(1, 1, 1) 23 | 24 | # create a mapper for the cube after elevation filter 25 | elevationMapper = vtk.vtkPolyDataMapper() 26 | elevationMapper.SetInputConnection(elevationFilter.GetOutputPort()) 27 | elevationMapper.SetScalarRange( 28 | 0, 1 29 | ) # To use the scalar data generated from the elevation filter 30 | 31 | # create an actor for the cube after elevation filter 32 | elevationActor = vtk.vtkActor() 33 | elevationActor.SetMapper(elevationMapper) 34 | elevationActor.SetPosition(2, 0, 0) # Move this cube to the center 35 | 36 | # create a warp filter 37 | warpFilter = vtk.vtkWarpScalar() 38 | warpFilter.SetInputConnection(elevationFilter.GetOutputPort()) 39 | warpFilter.SetScaleFactor(0.5) # Modify this to increase or decrease the deformation 40 | 41 | # create a mapper for the cube after warp filter 42 | warpMapper = vtk.vtkPolyDataMapper() 43 | warpMapper.SetInputConnection(warpFilter.GetOutputPort()) 44 | warpMapper.SetScalarRange( 45 | 0, 1 46 | ) # To use the scalar data generated from the elevation filter 47 | 48 | # create an actor for the cube after warp filter 49 | warpActor = vtk.vtkActor() 50 | warpActor.SetMapper(warpMapper) 51 | warpActor.SetPosition(4, 0, 0) # Move this cube to the right 52 | 53 | # create a renderer and add the actors 54 | renderer = vtk.vtkRenderer() 55 | renderer.AddActor(cubeActor) 56 | renderer.AddActor(elevationActor) 57 | renderer.AddActor(warpActor) 58 | 59 | # create a render window and add the renderer 60 | renderWindow = vtk.vtkRenderWindow() 61 | renderWindow.AddRenderer(renderer) 62 | 63 | # create an interactor and set it up to work with the render window 64 | interactor = vtk.vtkRenderWindowInteractor() 65 | interactor.SetRenderWindow(renderWindow) 66 | 67 | # initialize the interactor and start the rendering loop 68 | interactor.Initialize() 69 | interactor.Start() 70 | -------------------------------------------------------------------------------- /src/06_visualization_pipeline/lighting_and_shadows.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | 4 | def create_scene(): 5 | # Create a renderer and render window 6 | renderer = vtk.vtkRenderer() 7 | render_window = vtk.vtkRenderWindow() 8 | render_window.AddRenderer(renderer) 9 | render_window.SetSize(800, 600) 10 | 11 | # Create an interactor 12 | interactor = vtk.vtkRenderWindowInteractor() 13 | interactor.SetRenderWindow(render_window) 14 | 15 | # Create a light source 16 | light = vtk.vtkLight() 17 | light.SetFocalPoint(0, 0, 0) 18 | light.SetPosition(0, 0, 10) 19 | light.SetColor(1.0, 1.0, 1.0) 20 | renderer.AddLight(light) 21 | 22 | # Create a sphere 23 | sphere_source = vtk.vtkSphereSource() 24 | sphere_source.SetRadius(1.0) 25 | sphere_mapper = vtk.vtkPolyDataMapper() 26 | sphere_mapper.SetInputConnection(sphere_source.GetOutputPort()) 27 | sphere_actor = vtk.vtkActor() 28 | sphere_actor.SetMapper(sphere_mapper) 29 | sphere_actor.GetProperty().SetColor(1.0, 0.0, 0.0) # Set sphere color to red 30 | sphere_actor.SetPosition(-1.5, 0, 0) # Set sphere position 31 | renderer.AddActor(sphere_actor) 32 | 33 | # Create a cube 34 | cube_source = vtk.vtkCubeSource() 35 | cube_source.SetXLength(1.0) 36 | cube_source.SetYLength(1.0) 37 | cube_source.SetZLength(1.0) 38 | cube_mapper = vtk.vtkPolyDataMapper() 39 | cube_mapper.SetInputConnection(cube_source.GetOutputPort()) 40 | cube_actor = vtk.vtkActor() 41 | cube_actor.SetMapper(cube_mapper) 42 | cube_actor.GetProperty().SetColor(0.0, 1.0, 0.0) # Set cube color to green 43 | cube_actor.SetPosition(0, 0, 0) # Set cube position 44 | renderer.AddActor(cube_actor) 45 | 46 | # Create a cone 47 | cone_source = vtk.vtkConeSource() 48 | cone_source.SetHeight(2.0) 49 | cone_source.SetRadius(1.0) 50 | cone_mapper = vtk.vtkPolyDataMapper() 51 | cone_mapper.SetInputConnection(cone_source.GetOutputPort()) 52 | cone_actor = vtk.vtkActor() 53 | cone_actor.SetMapper(cone_mapper) 54 | cone_actor.GetProperty().SetColor(0.0, 0.0, 1.0) # Set cone color to blue 55 | cone_actor.SetPosition(1.5, 0, 0) # Set cone position 56 | renderer.AddActor(cone_actor) 57 | 58 | # Set camera position and orientation 59 | camera = vtk.vtkCamera() 60 | camera.SetPosition(0, -5, 5) 61 | camera.SetFocalPoint(0, 0, 0) 62 | renderer.SetActiveCamera(camera) 63 | 64 | # Set background color to black 65 | renderer.SetBackground(0.0, 0.0, 0.0) 66 | 67 | # Initialize the interactor and start the rendering loop 68 | interactor.Initialize() 69 | render_window.Render() 70 | interactor.Start() 71 | 72 | 73 | if __name__ == "__main__": 74 | create_scene() 75 | -------------------------------------------------------------------------------- /src/06_visualization_pipeline/pipeline_animation.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | # Create a cube 4 | cubeSource = vtk.vtkCubeSource() 5 | 6 | # Create a mapper and set the cube source as its input 7 | cubeMapper = vtk.vtkPolyDataMapper() 8 | cubeMapper.SetInputConnection(cubeSource.GetOutputPort()) 9 | 10 | # Create an actor and set the mapper as its input 11 | cubeActor = vtk.vtkActor() 12 | cubeActor.SetMapper(cubeMapper) 13 | 14 | # Create a renderer and add the cube actor to it 15 | renderer = vtk.vtkRenderer() 16 | renderer.AddActor(cubeActor) 17 | 18 | # Create a render window and add the renderer to it 19 | renderWindow = vtk.vtkRenderWindow() 20 | renderWindow.AddRenderer(renderer) 21 | 22 | # Create an interactor and set the render window as its input 23 | interactor = vtk.vtkRenderWindowInteractor() 24 | interactor.SetRenderWindow(renderWindow) 25 | 26 | # Initialize the interactor 27 | interactor.Initialize() 28 | 29 | # The main animation loop 30 | for i in range(360): 31 | # Rotate the cube actor 32 | cubeActor.RotateY(1) 33 | 34 | # Render the scene 35 | renderWindow.Render() 36 | 37 | # Start the interaction 38 | interactor.Start() 39 | -------------------------------------------------------------------------------- /src/06_visualization_pipeline/scalar_color_mapping.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import vtk 3 | 4 | # Create a 3D grid of points, each with a scalar value 5 | dims = (20, 20, 20) 6 | x = np.linspace(-1.0, 1.0, dims[0]) 7 | y = np.linspace(-1.0, 1.0, dims[1]) 8 | z = np.linspace(-1.0, 1.0, dims[2]) 9 | x, y, z = np.meshgrid(x, y, z, indexing="ij") 10 | 11 | # Create a scalar value for each point in the grid 12 | scalars = np.sqrt(x**2 + y**2 + z**2) 13 | 14 | # Create a structured grid object and assign the points and scalars 15 | grid = vtk.vtkStructuredGrid() 16 | grid.SetDimensions(dims) 17 | 18 | points = vtk.vtkPoints() 19 | points.SetNumberOfPoints(np.prod(dims)) 20 | 21 | for i in range(dims[0]): 22 | for j in range(dims[1]): 23 | for k in range(dims[2]): 24 | points.SetPoint( 25 | i * dims[1] * dims[2] + j * dims[2] + k, 26 | x[i, j, k], 27 | y[i, j, k], 28 | z[i, j, k], 29 | ) 30 | grid.SetPoints(points) 31 | 32 | scalarArray = vtk.vtkDoubleArray() 33 | scalarArray.SetNumberOfTuples(np.prod(dims)) 34 | for i in range(np.prod(dims)): 35 | scalarArray.SetTuple(i, (scalars.ravel()[i],)) 36 | scalarArray.SetName("Scalars") 37 | grid.GetPointData().SetScalars(scalarArray) 38 | 39 | # Create a mapper and set the scalar range to the range of our scalar data 40 | mapper = vtk.vtkDataSetMapper() 41 | mapper.SetInputData(grid) 42 | mapper.SetScalarModeToUsePointData() 43 | mapper.SetScalarRange(scalars.min(), scalars.max()) 44 | 45 | # Create an actor 46 | actor = vtk.vtkActor() 47 | actor.SetMapper(mapper) 48 | 49 | # Create a renderer, add the actor to it 50 | renderer = vtk.vtkRenderer() 51 | renderer.AddActor(actor) 52 | 53 | # Create a render window, add the renderer to it 54 | renderWindow = vtk.vtkRenderWindow() 55 | renderWindow.AddRenderer(renderer) 56 | 57 | # Create an interactor, add the render window to it 58 | interactor = vtk.vtkRenderWindowInteractor() 59 | interactor.SetRenderWindow(renderWindow) 60 | 61 | # Initialize the interactor and start the rendering loop 62 | interactor.Initialize() 63 | interactor.Start() 64 | -------------------------------------------------------------------------------- /src/07_interactive_widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/07_interactive_widgets/__init__.py -------------------------------------------------------------------------------- /src/07_interactive_widgets/deformation_cylinder.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import numpy as np 3 | from vtkmodules.vtkInteractionWidgets import vtkSliderWidget, vtkSliderRepresentation2D 4 | from vtkmodules.vtkFiltersSources import vtkCylinderSource 5 | from vtkmodules.vtkRenderingCore import ( 6 | vtkActor, 7 | vtkRenderer, 8 | vtkRenderWindow, 9 | vtkRenderWindowInteractor, 10 | vtkPolyDataMapper, 11 | ) 12 | from vtkmodules.vtkCommonColor import vtkNamedColors 13 | 14 | # Create the cylinder 15 | cylinder = vtkCylinderSource() 16 | cylinder.SetHeight(10) 17 | cylinder.SetRadius(2) 18 | cylinder.SetResolution(100) 19 | cylinder.Update() 20 | 21 | # Get the cylinder's points 22 | points = cylinder.GetOutput().GetPoints() 23 | 24 | # Store the original point coordinates for reference 25 | original_points = np.array( 26 | [points.GetPoint(i) for i in range(points.GetNumberOfPoints())] 27 | ) 28 | 29 | # Mapper 30 | cylinderMapper = vtkPolyDataMapper() 31 | cylinderMapper.SetInputConnection(cylinder.GetOutputPort()) 32 | 33 | # Actor 34 | cylinderActor = vtkActor() 35 | cylinderActor.SetMapper(cylinderMapper) 36 | 37 | # Renderer 38 | renderer = vtkRenderer() 39 | renderer.AddActor(cylinderActor) 40 | renderer.SetBackground(0, 0, 0) # Background color black 41 | 42 | # Render Window 43 | renderWindow = vtkRenderWindow() 44 | renderWindow.AddRenderer(renderer) 45 | renderWindow.SetSize(1200, 800) # Increased size for more space 46 | 47 | # Interactor 48 | renderWindowInteractor = vtkRenderWindowInteractor() 49 | renderWindowInteractor.SetRenderWindow(renderWindow) 50 | 51 | # Global variables to store slider values 52 | current_bending = 0 53 | current_compression = 0 54 | current_torsion = 0 55 | current_shear = 0 56 | 57 | 58 | def apply_deformation(): 59 | for i in range(points.GetNumberOfPoints()): 60 | x, y, z = original_points[i] 61 | 62 | # Apply compression along the Z-axis 63 | z = z * (1 - current_compression) 64 | 65 | # Apply bending (displacement along Y-axis based on Z, similar to image) 66 | if current_bending != 0: 67 | curvature = current_bending / 100.0 # Adjust curvature sensitivity 68 | y = y + curvature * z**2 69 | 70 | # Apply torsion (twisting, rotation around Z-axis based on Z, like a corkscrew) 71 | if current_torsion != 0: 72 | theta = current_torsion * (z / 10.0) 73 | x_new = x * np.cos(np.radians(theta)) - y * np.sin(np.radians(theta)) 74 | y_new = x * np.sin(np.radians(theta)) + y * np.cos(np.radians(theta)) 75 | x, y = x_new, y_new 76 | 77 | # Apply shear (lateral displacement along XZ-plane) 78 | x = x + current_shear * z 79 | 80 | points.SetPoint(i, x, y, z) 81 | 82 | # Update the cylinder with new point data 83 | points.Modified() 84 | renderWindow.Render() 85 | 86 | 87 | # Slider callback functions 88 | def update_bending(obj, event): 89 | global current_bending 90 | current_bending = obj.GetRepresentation().GetValue() 91 | apply_deformation() 92 | 93 | 94 | def update_compression(obj, event): 95 | global current_compression 96 | current_compression = obj.GetRepresentation().GetValue() 97 | apply_deformation() 98 | 99 | 100 | def update_torsion(obj, event): 101 | global current_torsion 102 | current_torsion = obj.GetRepresentation().GetValue() 103 | apply_deformation() 104 | 105 | 106 | def update_shear(obj, event): 107 | global current_shear 108 | current_shear = obj.GetRepresentation().GetValue() 109 | apply_deformation() 110 | 111 | 112 | # Creating Sliders 113 | def create_slider(min_val, max_val, title, y_position): 114 | sliderRep = vtkSliderRepresentation2D() 115 | sliderRep.SetMinimumValue(min_val) 116 | sliderRep.SetMaximumValue(max_val) 117 | sliderRep.SetValue(0.0) 118 | sliderRep.SetTitleText(title) 119 | sliderRep.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay() 120 | sliderRep.GetPoint1Coordinate().SetValue(0.01, y_position) # Farther to the left 121 | sliderRep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() 122 | sliderRep.GetPoint2Coordinate().SetValue( 123 | 0.3, y_position 124 | ) # Enough distance from cylinder 125 | 126 | sliderWidget = vtkSliderWidget() 127 | sliderWidget.SetInteractor(renderWindowInteractor) 128 | sliderWidget.SetRepresentation(sliderRep) 129 | sliderWidget.EnabledOn() 130 | 131 | return sliderWidget 132 | 133 | 134 | # Adjusted positions for sliders to avoid overlapping 135 | bending_slider = create_slider(-30, 30, "Bending", 0.8) 136 | bending_slider.AddObserver("EndInteractionEvent", update_bending) 137 | 138 | compression_slider = create_slider(0, 0.5, "Compression", 0.6) 139 | compression_slider.AddObserver("EndInteractionEvent", update_compression) 140 | 141 | torsion_slider = create_slider(-180, 180, "Torsion", 0.4) 142 | torsion_slider.AddObserver("EndInteractionEvent", update_torsion) 143 | 144 | shear_slider = create_slider(-1, 1, "Shear", 0.2) 145 | shear_slider.AddObserver("EndInteractionEvent", update_shear) 146 | 147 | # Start interaction 148 | renderWindow.Render() 149 | renderWindowInteractor.Start() 150 | -------------------------------------------------------------------------------- /src/07_interactive_widgets/interactive_flower_mesh.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | import numpy as np 3 | 4 | 5 | def generate_flower_mesh(petal_count: int, points_per_petal: int) -> vtk.vtkPolyData: 6 | theta = np.linspace(0, 2 * np.pi, points_per_petal) 7 | radius = np.cos(petal_count * theta) + 2 8 | 9 | points = vtk.vtkPoints() 10 | for i in range(points_per_petal): 11 | x = radius[i] * np.cos(theta[i]) 12 | y = radius[i] * np.sin(theta[i]) 13 | points.InsertNextPoint(x, y, 0) 14 | 15 | points.InsertNextPoint(0, 0, 0) 16 | 17 | polygons = vtk.vtkCellArray() 18 | for i in range(points_per_petal - 1): 19 | polygon = vtk.vtkPolygon() 20 | polygon.GetPointIds().SetNumberOfIds(3) 21 | polygon.GetPointIds().SetId(0, i) 22 | polygon.GetPointIds().SetId(1, i + 1) 23 | polygon.GetPointIds().SetId(2, points_per_petal) 24 | polygons.InsertNextCell(polygon) 25 | 26 | polygon = vtk.vtkPolygon() 27 | polygon.GetPointIds().SetNumberOfIds(3) 28 | polygon.GetPointIds().SetId(0, points_per_petal - 1) 29 | polygon.GetPointIds().SetId(1, 0) 30 | polygon.GetPointIds().SetId(2, points_per_petal) 31 | polygons.InsertNextCell(polygon) 32 | 33 | poly_data = vtk.vtkPolyData() 34 | poly_data.SetPoints(points) 35 | poly_data.SetPolys(polygons) 36 | 37 | return poly_data 38 | 39 | 40 | def update_flower_mesh( 41 | petal_count: int, points_per_petal: int, actor: vtk.vtkActor 42 | ) -> None: 43 | new_mesh = generate_flower_mesh(petal_count, points_per_petal) 44 | mapper = vtk.vtkPolyDataMapper() 45 | mapper.SetInputData(new_mesh) 46 | actor.SetMapper(mapper) 47 | 48 | 49 | def slider_callback( 50 | obj: vtk.vtkObject, 51 | event: str, 52 | petal_slider: vtk.vtkSliderWidget, 53 | points_slider: vtk.vtkSliderWidget, 54 | actor: vtk.vtkActor, 55 | render_window: vtk.vtkRenderWindow, 56 | text_actor: vtk.vtkTextActor, 57 | ) -> None: 58 | petal_count = int(petal_slider.GetRepresentation().GetValue()) 59 | points_per_petal = int(points_slider.GetRepresentation().GetValue()) 60 | update_flower_mesh(petal_count, points_per_petal, actor) 61 | text_actor.SetInput(f"Petals: {petal_count}\nPoints: {points_per_petal}") 62 | render_window.Render() 63 | 64 | 65 | def create_slider_widget( 66 | title: str, 67 | interactor: vtk.vtkRenderWindowInteractor, 68 | min_value: float, 69 | max_value: float, 70 | initial_value: float, 71 | position: list[float], 72 | ) -> vtk.vtkSliderWidget: 73 | slider_rep = vtk.vtkSliderRepresentation2D() 74 | slider_rep.SetMinimumValue(min_value) 75 | slider_rep.SetMaximumValue(max_value) 76 | slider_rep.SetValue(initial_value) 77 | slider_rep.SetTitleText(title) 78 | slider_rep.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay() 79 | slider_rep.GetPoint1Coordinate().SetValue(position[0], position[1]) 80 | slider_rep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() 81 | slider_rep.GetPoint2Coordinate().SetValue(position[2], position[3]) 82 | slider_widget = vtk.vtkSliderWidget() 83 | slider_widget.SetInteractor(interactor) 84 | slider_widget.SetRepresentation(slider_rep) 85 | slider_widget.SetAnimationModeToAnimate() 86 | slider_widget.EnabledOn() 87 | return slider_widget 88 | 89 | 90 | def rotate_flower(obj: vtk.vtkObject, event: str) -> None: 91 | actor.RotateZ(1) 92 | obj.GetRenderWindow().Render() 93 | 94 | 95 | if __name__ == "__main__": 96 | petal_count = 8 97 | points_per_petal = 80 98 | 99 | flower_mesh = generate_flower_mesh(petal_count, points_per_petal) 100 | 101 | mapper = vtk.vtkPolyDataMapper() 102 | mapper.SetInputData(flower_mesh) 103 | 104 | actor = vtk.vtkActor() 105 | actor.SetMapper(mapper) 106 | actor.GetProperty().SetEdgeVisibility(True) 107 | actor.GetProperty().SetEdgeColor(0, 0, 0) 108 | actor.GetProperty().SetColor(1, 1, 1) # Light-colored flower 109 | 110 | renderer = vtk.vtkRenderer() 111 | render_window = vtk.vtkRenderWindow() 112 | render_window.AddRenderer(renderer) 113 | render_window_interactor = vtk.vtkRenderWindowInteractor() 114 | render_window_interactor.SetRenderWindow(render_window) 115 | 116 | renderer.AddActor(actor) 117 | renderer.SetBackground(0.1, 0.1, 0.1) # Dark background 118 | 119 | text_actor = vtk.vtkTextActor() 120 | text_actor.SetInput(f"Petals: {petal_count}\nPoints: {points_per_petal}") 121 | text_actor.GetTextProperty().SetColor(1, 1, 1) # White text 122 | text_actor.GetTextProperty().SetFontSize(24) 123 | text_actor.SetPosition2(10, 40) 124 | text_actor.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() 125 | text_actor.SetPosition(0.75, 0.85) 126 | renderer.AddActor2D(text_actor) 127 | 128 | petal_slider = create_slider_widget( 129 | "Petals", render_window_interactor, 1, 20, petal_count, [0.1, 0.1, 0.4, 0.1] 130 | ) 131 | points_slider = create_slider_widget( 132 | "Points", 133 | render_window_interactor, 134 | 10, 135 | 200, 136 | points_per_petal, 137 | [0.1, 0.2, 0.4, 0.2], 138 | ) 139 | 140 | slider_callback_closure = lambda obj, event: slider_callback( 141 | obj, event, petal_slider, points_slider, actor, render_window, text_actor 142 | ) 143 | petal_slider.AddObserver("EndInteractionEvent", slider_callback_closure) 144 | points_slider.AddObserver("EndInteractionEvent", slider_callback_closure) 145 | 146 | render_window_interactor.AddObserver("TimerEvent", rotate_flower) 147 | render_window_interactor.CreateRepeatingTimer(100) 148 | 149 | render_window.Render() 150 | render_window_interactor.Start() 151 | -------------------------------------------------------------------------------- /src/07_interactive_widgets/orientation_marker.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | from vtkmodules.vtkCommonTransforms import vtkTransform 3 | from vtkmodules.vtkFiltersSources import vtkPlaneSource 4 | from vtkmodules.vtkInteractionWidgets import vtkBoxWidget 5 | from vtkmodules.vtkRenderingCore import ( 6 | vtkPolyDataMapper, 7 | vtkRenderer, 8 | vtkRenderWindow, 9 | vtkRenderWindowInteractor, 10 | ) 11 | 12 | 13 | def create_plane_actor(color: tuple) -> vtk.vtkActor: 14 | """ 15 | Create a plane actor with specified color. 16 | 17 | Args: 18 | color (tuple): A tuple of three float values representing RGB color. 19 | 20 | Returns: 21 | vtk.vtkActor: An actor representing a colored plane. 22 | """ 23 | plane = vtkPlaneSource() 24 | plane.SetXResolution(10) 25 | plane.SetYResolution(10) 26 | 27 | mapper = vtkPolyDataMapper() 28 | mapper.SetInputConnection(plane.GetOutputPort()) 29 | 30 | actor = vtk.vtkActor() 31 | actor.SetMapper(mapper) 32 | actor.GetProperty().SetColor(color) 33 | 34 | return actor 35 | 36 | 37 | def plane_widget_callback(obj, event): 38 | """ 39 | Callback function to modify the plane when the widget is manipulated. 40 | 41 | Args: 42 | obj: The object associated with the callback. 43 | event: The event triggering the callback. 44 | """ 45 | transform = vtkTransform() 46 | obj.GetTransform(transform) 47 | matrix = transform.GetMatrix() 48 | obj.GetProp3D().SetUserMatrix(matrix) 49 | 50 | 51 | def setup_interaction( 52 | plane_actor: vtk.vtkActor, render_window_interactor: vtk.vtkRenderWindowInteractor 53 | ): 54 | """ 55 | Set up interaction widget for a plane actor. 56 | 57 | Args: 58 | plane_actor (vtk.vtkActor): The plane actor to interact with. 59 | render_window_interactor (vtk.vtkRenderWindowInteractor): The render window interactor. 60 | """ 61 | plane_widget = vtkBoxWidget() 62 | plane_widget.SetInteractor(render_window_interactor) 63 | plane_widget.SetProp3D(plane_actor) 64 | plane_widget.On() 65 | plane_widget.AddObserver("InteractionEvent", plane_widget_callback) 66 | 67 | 68 | # Main execution 69 | if __name__ == "__main__": 70 | # Create two plane actors with different colors 71 | red_plane_actor = create_plane_actor((1, 0, 0)) 72 | blue_plane_actor = create_plane_actor((0, 0, 1)) 73 | 74 | # Define a vtkRenderer and add the two actors 75 | renderer = vtkRenderer() 76 | renderer.AddActor(red_plane_actor) 77 | renderer.AddActor(blue_plane_actor) 78 | 79 | # Create and set up render window and interactor 80 | render_window = vtkRenderWindow() 81 | render_window.AddRenderer(renderer) 82 | 83 | render_window_interactor = vtkRenderWindowInteractor() 84 | render_window_interactor.SetRenderWindow(render_window) 85 | 86 | # Set up interaction for both planes 87 | setup_interaction(red_plane_actor, render_window_interactor) 88 | setup_interaction(blue_plane_actor, render_window_interactor) 89 | 90 | # Initialize and start the interactor 91 | render_window_interactor.Initialize() 92 | render_window.Render() 93 | render_window_interactor.Start() 94 | -------------------------------------------------------------------------------- /src/07_interactive_widgets/simple_button.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | from src.common.button import Button2D 4 | 5 | 6 | def on_button_clicked(): 7 | print("Button clicked!") 8 | 9 | 10 | def main(): 11 | # Create a renderer, render window, and interactor 12 | renderer = vtk.vtkRenderer() 13 | renderer.SetBackground(1, 1, 1) # White background 14 | render_window = vtk.vtkRenderWindow() 15 | render_window.SetSize(300, 300) 16 | render_window.AddRenderer(renderer) 17 | interactor = vtk.vtkRenderWindowInteractor() 18 | interactor.SetRenderWindow(render_window) 19 | 20 | # Create a 2D button 21 | button = Button2D(interactor, "Click Me", (50, 50), (100, 50)) 22 | button.add_click_callback(on_button_clicked) 23 | 24 | # Start the interaction 25 | render_window.Render() 26 | interactor.Initialize() 27 | interactor.Start() 28 | 29 | 30 | if __name__ == "__main__": 31 | main() 32 | -------------------------------------------------------------------------------- /src/07_interactive_widgets/slider.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | 4 | def main(): 5 | # Create a sphere 6 | sphereSource = vtk.vtkSphereSource() 7 | sphereSource.Update() 8 | 9 | # Create a mapper 10 | mapper = vtk.vtkPolyDataMapper() 11 | mapper.SetInputConnection(sphereSource.GetOutputPort()) 12 | 13 | # Create an actor 14 | actor = vtk.vtkActor() 15 | actor.SetMapper(mapper) 16 | 17 | # Create a renderer 18 | renderer = vtk.vtkRenderer() 19 | renderer.AddActor(actor) 20 | 21 | # Create a render window 22 | renderWindow = vtk.vtkRenderWindow() 23 | renderWindow.AddRenderer(renderer) 24 | 25 | # Create a render window interactor 26 | renderWindowInteractor = vtk.vtkRenderWindowInteractor() 27 | renderWindowInteractor.SetRenderWindow(renderWindow) 28 | 29 | # Initialize the interactor and start the rendering loop 30 | renderWindow.Render() 31 | renderWindowInteractor.Initialize() 32 | 33 | # Setup picker 34 | picker = vtk.vtkCellPicker() 35 | 36 | # Create a text actor to display the cell ID 37 | textActor = vtk.vtkTextActor() 38 | textActor.SetInput("Cell ID: ") 39 | textActor.GetTextProperty().SetColor(1.0, 1.0, 1.0) # White color 40 | textActor.SetPosition(10, 10) # Position in screen coordinates 41 | renderer.AddActor(textActor) 42 | 43 | def onClick(event, obj): 44 | x, y = renderWindowInteractor.GetEventPosition() 45 | picker.Pick(x, y, 0, renderer) 46 | pickedCell = picker.GetCellId() 47 | if pickedCell != -1: 48 | textActor.SetInput(f"Cell ID: {pickedCell}") 49 | renderWindow.Render() 50 | 51 | # Add click event listener 52 | renderWindowInteractor.AddObserver("LeftButtonPressEvent", onClick) 53 | 54 | # Start interaction 55 | renderWindowInteractor.Start() 56 | 57 | 58 | if __name__ == "__main__": 59 | main() 60 | -------------------------------------------------------------------------------- /src/08_integration_with_ui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/08_integration_with_ui/__init__.py -------------------------------------------------------------------------------- /src/08_integration_with_ui/matplotlib_sphere.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import vtkmodules.all as vtk 3 | from vtkmodules.util import numpy_support 4 | 5 | 6 | def create_sphere(radius=1.0, theta_resolution=40, phi_resolution=40): 7 | # Create a sphere 8 | sphere = vtk.vtkSphereSource() 9 | sphere.SetRadius(radius) 10 | sphere.SetThetaResolution(theta_resolution) 11 | sphere.SetPhiResolution(phi_resolution) 12 | sphere.Update() 13 | return sphere 14 | 15 | 16 | def convert_vtk_to_numpy(vtk_data): 17 | # Convert vtk to numpy 18 | numpy_array = numpy_support.vtk_to_numpy(vtk_data) 19 | return numpy_array 20 | 21 | 22 | def main(): 23 | # Create a sphere 24 | sphere = create_sphere() 25 | 26 | # Convert vtk to numpy 27 | vtk_array = sphere.GetOutput().GetPoints().GetData() 28 | numpy_array = convert_vtk_to_numpy(vtk_array) 29 | 30 | # Split the numpy array into x, y, z components for 3D plotting 31 | x, y, z = numpy_array[:, 0], numpy_array[:, 1], numpy_array[:, 2] 32 | 33 | # Plot the sphere using matplotlib 34 | fig = plt.figure() 35 | ax = fig.add_subplot(111, projection="3d") 36 | ax.scatter(x, y, z, color="b", alpha=0.6, edgecolors="w", s=20) 37 | plt.show() 38 | 39 | 40 | if __name__ == "__main__": 41 | main() 42 | -------------------------------------------------------------------------------- /src/08_integration_with_ui/matplotlib_surface_plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import vtkmodules.all as vtk 4 | from mpl_toolkits.mplot3d import Axes3D 5 | 6 | # Create a grid of points for the Rosenbrock Function 7 | x = np.linspace(-5, 5, 100) 8 | y = np.linspace(-5, 5, 100) 9 | X, Y = np.meshgrid(x, y) 10 | Z = (1 - X) ** 2 + 100 * (Y - X**2) ** 2 # Rosenbrock Function 11 | 12 | 13 | def create_surface_from_grid(x, y, z): 14 | # Create a surface from the grid data 15 | points = vtk.vtkPoints() 16 | vertices = vtk.vtkCellArray() 17 | 18 | for i in range(len(x)): 19 | for j in range(len(y)): 20 | points.InsertNextPoint(x[i][j], y[i][j], z[i][j]) 21 | if i < len(x) - 1 and j < len(y) - 1: 22 | vertices.InsertNextCell(4) 23 | vertices.InsertCellPoint(i * len(y) + j) 24 | vertices.InsertCellPoint((i + 1) * len(y) + j) 25 | vertices.InsertCellPoint((i + 1) * len(y) + (j + 1)) 26 | vertices.InsertCellPoint(i * len(y) + (j + 1)) 27 | 28 | grid = vtk.vtkPolyData() 29 | grid.SetPoints(points) 30 | grid.SetPolys(vertices) 31 | return grid 32 | 33 | 34 | def main(): 35 | # Create a surface from the grid data 36 | surface = create_surface_from_grid(X, Y, Z) 37 | 38 | # Create a Matplotlib 3D plot 39 | fig = plt.figure() 40 | ax = fig.add_subplot(111, projection="3d") 41 | 42 | # Plot the surface 43 | ax.plot_surface( 44 | X, Y, Z, cmap="viridis", rstride=1, cstride=1, linewidth=0, antialiased=False 45 | ) 46 | 47 | # Customize the plot (add labels, title, etc.) 48 | ax.set_xlabel("X") 49 | ax.set_ylabel("Y") 50 | ax.set_zlabel("Z") 51 | ax.set_title("Rosenbrock Function") 52 | 53 | # Show the plot 54 | plt.show() 55 | 56 | 57 | if __name__ == "__main__": 58 | main() 59 | -------------------------------------------------------------------------------- /src/08_integration_with_ui/qt_sphere.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import vtkmodules.all as vtk 4 | from PyQt6 import QtCore 5 | from PyQt6.QtWidgets import ( 6 | QApplication, 7 | QColorDialog, 8 | QMainWindow, 9 | QPushButton, 10 | QSlider, 11 | QVBoxLayout, 12 | QWidget, 13 | ) 14 | from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor 15 | 16 | 17 | class CustomActor(vtk.vtkActor): 18 | def __init__(self, source=None): 19 | super().__init__() 20 | self.source = source or vtk.vtkSphereSource() 21 | self.color = (0.1, 0.8, 0.5) # Default color 22 | self.update_mapper() 23 | 24 | def update_mapper(self): 25 | mapper = vtk.vtkPolyDataMapper() 26 | mapper.SetInputConnection(self.source.GetOutputPort()) 27 | self.SetMapper(mapper) 28 | self.SetPosition(0.2, 0.2, 0.6) 29 | self.GetProperty().SetColor(self.color) 30 | 31 | def update_radius(self, radius): 32 | self.source.SetRadius(radius) 33 | self.source.Update() 34 | self.update_mapper() 35 | 36 | def update_color(self, color): 37 | self.color = (color.redF(), color.greenF(), color.blueF()) 38 | self.GetProperty().SetColor(self.color) 39 | 40 | 41 | class VtkDisplay(QWidget): 42 | def __init__(self, parent=None): 43 | super().__init__(parent) 44 | 45 | layout = QVBoxLayout(self) 46 | self.vtk_display = QVTKRenderWindowInteractor(self) 47 | layout.addWidget(self.vtk_display) 48 | 49 | self.slider = QSlider(QtCore.Qt.Orientation.Horizontal) 50 | self.slider.setMinimum(1) 51 | self.slider.setMaximum(10) 52 | self.slider.setValue(1) 53 | layout.addWidget(self.slider) 54 | 55 | self.color_button = QPushButton("Change color") 56 | layout.addWidget(self.color_button) 57 | 58 | self.renderer = vtk.vtkRenderer() 59 | self.vtk_display.GetRenderWindow().AddRenderer(self.renderer) 60 | self.interactor = self.vtk_display.GetRenderWindow().GetInteractor() 61 | 62 | self.actor = CustomActor() 63 | self.renderer.AddActor(self.actor) 64 | 65 | self.slider.valueChanged.connect(self.change_radius) 66 | self.color_button.clicked.connect(self.change_color) 67 | 68 | self.renderer.ResetCamera() 69 | self.interactor.Initialize() 70 | 71 | def change_radius(self, value): 72 | self.actor.update_radius(value / 12) 73 | self.vtk_display.GetRenderWindow().Render() 74 | 75 | def change_color(self): 76 | color = QColorDialog.getColor() 77 | if color.isValid(): 78 | self.actor.update_color(color) 79 | self.vtk_display.GetRenderWindow().Render() 80 | 81 | 82 | if __name__ == "__main__": 83 | app = QApplication(sys.argv) 84 | window = QMainWindow() 85 | widget = VtkDisplay() 86 | window.setCentralWidget(widget) 87 | window.show() 88 | sys.exit(app.exec()) 89 | -------------------------------------------------------------------------------- /src/08_integration_with_ui/spark_vtk_workflow.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import numpy as np 4 | import pandas as pd 5 | import vtk 6 | from vtk.util import numpy_support 7 | import logging 8 | 9 | # Configure logging 10 | logging.basicConfig( 11 | level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" 12 | ) 13 | logger = logging.getLogger(__name__) 14 | 15 | 16 | def check_environment(): 17 | """Check if the environment is properly configured.""" 18 | # Check for Java 19 | java_home = os.environ.get("JAVA_HOME") 20 | if not java_home: 21 | raise EnvironmentError( 22 | "JAVA_HOME is not set. Please install Java and set JAVA_HOME environment variable.\n" 23 | "On Ubuntu/Debian: \n" 24 | "1. sudo apt update\n" 25 | "2. sudo apt install default-jdk\n" 26 | "3. Add to ~/.bashrc:\n" 27 | " export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64\n" 28 | " (adjust path according to your Java installation)" 29 | ) 30 | 31 | # Check if Java is accessible 32 | if os.system("java -version > /dev/null 2>&1") != 0: 33 | raise EnvironmentError("Java is not accessible from command line") 34 | 35 | return True 36 | 37 | 38 | def create_sample_data_without_spark(num_points=1000): 39 | """Generate sample 3D points with a scalar value using only Pandas.""" 40 | np.random.seed(42) 41 | data = { 42 | "x": np.random.normal(0, 1, num_points), 43 | "y": np.random.normal(0, 1, num_points), 44 | "z": np.random.normal(0, 1, num_points), 45 | } 46 | df = pd.DataFrame(data) 47 | df["distance"] = np.sqrt(df["x"] ** 2 + df["y"] ** 2 + df["z"] ** 2) 48 | return df 49 | 50 | 51 | def process_data_without_spark(df): 52 | """Process data using Pandas instead of Spark.""" 53 | return df[df["distance"] < 2.0].copy() 54 | 55 | 56 | def convert_to_vtk(df): 57 | """Convert DataFrame to VTK PolyData.""" 58 | try: 59 | # Create points array 60 | points = vtk.vtkPoints() 61 | vertices = vtk.vtkCellArray() 62 | 63 | # Create array for scalar values 64 | scalars = vtk.vtkDoubleArray() 65 | scalars.SetName("Distance") 66 | 67 | # Add points and scalar values 68 | for idx, row in df.iterrows(): 69 | point_id = points.InsertNextPoint(row["x"], row["y"], row["z"]) 70 | scalars.InsertNextValue(row["distance"]) 71 | 72 | # Create a vertex cell for each point 73 | vertex = vtk.vtkVertex() 74 | vertex.GetPointIds().SetId(0, point_id) 75 | vertices.InsertNextCell(vertex) 76 | 77 | # Create PolyData 78 | polydata = vtk.vtkPolyData() 79 | polydata.SetPoints(points) 80 | polydata.SetVerts(vertices) 81 | polydata.GetPointData().SetScalars(scalars) 82 | 83 | return polydata 84 | except Exception as e: 85 | logger.error(f"Error in converting to VTK: {str(e)}") 86 | raise 87 | 88 | 89 | def visualize_vtk(polydata): 90 | """Create a basic VTK visualization.""" 91 | try: 92 | # Create mapper and actor 93 | mapper = vtk.vtkPolyDataMapper() 94 | mapper.SetInputData(polydata) 95 | mapper.ScalarVisibilityOn() 96 | mapper.SetScalarRange(polydata.GetPointData().GetScalars().GetRange()) 97 | 98 | actor = vtk.vtkActor() 99 | actor.SetMapper(mapper) 100 | 101 | # Create renderer and window 102 | renderer = vtk.vtkRenderer() 103 | renderer.AddActor(actor) 104 | renderer.SetBackground(0.1, 0.1, 0.1) 105 | 106 | window = vtk.vtkRenderWindow() 107 | window.AddRenderer(renderer) 108 | window.SetSize(800, 600) 109 | 110 | # Add interactor 111 | interactor = vtk.vtkRenderWindowInteractor() 112 | interactor.SetRenderWindow(window) 113 | 114 | # Initialize and start 115 | interactor.Initialize() 116 | window.Render() 117 | interactor.Start() 118 | except Exception as e: 119 | logger.error(f"Error in visualization: {str(e)}") 120 | raise 121 | 122 | 123 | def main(): 124 | try: 125 | logger.info("Starting data processing and visualization workflow") 126 | 127 | # Create and process data using Pandas 128 | logger.info("Generating sample data") 129 | df = create_sample_data_without_spark() 130 | 131 | logger.info("Processing data") 132 | processed_df = process_data_without_spark(df) 133 | 134 | # Save to parquet (optional) 135 | parquet_path = "processed_data.parquet" 136 | logger.info(f"Saving data to {parquet_path}") 137 | processed_df.to_parquet(parquet_path) 138 | 139 | # Convert to VTK 140 | logger.info("Converting data to VTK format") 141 | vtk_data = convert_to_vtk(processed_df) 142 | 143 | # Visualize 144 | logger.info("Starting visualization") 145 | visualize_vtk(vtk_data) 146 | 147 | # Clean up 148 | if os.path.exists(parquet_path): 149 | os.remove(parquet_path) 150 | logger.info("Cleaned up temporary files") 151 | 152 | except Exception as e: 153 | logger.error(f"An error occurred: {str(e)}") 154 | sys.exit(1) 155 | 156 | 157 | if __name__ == "__main__": 158 | try: 159 | # Check environment before running 160 | check_environment() 161 | main() 162 | except EnvironmentError as e: 163 | logger.error(f"Environment configuration error: {str(e)}") 164 | sys.exit(1) 165 | except Exception as e: 166 | logger.error(f"Unexpected error: {str(e)}") 167 | sys.exit(1) 168 | -------------------------------------------------------------------------------- /src/09_cfd/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/09_cfd/__init__.py -------------------------------------------------------------------------------- /src/09_cfd/fluid_flow_simulator.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import vtk 4 | from vtkmodules.util import numpy_support 5 | 6 | 7 | def initialize_grid(l, h, dx, dy, u0): 8 | nx, ny = int(l / dx), int(h / dy) 9 | x, y = np.arange(0, l + dx, dx), np.arange(0, h + dy, dy) 10 | u = u0 * np.ones((ny + 1, nx + 1)) 11 | u[0, :] = u[-1, :] = 0 # No-slip boundary condition 12 | p = np.zeros((ny + 1, nx + 1)) 13 | return x, y, u, p, nx, ny 14 | 15 | 16 | def update_velocity(u, p, rho, mu, dx, dy, dt, ua, nx, ny): 17 | bmax = 0 18 | u_new = np.copy(u) 19 | 20 | # Compute velocity field 21 | for i in range(1, ny): 22 | for j in range(1, nx): 23 | # Compute pressure gradient 24 | dpdx = (p[i, j - 1] - p[i, j + 1]) / (2 * dx) 25 | dpdy = (p[i - 1, j] - p[i + 1, j]) / (2 * dy) 26 | 27 | # Compute viscous term 28 | viscous_term_x = mu * (u[i, j + 1] - 2 * u[i, j] + u[i, j - 1]) / dx**2 29 | viscous_term_y = mu * (u[i + 1, j] - 2 * u[i, j] + u[i - 1, j]) / dy**2 30 | 31 | # Update velocity 32 | u_new[i, j] = u[i, j] + dt * ( 33 | -u[i, j] * dpdx + viscous_term_x - dpdy + viscous_term_y 34 | ) 35 | 36 | # Update max change for convergence check 37 | bmax = max(bmax, abs(u_new[i, j] - u[i, j])) 38 | 39 | return u_new, bmax 40 | 41 | 42 | def create_points(x, y, u): 43 | points = vtk.vtkPoints() 44 | velocity_values = vtk.vtkFloatArray() 45 | velocity_values.SetName("Velocity") 46 | 47 | nx, ny = len(x), len(y) 48 | for j in range(ny): 49 | for i in range(nx): 50 | points.InsertNextPoint(x[i], y[j], 0) 51 | velocity_values.InsertNextValue(u[j, i]) # Ensure correct indexing 52 | 53 | return points, velocity_values 54 | 55 | 56 | # Create vtkPolyData for visualization 57 | def create_poly_data(nx, ny, points, velocity_values): 58 | polyData = vtk.vtkPolyData() 59 | polyData.SetPoints(points) 60 | 61 | cells = vtk.vtkCellArray() 62 | for i in range(ny - 1): 63 | for j in range(nx - 1): 64 | quad = vtk.vtkQuad() 65 | quad.GetPointIds().SetId(0, i * nx + j) 66 | quad.GetPointIds().SetId(1, (i + 1) * nx + j) 67 | quad.GetPointIds().SetId(2, (i + 1) * nx + (j + 1)) 68 | quad.GetPointIds().SetId(3, i * nx + (j + 1)) 69 | cells.InsertNextCell(quad) 70 | 71 | polyData.SetPolys(cells) 72 | polyData.GetPointData().SetScalars(velocity_values) 73 | 74 | return polyData 75 | 76 | 77 | # Create a color map for VTK visualization 78 | def create_color_map(u): 79 | color_map = vtk.vtkLookupTable() 80 | min_val, max_val = np.min(u), np.max(u) 81 | color_map.SetRange(min_val, max_val) 82 | color_map.SetHueRange(0.667, 0) # Blue to red 83 | color_map.Build() 84 | return color_map 85 | 86 | 87 | # Visualizes the velocity field using VTK 88 | def vtk_velocity_plot(x, y, snapshots): 89 | # Setup renderer and render window 90 | renderer = vtk.vtkRenderer() 91 | renderWindow = vtk.vtkRenderWindow() 92 | renderWindow.AddRenderer(renderer) 93 | 94 | # Enable user interaction with the scene 95 | renderWindowInteractor = vtk.vtkRenderWindowInteractor() 96 | renderWindowInteractor.SetRenderWindow(renderWindow) 97 | renderWindowInteractor.Initialize() 98 | 99 | # Set up interaction style for camera controls 100 | interact_style = vtk.vtkInteractorStyleTrackballCamera() 101 | renderWindowInteractor.SetInteractorStyle(interact_style) 102 | 103 | # Initialize variables to store actors 104 | surface_actor = None 105 | scalar_bar = None 106 | 107 | # Define a callback function for the timer 108 | def update_visualization(obj, event): 109 | nonlocal surface_actor, scalar_bar 110 | nonlocal snapshots 111 | 112 | # Remove the current actors 113 | if surface_actor: 114 | renderer.RemoveActor(surface_actor) 115 | renderer.RemoveActor(scalar_bar) 116 | 117 | # Stop the timer if no more snapshots are available 118 | if not snapshots: 119 | return 120 | 121 | # Get the next snapshot 122 | u_vtk = snapshots.pop(0) 123 | 124 | # Process the snapshot 125 | if isinstance(u_vtk, vtk.vtkTypeFloat32Array): 126 | u_np = numpy_support.vtk_to_numpy(u_vtk) 127 | u_np = u_np.reshape(len(y), len(x)) 128 | else: 129 | u_np = u_vtk 130 | 131 | points, velocity_values = create_points(x, y, u_np) 132 | polyData = create_poly_data(len(x), len(y), points, velocity_values) 133 | color_map = create_color_map(u_np) 134 | 135 | mapper = vtk.vtkPolyDataMapper() 136 | mapper.SetInputData(polyData) 137 | mapper.SetLookupTable(color_map) 138 | mapper.SetScalarModeToUsePointData() 139 | mapper.SetScalarRange(np.min(u_np), np.max(u_np)) 140 | 141 | # Create and add new actors 142 | surface_actor = vtk.vtkActor() 143 | surface_actor.SetMapper(mapper) 144 | scalar_bar = vtk.vtkScalarBarActor() 145 | scalar_bar.SetLookupTable(color_map) 146 | scalar_bar.SetTitle("Velocity") 147 | scalar_bar.SetNumberOfLabels(5) 148 | 149 | renderer.AddActor(surface_actor) 150 | renderer.AddActor(scalar_bar) 151 | renderer.ResetCamera() 152 | renderWindow.Render() 153 | 154 | # Add a timer to update the visualization 155 | renderWindowInteractor.AddObserver("TimerEvent", update_visualization) 156 | timerId = renderWindowInteractor.CreateRepeatingTimer(1000) # Time in milliseconds 157 | 158 | # Start the interaction 159 | renderWindow.Render() 160 | renderWindowInteractor.Start() 161 | 162 | # Clean up 163 | renderWindow.Finalize() 164 | renderWindowInteractor.TerminateApp() 165 | 166 | 167 | def main(): 168 | # Simulation parameters 169 | l, h = 20.0, 2.0 170 | dx, dy = 0.1, 0.1 171 | dt = 0.01 # Time step 172 | rho, mu, ua = 1.0, 0.01, 0.5 173 | u0 = 1.0 # Inlet velocity 174 | btol = 1e-4 # Convergence tolerance 175 | 176 | # Initialize the grid and variables 177 | x, y, u, p, nx, ny = initialize_grid(l, h, dx, dy, u0) 178 | 179 | snapshots = [] 180 | snapshot_interval = 100 # Define how often to take snapshots 181 | 182 | # Iterative solver 183 | iter_count = 0 184 | time_elapsed = 0 185 | 186 | while True: 187 | u, bmax = update_velocity(u, p, rho, mu, dx, dy, dt, ua, nx, ny) 188 | time_elapsed += dt 189 | print( 190 | f"Iteration {iter_count}, Time: {time_elapsed:.2f} s, Residual: {bmax:.6f}" 191 | ) 192 | 193 | if iter_count % snapshot_interval == 0: 194 | # Convert u to a VTK array and store it 195 | vtk_u = numpy_support.numpy_to_vtk( 196 | num_array=u.ravel(), deep=True, array_type=vtk.VTK_FLOAT 197 | ) 198 | vtk_u.SetName("Velocity") 199 | snapshots.append(vtk_u) 200 | 201 | if bmax < btol: 202 | print(f"Convergence achieved in {time_elapsed:.2f} seconds.") 203 | break 204 | 205 | iter_count += 1 206 | if iter_count > 10000: # Prevent infinite loop 207 | print("Convergence not achieved") 208 | break 209 | 210 | # Plotting the velocity field 211 | X, Y = np.meshgrid(x, y) 212 | plt.contourf(X, Y, u, levels=np.linspace(u.min(), u.max(), 20)) 213 | plt.colorbar() 214 | plt.xlabel("x (m)") 215 | plt.ylabel("y (m)") 216 | plt.title("Velocity Field") 217 | plt.show() 218 | 219 | # Post-simulation visualization 220 | vtk_velocity_plot(x, y, snapshots) 221 | 222 | 223 | if __name__ == "__main__": 224 | main() 225 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/__init__.py -------------------------------------------------------------------------------- /src/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djeada/Vtk-Examples/e9105e31800958705894eb94925ad251d2ad0117/src/common/__init__.py -------------------------------------------------------------------------------- /src/common/button.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | 4 | class Button2D: 5 | def __init__(self, interactor, label="Button", pos=(100, 100), size=(100, 40)): 6 | self.interactor = interactor 7 | self.label = label 8 | self.pos = pos 9 | self.size = size 10 | 11 | # Create the 2D button representation 12 | self.button_actor = vtk.vtkTexturedButtonRepresentation2D() 13 | self.button_actor.SetNumberOfStates(1) 14 | self.button_actor.SetPlaceFactor(1) 15 | self.button_actor.PlaceWidget( 16 | [pos[0], pos[0] + size[0], pos[1], pos[1] + size[1], 0, 0] 17 | ) 18 | 19 | # Create a texture for the button 20 | self.create_button_texture() 21 | 22 | # Create the button widget 23 | self.button_widget = vtk.vtkButtonWidget() 24 | self.button_widget.SetInteractor(interactor) 25 | self.button_widget.SetRepresentation(self.button_actor) 26 | self.button_widget.On() 27 | 28 | # Create the text label 29 | self.create_button_label() 30 | 31 | def create_button_texture(self): 32 | # Create an image for the button texture 33 | image = vtk.vtkImageData() 34 | image.SetDimensions(self.size[0], self.size[1], 1) 35 | image.AllocateScalars(vtk.VTK_UNSIGNED_CHAR, 3) 36 | 37 | # Fill the image with a color 38 | for y in range(self.size[1]): 39 | for x in range(self.size[0]): 40 | pixel = [180, 180, 180] # Light gray color 41 | image.SetScalarComponentFromFloat(x, y, 0, 0, pixel[0]) 42 | image.SetScalarComponentFromFloat(x, y, 0, 1, pixel[1]) 43 | image.SetScalarComponentFromFloat(x, y, 0, 2, pixel[2]) 44 | 45 | # Set the image directly as the button texture 46 | self.button_actor.SetButtonTexture(0, image) 47 | 48 | def create_button_label(self): 49 | # Create a text actor 50 | text_actor = vtk.vtkTextActor() 51 | text_actor.SetInput(self.label) 52 | 53 | # Adjust font size and alignment 54 | text_property = text_actor.GetTextProperty() 55 | text_property.SetFontSize( 56 | min(self.size) // 2 57 | ) # Adjust font size based on button size 58 | text_property.SetColor(0, 0, 0) # Black text 59 | text_property.SetJustificationToCentered() 60 | text_property.SetVerticalJustificationToCentered() 61 | 62 | # Estimate the vertical centering position 63 | approx_text_height = text_property.GetFontSize() * 0.5 64 | y_position = self.pos[1] + (self.size[1] - approx_text_height) / 2 65 | 66 | # Position the text in the center of the button 67 | text_actor.SetPosition(self.pos[0] + self.size[0] / 2, y_position) 68 | 69 | # Add the text actor to the renderer 70 | self.interactor.GetRenderWindow().GetRenderers().GetFirstRenderer().AddActor( 71 | text_actor 72 | ) 73 | 74 | def add_click_callback(self, callback): 75 | # Add click event listener 76 | def on_button_press(widget, event_string): 77 | callback() 78 | 79 | self.button_widget.AddObserver("StateChangedEvent", on_button_press) 80 | -------------------------------------------------------------------------------- /src/common/simple_pipeline.py: -------------------------------------------------------------------------------- 1 | import vtk 2 | 3 | 4 | class VisualisationPipeline: 5 | def __init__( 6 | self, 7 | mappers, 8 | point_size=1, 9 | edges_visible=False, 10 | background_color=(0, 0, 0), 11 | window_title="VTK Visualization", 12 | ): 13 | """ 14 | Initialize the visualization pipeline with specified parameters. 15 | 16 | Args: 17 | mappers (list of vtkPolyDataMapper): The data mappers for rendering. 18 | point_size (int): Size of points in the rendered actors. 19 | edges_visible (bool): Flag to render edges of the actors. 20 | background_color (tuple): Background color of the renderer. 21 | window_title (str): Title of the visualization window. 22 | """ 23 | self.mappers = mappers 24 | self.point_size = point_size 25 | self.edges_visible = edges_visible 26 | self.background_color = background_color 27 | self.window_title = window_title 28 | 29 | def create_actors(self): 30 | """ 31 | Create actors based on the mappers provided. 32 | 33 | Returns: 34 | list of vtkActor: List of actors for rendering. 35 | """ 36 | actors = [] 37 | for mapper in self.mappers: 38 | actor = vtk.vtkActor() 39 | actor.SetMapper(mapper) 40 | actor.GetProperty().SetPointSize(self.point_size) 41 | if self.edges_visible: 42 | actor.GetProperty().SetEdgeVisibility(1) 43 | actor.GetProperty().SetOpacity(0.5) 44 | actor.GetProperty().BackfaceCullingOn() 45 | actors.append(actor) 46 | return actors 47 | 48 | def create_renderer(self, actors): 49 | """ 50 | Create a renderer and add actors to it. 51 | 52 | Args: 53 | actors (list of vtkActor): Actors to be rendered. 54 | 55 | Returns: 56 | vtkRenderer: Configured renderer. 57 | """ 58 | renderer = vtk.vtkRenderer() 59 | for actor in actors: 60 | renderer.AddActor(actor) 61 | renderer.SetBackground(*self.background_color) 62 | return renderer 63 | 64 | def create_window(self, renderer): 65 | """ 66 | Create a rendering window. 67 | 68 | Args: 69 | renderer (vtkRenderer): Renderer to be displayed in the window. 70 | 71 | Returns: 72 | vtkRenderWindow: Configured rendering window. 73 | """ 74 | window = vtk.vtkRenderWindow() 75 | window.AddRenderer(renderer) 76 | window.SetSize(800, 600) 77 | # window.SetTitle(self.window_title) 78 | return window 79 | 80 | def create_interactor(self, window): 81 | """ 82 | Create an interactor for the rendering window. 83 | 84 | Args: 85 | window (vtkRenderWindow): Rendering window. 86 | 87 | Returns: 88 | vtkRenderWindowInteractor: Configured window interactor. 89 | """ 90 | interactor = vtk.vtkRenderWindowInteractor() 91 | interactor.SetRenderWindow(window) 92 | return interactor 93 | 94 | def run(self): 95 | """ 96 | Run the visualization pipeline. 97 | """ 98 | actors = self.create_actors() 99 | renderer = self.create_renderer(actors) 100 | window = self.create_window(renderer) 101 | interactor = self.create_interactor(window) 102 | interactor.Start() 103 | -------------------------------------------------------------------------------- /vtk_js/basic/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | 5 | -------------------------------------------------------------------------------- /vtk_js/basic/README.md: -------------------------------------------------------------------------------- 1 | 1. Install Dependencies: 2 | 3 | ``` 4 | npm install 5 | ``` 6 | 7 | 2. Build the Project: 8 | 9 | ``` 10 | npm run build 11 | ``` 12 | 13 | 3. Run the Application: 14 | 15 | ``` 16 | npm start 17 | ``` 18 | 19 | 4. Access the Application: 20 | - Open a web browser and navigate to the localhost URL provided by the server (typically http://localhost:8080). 21 | -------------------------------------------------------------------------------- /vtk_js/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | VTK.js Hello World 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /vtk_js/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vtk-js-example", 3 | "version": "1.0.0", 4 | "description": "A simple VTK.js example using @kitware/vtk.js", 5 | "main": "src/main.js", 6 | "scripts": { 7 | "build": "webpack --progress --mode=development", 8 | "start": "webpack serve --progress --mode=development --static=dist" 9 | }, 10 | "dependencies": { 11 | "@kitware/vtk.js": "^29.2.0" 12 | }, 13 | "devDependencies": { 14 | "@babel/core": "^7.23.6", 15 | "@babel/preset-env": "^7.23.6", 16 | "babel-loader": "^9.1.3", 17 | "webpack": "^5.89.0", 18 | "webpack-cli": "^5.1.4", 19 | "webpack-dev-server": "^4.15.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /vtk_js/basic/src/main.js: -------------------------------------------------------------------------------- 1 | import '@kitware/vtk.js/Rendering/Profiles/Geometry'; 2 | import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow'; 3 | import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor'; 4 | import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper'; 5 | import vtkCalculator from '@kitware/vtk.js/Filters/General/Calculator'; 6 | import vtkConeSource from '@kitware/vtk.js/Filters/Sources/ConeSource'; 7 | 8 | const fullScreenRenderWindow = vtkFullScreenRenderWindow.newInstance(); 9 | const renderer = fullScreenRenderWindow.getRenderer(); 10 | const renderWindow = fullScreenRenderWindow.getRenderWindow(); 11 | 12 | const coneSource = vtkConeSource.newInstance(); 13 | const mapper = vtkMapper.newInstance(); 14 | mapper.setInputConnection(coneSource.getOutputPort()); 15 | 16 | const actor = vtkActor.newInstance(); 17 | actor.setMapper(mapper); 18 | 19 | renderer.addActor(actor); 20 | renderer.resetCamera(); 21 | renderWindow.render(); 22 | 23 | -------------------------------------------------------------------------------- /vtk_js/basic/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | mode: 'development', 5 | entry: './src/main.js', // make sure this points to your main JavaScript file 6 | output: { 7 | path: path.resolve(__dirname, 'dist'), 8 | filename: 'bundle.js', 9 | libraryTarget: 'umd', // This exposes your bundle on different environments 10 | globalObject: 'this' // This ensures compatibility with both browser and Node environments 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /\.js$/, 16 | exclude: /node_modules/, 17 | use: { 18 | loader: 'babel-loader', 19 | options: { 20 | presets: ['@babel/preset-env'] 21 | } 22 | }, 23 | }, 24 | ], 25 | }, 26 | resolve: { 27 | extensions: ['.js'], // Add '.ts' if you are using TypeScript 28 | fallback: { 29 | "stream": require.resolve("stream-browserify"), 30 | "buffer": require.resolve("buffer") 31 | } 32 | }, 33 | }; 34 | 35 | --------------------------------------------------------------------------------