├── simpegViz ├── __init__.py ├── vtkView.py └── vtkTools.py ├── .gitignore ├── README.md ├── LICENSE └── notebooks ├── simpegViz practical test.ipynb └── Upgrading test for simpegViz.ipynb /simpegViz/__init__.py: -------------------------------------------------------------------------------- 1 | from vtkTools import vtkTools 2 | from vtkView import vtkView -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | **/*.pyc 3 | **/__pycache__/ 4 | **/.ipynb_checkpoints/ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | simpegViz 2 | ========= 3 | 4 | Visualization package for SimPEG that makes use of VTK, etc. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2014 SimPEG Developers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /notebooks/simpegViz practical test.ipynb: -------------------------------------------------------------------------------- 1 | {"nbformat_minor": 0, "cells": [{"execution_count": 1, "cell_type": "code", "source": "# Practical test of vtkViewer\nimport numpy as np, vtk\nimport SimPEG as simpeg\nimport simpegViz\nfrom glob import glob", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 2, "cell_type": "code", "source": "# Load data - UBC MT models\nworkDir = '/home/gudni/Dropbox/Work/ISOR/Hengill/MT3D/New3Dinv/TrueNorthSSc/RefineMesh'\nM = simpeg.Utils.meshutils.readUBCTensorMesh(workDir + '/reMesh1.txt')\n\nmodDict = {}\nfor mod in glob(workDir+'/run6/inv_*'):\n key = mod.split('/')[-1].replace('.con','')\n modDict[key] = simpeg.Utils.meshutils.readUBCTensorModel(mod,M)\n \n ", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 3, "cell_type": "code", "source": "# Setup the viewer\nvtkViewer = simpegViz.vtkView(M,{'C':modDict})", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": null, "cell_type": "code", "source": "vtkViewer.Show()", "outputs": [], "metadata": {"scrolled": true, "collapsed": false, "trusted": true}}, {"execution_count": 11, "cell_type": "code", "source": "# Set limits\nvtkViewer.limits = [1e-3,1]\nvtkViewer.range = [1e-3,1]", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 12, "cell_type": "code", "source": "vtkViewer.extent = [5,34,5,38,5,49]", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 14, "cell_type": "code", "source": "vtkViewer.viewprop = {'C':7}\nvtkViewer.Show()", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 9, "cell_type": "code", "source": "pl = vtkViewer._plane", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 10, "cell_type": "code", "source": "pl.GetOrigin()", "outputs": [{"execution_count": 10, "output_type": "execute_result", "data": {"text/plain": "(476320.0, 7093320.0, 0.0)"}, "metadata": {}}], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 9, "cell_type": "code", "source": "# pl.SetOrigin(np.array(vtkViewer._vtkobj.GetBounds()[0::2]) + np.array([500,0,0]))", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 11, "cell_type": "code", "source": "vtkViewer.Show()", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": null, "cell_type": "code", "source": "vtkViewer._widget.GetEnabled()", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": null, "cell_type": "code", "source": "cam = vtkViewer._ren.GetActiveCamera()\nprint cam.GetFocalPoint()\nprint cam.GetClippingRange()\nprint cam.GetPosition()", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": null, "cell_type": "code", "source": "M.vectorNx", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 12, "cell_type": "code", "source": "import tvtk\n", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 16, "cell_type": "code", "source": "from tvtk.api import tvtk", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 26, "cell_type": "code", "source": "vtk.vtkVersion.GetVTKVersion()", "outputs": [{"execution_count": 26, "output_type": "execute_result", "data": {"text/plain": "'5.10.1'"}, "metadata": {}}], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 18, "cell_type": "code", "source": "vtk.vtkUnstructuredGridReader(", "outputs": [{"execution_count": 18, "output_type": "execute_result", "data": {"text/plain": "tvtk.tvtk_classes.unstructured_grid_reader.UnstructuredGridReader"}, "metadata": {}}], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 25, "cell_type": "code", "source": "ver(buildversion)", "outputs": [{"ename": "NameError", "evalue": "name 'buildversion' is not defined", "traceback": ["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mver\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbuildversion\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mNameError\u001b[0m: name 'buildversion' is not defined"], "output_type": "error"}], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": null, "cell_type": "code", "source": "", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}], "nbformat": 4, "metadata": {"kernelspec": {"display_name": "Python 2", "name": "python2", "language": "python"}, "language_info": {"mimetype": "text/x-python", "nbconvert_exporter": "python", "version": "2.7.9", "name": "python", "file_extension": ".py", "pygments_lexer": "ipython2", "codemirror_mode": {"version": 2, "name": "ipython"}}}} -------------------------------------------------------------------------------- /notebooks/Upgrading test for simpegViz.ipynb: -------------------------------------------------------------------------------- 1 | {"nbformat_minor": 0, "cells": [{"execution_count": 1, "cell_type": "code", "source": "# Issue one.\n# The plane and the implicit widget are not working well together.", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 1, "cell_type": "code", "source": "# Manually make the widget.\nimport numpy as np, vtk\nimport SimPEG as simpeg\nimport simpegViz\nfrom glob import glob", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 2, "cell_type": "code", "source": "# Load data - UBC MT models\nworkDir = '/home/gudni/Dropbox/Work/ISOR/Hengill/MT3D/New3Dinv/TrueNorthSSc/RefineMesh'\nM = simpeg.Utils.meshutils.readUBCTensorMesh(workDir + '/reMesh1.txt')\n\nmodDict = {}\nfor mod in glob(workDir+'/run6/inv_*'):\n key = mod.split('/')[-1].replace('.con','')\n modDict[key] = simpeg.Utils.meshutils.readUBCTensorModel(mod,M)", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 3, "cell_type": "code", "source": "# Setup the viewer\nvtkViewer = simpegViz.vtkView(M,{'C':modDict})", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": 4, "cell_type": "code", "source": "# vtkViewer.Show()\nfrom tvtk.api import tvtk\ntvtkrect = tvtk.to_tvtk(vtkViewer._cells)", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 7, "cell_type": "code", "source": "def view3Dvolume(tvtkObj): \n # Make a widget\n global plane, selectActor\n plane = tvtk.Plane()\n clipper = tvtk.ClipDataSet()\n clipper.input_connection = tvtkObj.producer_port\n clipper.clip_function = plane\n clipper.inside_out\n # Make mapper and actor\n selectMapper = tvtk.DataSetMapper(input_connection = clipper.output_port)\n # The actoer\n selectActor = tvtk.LODActor(mapper = selectMapper)\n selectProp = selectActor.property\n selectProp.representation = 's'\n # Create the RenderWindow, Renderer, RenderWindowInteractor\n ren = tvtk.Renderer()\n ren.add_actor(selectActor)\n ren.background = (1, 1, 1)\n renWin = tvtk.RenderWindow(size=(400,400))\n # For some reason this doesn't work, likely a bug\n #renWin.add_renderer(ren) \n # This is a work around... Add the renderer in the vtk\n tvtk.to_vtk(renWin).AddRenderer(tvtk.to_vtk(ren))\n iren = tvtk.RenderWindowInteractor(render_window=renWin)\n tvtk.to_vtk(iren).GetInteractorStyle().SetCurrentStyleToTrackballCamera()\n # The callback function\n def movePlane(obj, event):\n global plane, selectActor\n # Don't know why, but obj is a VTK to a TVTK object\n # Use vtk method and convert plane to VTK object\n obj.GetPlane(tvtk.to_vtk(plane))\n selectActor.visibility = 1\n\n # Associate the line widget with the interactor\n planeWidget = tvtk.ImplicitPlaneWidget()\n planeWidget.interactor = iren\n planeWidget.place_factor = 1.05\n planeWidget.input = clipper.output\n planeWidget.place_widget(tvtkObj.bounds)\n planeWidget.add_observer('InteractionEvent', movePlane)\n planeWidget.enabled = 0 \n planeWidget.outside_bounds = 0\n planeWidget.scale_enabled = 0\n planeWidget.outline_translation = 0\n planeWidget.origin = np.array(tvtkObj.bounds[0::2])\n planeWidget.plane_property.opacity = 0.1\n \n # Direction widget\n nArr = tvtk.ConeSource(direction=(.0,1.0,.0),height=50,radius=10,resolution=100)\n nArrMap = tvtk.PolyDataMapper(input_connection=nArr.output_port)\n nArrAct = tvtk.Actor(mapper=nArrMap)\n\n oriWid = tvtk.OrientationMarkerWidget(key_press_activation=False)\n# oriWid.viewport = (0.01,0.01,.11,.11)\n oriWid.orientation_marker = nArrAct\n oriWid.interactor = iren\n oriWid.enabled = 1\n oriWid.on()\n # Start interaction.\n \n renWin.render()\n\n #planeWidget.on()\n iren.initialize()\n iren.start()\n\n # When done\n iren.terminate_app()\n renWin.finalize()\n del renWin, iren", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 8, "cell_type": "code", "source": "view3Dvolume(tvtkrect)", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 13, "cell_type": "code", "source": "", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": 18, "cell_type": "code", "source": "propVTK.SetR", "outputs": [{"ename": "NameError", "evalue": "name 'vtkrw' is not defined", "traceback": ["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mvtkrw\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mAddRenderer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtvtk\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto_vtk\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mren\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mNameError\u001b[0m: name 'vtkrw' is not defined"], "output_type": "error"}], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": null, "cell_type": "code", "source": "", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}, {"execution_count": null, "cell_type": "code", "source": "iren.interactor_style.set_current_style_to_trackball_actor", "outputs": [], "metadata": {"collapsed": false, "trusted": true}}, {"execution_count": null, "cell_type": "code", "source": "", "outputs": [], "metadata": {"collapsed": true, "trusted": true}}], "nbformat": 4, "metadata": {"kernelspec": {"display_name": "Python 2", "name": "python2", "language": "python"}, "language_info": {"mimetype": "text/x-python", "nbconvert_exporter": "python", "version": "2.7.9", "name": "python", "file_extension": ".py", "pygments_lexer": "ipython2", "codemirror_mode": {"version": 2, "name": "ipython"}}}} -------------------------------------------------------------------------------- /simpegViz/vtkView.py: -------------------------------------------------------------------------------- 1 | import numpy as np, matplotlib as mpl 2 | try: 3 | import vtk, vtk.util.numpy_support as npsup 4 | #import SimPEG.visualize.vtk.vtkTools as vtkSP # Always get an error for this import 5 | except Exception, e: 6 | print 'VTK import error. Please ensure you have VTK installed to use this visualization package.' 7 | import SimPEG as simpeg 8 | 9 | class vtkView(object): 10 | """ 11 | Class for storing and view of SimPEG models in VTK (visualization toolkit). 12 | 13 | Inputs: 14 | :param mesh, SimPEG mesh. 15 | :param propdict, dictionary of property models. 16 | Can have these dictionary names: 17 | 'C' - cell model; 'F' - face model; 'E' - edge model; ('V' - vector field : NOT SUPPORTED) 18 | The dictionary values are given as dictionaries with: 19 | {'NameOfThePropertyModel': np.array of the properties}. 20 | The property np.array has to be ordered in compliance with SimPEG standards. 21 | 22 | :: 23 | Example of usages. 24 | 25 | ToDo 26 | 27 | """ 28 | 29 | def __init__(self,mesh,propdict): 30 | """ 31 | """ 32 | 33 | # Setup hidden properties, used for the visualization 34 | self._ren = None 35 | self._iren = None 36 | self._renwin = None 37 | self._core = None 38 | self._vtkobj = None # Object for viewing, has threshold and exent built in 39 | self._plane = None 40 | self._clipper = None 41 | self._widget = None 42 | self._actor = None 43 | self._lut = None 44 | # Set vtk object containers 45 | self._cells = None 46 | self._faces = None 47 | self._edges = None 48 | self._vectors = None # Not implemented 49 | # Set default values 50 | self.name = 'VTK figure of SimPEG model' 51 | 52 | 53 | 54 | # Error check the input mesh 55 | if type(mesh).__name__ != 'TensorMesh': 56 | raise Exception('The input {:s} to vtkView has to be a TensorMesh object'.format(mesh)) 57 | # Set the mesh 58 | self._mesh = mesh 59 | 60 | # Read the property dictionary 61 | self._readPropertyDictionary(propdict) 62 | 63 | 64 | 65 | 66 | # Set/Get properties 67 | @property 68 | def cmap(self): 69 | ''' Colormap to use in vtkView. Colormap is a matplotlib cmap(cm) array, has to be uint8(use flag bytes=True during cmap generation).''' 70 | if getattr(self,'_cmap',None) is None: 71 | # Set default 72 | self._cmap = mpl.cm.hsv(np.arange(0.,1.,0.05),bytes=True) 73 | return self._cmap 74 | @cmap.setter 75 | def cmap(self,value): 76 | if value.min() > 0 or value.max() < 255 or value.shape[1] != 4 or value.dtype != np.uint8: 77 | raise Exception('Input not an allowed array.\n Use matplotlib.cm to generate an array of size [nrColors,4] and dtype = uint8(flag bytes=True).') 78 | self._cmap = value 79 | 80 | @property 81 | def range(self): 82 | ''' Range of the colors in vtkView.''' 83 | if getattr(self,'_range',None) is None: 84 | self._range = np.array(self._getActiveVTKobj().GetArray(self.viewprop.values()[0]).GetRange()) 85 | return self._range 86 | @range.setter 87 | def range(self,value): 88 | if type(value) not in [tuple, list, np.ndarray] or len(value) != 2 or np.array(value).dtype is not np.dtype('float'): 89 | raise Exception('Input not in correct format. \n Has to be a list, tuple or np.arry of 2 floats.') 90 | self._range = np.array(value) 91 | 92 | @property 93 | def extent(self): 94 | ''' Extent of the sub-domain of the model to view''' 95 | if getattr(self,'_extent',None) is None: 96 | self._extent = [0,self._mesh.nCx-1,0,self._mesh.nCy-1,0,self._mesh.nCz-1] 97 | return self._extent 98 | @extent.setter 99 | def extent(self,value): 100 | 101 | import warnings 102 | # Error check 103 | valnp = np.array(value,dtype=int) 104 | if valnp.dtype != int or len(valnp) != 6: 105 | raise Exception('.extent has to be list or nparray of 6 integers.') 106 | # Test the range of the values 107 | loB = np.zeros(3,dtype=int) 108 | upB = np.array(self._mesh.nC - np.ones(3),dtype=int) 109 | # Test the bounds 110 | change = 0 111 | # Test for lower bounds, can't be smaller the 0 112 | tlb = valnp[::2] < loB 113 | if tlb.any(): 114 | valnp[::2][tlb] = loB[tlb] 115 | change = 1 116 | warnings.warn('Lower bounds smaller then 0') 117 | # Test for lower bounds, can't be larger then upB 118 | tlub = valnp[::2] > upB 119 | if tlub.any(): 120 | valnp[::2][tlub] = upB[tlub] - 1 121 | change = 1 122 | warnings.warn('Lower bounds larger then uppermost bounds') 123 | # Test for upper bounds, can't be larger the extent of the mesh 124 | tub = valnp[1::2] > upB 125 | if tub.any(): 126 | valnp[1::2][tub] = upB[tub] 127 | change = 1 128 | warnings.warn('Upper bounds greater then number of cells') 129 | # Test if lower is smaller the upper 130 | tgt = valnp[::2] > valnp[1::2] 131 | if tgt.any(): 132 | valnp[1::2][tgt] = valnp[::2][tgt] + 1 133 | change = 1 134 | warnings.warn('Lower bounds greater the Upper bounds') 135 | # Print a warning 136 | if change: 137 | warnings.warn('Changed given extent from {:s} to {:s}'.format(value,valnp.tolist())) 138 | 139 | # Set extent 140 | self._extent = valnp 141 | 142 | @property 143 | def limits(self): 144 | ''' Lower and upper limits (cutoffs) of the values to view. ''' 145 | return getattr(self,'_limits',None) 146 | @limits.setter 147 | def limits(self,value): 148 | if value is None: 149 | self._limits = None 150 | else: 151 | valnp = np.array(value) 152 | if valnp.dtype != float or len(valnp) != 2: 153 | raise Exception('.limits has to be list or numpy array of 2 floats.') 154 | self._limits = valnp 155 | 156 | 157 | @property 158 | def viewprop(self): 159 | ''' Controls the property that will be viewed.''' 160 | 161 | if getattr(self,'_viewprop',None) is None: 162 | self._viewprop = {'C':0} # Name of the type and Int order of the array or name of the vector. 163 | return self._viewprop 164 | @viewprop.setter 165 | def viewprop(self,value): 166 | if type(value) != dict: 167 | raise Exception('{:s} has to be a python dictionary containing property type and name index. ') 168 | if len(value) > 1: 169 | raise Exception('Too many input items in the viewprop dictionary') 170 | if value.keys()[0] not in ['C','F','E']: 171 | raise Exception('\"{:s}\" is not allowed as a dictionary key. Can be \'C\',\'F\',\'E\'.'.format(propitem[0])) 172 | if not(type(self.viewprop.values()[0]) is int or type(self.viewprop.values()[0]) is str): 173 | raise Exception('The vtkView.viewprop.values()[0] has the wrong format. Has to be integer or a string with the index.') 174 | 175 | 176 | self._viewprop = value 177 | 178 | def _getActiveVTKobj(self): 179 | """ 180 | Finds the active VTK object. 181 | """ 182 | 183 | if self.viewprop.keys()[0] is 'C': 184 | vtkCellData = self._cells.GetCellData() 185 | elif self.viewprop.keys()[0] is 'F': 186 | vtkCellData = self._faces.GetCellData() 187 | elif self.viewprop.keys()[0] is 'E': 188 | vtkCellData = self._edges.GetCellData() 189 | 190 | return vtkCellData 191 | 192 | def _getActiveArrayName(self): 193 | """ 194 | Finds the name of the active array. 195 | """ 196 | actArr = self.viewprop.values()[0] 197 | if type(actArr) is str: 198 | activeName = actArr 199 | elif type(actArr) is int: 200 | activeName = self._getActiveVTKobj().GetArrayName(actArr) 201 | return activeName 202 | 203 | def _readPropertyDictionary(self,propdict): 204 | """ 205 | Reads the property and assigns to the object 206 | """ 207 | import simpegViz.vtkTools as vtkSP 208 | 209 | # Test the property dictionary 210 | if type(propdict) != dict: 211 | raise Exception('{:s} has to be a python dictionary containing property models. ') 212 | if len(propdict) > 4: 213 | raise Exception('Too many input items in the property dictionary') 214 | for propitem in propdict.iteritems(): 215 | if propitem[0] in ['C','F','E']: 216 | if propitem[0] == 'C': 217 | self._cells = vtkSP.makeCellVTKObject(self._mesh,propitem[1]) 218 | if propitem[0] == 'F': 219 | self._faces = vtkSP.makeFaceVTKObject(self._mesh,propitem[1]) 220 | if propitem[0] == 'E': 221 | self._edges = vtkSP.makeEdgeVTKObject(self._mesh,propitem[1]) 222 | else: 223 | raise Exception('\"{:s}\" is not allowed as a dictionary key. Can be \'C\',\'F\',\'E\'.'.format(propitem[0])) 224 | 225 | def Show(self): 226 | """ 227 | Open the VTK figure window and show the mesh. 228 | """ 229 | import simpegViz.vtkTools as vtkSP 230 | 231 | # Make a renderer 232 | self._ren = vtk.vtkRenderer() 233 | # Make renderwindow. Returns the interactor. 234 | self._iren, self._renwin = vtkSP.makeRenderWindow(self._ren) 235 | 236 | 237 | # Set the active scalar. 238 | if type(self.viewprop.values()[0]) == int: 239 | actScalar = self._getActiveVTKobj().GetArrayName(self.viewprop.values()[0]) 240 | elif type(self.viewprop.values()[0]) == str: 241 | actScalar = self.viewprop.values()[0] 242 | else : 243 | raise Exception('The vtkView.viewprop.values()[0] has the wrong format. Has to be interger or a string.') 244 | self._getActiveVTKobj().SetActiveScalars(actScalar) 245 | # Sort out the actor 246 | imageType = self.viewprop.keys()[0] 247 | if imageType == 'C': 248 | if self.limits is None: 249 | self.limits = self._cells.GetCellData().GetArray(self.viewprop.values()[0]).GetRange() 250 | self._vtkobj, self._core = vtkSP.makeRectiVTKVOIThres(self._cells,self.extent,self.limits) 251 | elif imageType == 'F': 252 | if self.limits is None: 253 | self.limits = self._faces.GetCellData().GetArray(self.viewprop.values()[0]).GetRange() 254 | extent = [self._mesh.vectorNx[self.extent[0]], self._mesh.vectorNx[self.extent[1]], self._mesh.vectorNy[self.extent[2]], self._mesh.vectorNy[self.extent[3]], self._mesh.vectorNz[self.extent[4]], self._mesh.vectorNz[self.extent[5]] ] 255 | self._vtkobj, self._core = vtkSP.makeUnstructVTKVOIThres(self._faces,extent,self.limits) 256 | elif imageType == 'E': 257 | if self.limits is None: 258 | self.limits = self._edges.GetCellData().GetArray(self.viewprop.values()[0]).GetRange() 259 | extent = [self._mesh.vectorNx[self.extent[0]], self._mesh.vectorNx[self.extent[1]], self._mesh.vectorNy[self.extent[2]], self._mesh.vectorNy[self.extent[3]], self._mesh.vectorNz[self.extent[4]], self._mesh.vectorNz[self.extent[5]] ] 260 | self._vtkobj, self._core = vtkSP.makeUnstructVTKVOIThres(self._edges,extent,self.limits) 261 | else: 262 | raise Exception("{:s} is not a valid viewprop. Has to be 'C':'F':'E'".format(imageType)) 263 | #self._vtkobj.GetCellData().SetActiveScalars(actScalar) 264 | # Set global variables to be used in the interactive widget 265 | global intPlane, intActor 266 | # Set up the plane, clipper and the user interaction. 267 | if not self._plane: 268 | intPlane = vtk.vtkPlane() 269 | self._plane = intPlane 270 | else: 271 | intPlane = self._plane 272 | 273 | self._clipper = vtkSP.makePlaneClipper(self._vtkobj,intPlane) 274 | intActor = vtkSP.makeVTKLODActor(self._vtkobj,self._clipper) 275 | self._actor = intActor 276 | self._widget = vtkSP.makePlaneWidget(self._vtkobj,self._iren) 277 | 278 | # Callback function 279 | def movePlane(obj, events): 280 | global intPlane, intActor 281 | obj.GetPlane(intPlane) 282 | intActor.VisibilityOn() 283 | 284 | self._widget.AddObserver("InteractionEvent",movePlane) 285 | lut = vtk.vtkLookupTable() 286 | lut.SetNumberOfColors(len(self.cmap)) 287 | lut.SetTable(npsup.numpy_to_vtk(self.cmap)) 288 | lut.Build() 289 | self._lut = lut 290 | scalarBar = vtk.vtkScalarBarActor() 291 | scalarBar.SetLookupTable(lut) 292 | scalarBar.SetTitle(self._getActiveArrayName()) 293 | scalarBar.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() 294 | scalarBar.GetPositionCoordinate().SetValue(0.1,0.01) 295 | scalarBar.SetOrientationToHorizontal() 296 | scalarBar.SetWidth(0.8) 297 | scalarBar.SetHeight(0.17) 298 | 299 | self._actor.GetMapper().SetScalarRange(self.range) 300 | self._actor.GetMapper().SetLookupTable(lut) 301 | 302 | # Set renderer options 303 | self._ren.SetBackground(.5,.5,.5) 304 | self._ren.AddActor(self._actor) 305 | self._ren.AddActor2D(scalarBar) 306 | self._renwin.SetSize(450,450) 307 | 308 | # Start the render Window 309 | vtkSP.startRenderWindow(self._iren) 310 | # Close the window when exited 311 | vtkSP.closeRenderWindow(self._iren) 312 | del self._iren, self._renwin 313 | 314 | 315 | 316 | if __name__ == '__main__': 317 | 318 | 319 | #Make a mesh and model 320 | x0 = np.zeros(3) 321 | h1 = np.ones(60)*50 322 | h2 = np.ones(60)*100 323 | h3 = np.ones(50)*200 324 | 325 | mesh = simpeg.Mesh.TensorMesh([h1,h2,h3],x0) 326 | 327 | # Make a models that correspond to the cells, faces and edges. 328 | t = np.ones(mesh.nC) 329 | t[10000:50000] = 100 330 | t[100000:120000] = 100 331 | t[100000:120000] = 50 332 | models = {'C':{'Test':np.arange(0,mesh.nC),'Model':t, 'AllOnce':np.ones(mesh.nC)},'F':{'Test':np.arange(0,mesh.nF),'AllOnce':np.ones(mesh.nF)},'E':{'Test':np.arange(0,mesh.nE),'AllOnce':np.ones(mesh.nE)}} 333 | # Make the vtk viewer object. 334 | vtkViewer = simpegViz.vtkView(mesh,models) 335 | # Set the .viewprop for which model to view 336 | vtkViewer.viewprop = {'F':'Test'} 337 | # Show the image 338 | vtkViewer.Show() 339 | 340 | # Set subset of the mesh to view (remove padding) 341 | vtkViewer.extent = [4,14,0,7,0,3] 342 | vtkViewer.Show() 343 | 344 | # Change viewing property 345 | vtkViewer.viewprop = {'C':'Model'} 346 | # Set the color range 347 | # Reset extent. 348 | vtkViewer.extent = [-1,1000,-1,1000,-1,1000] 349 | vtkViewer.range = [0.,100.] 350 | vtkViewer.Show() 351 | # Change color scale, has to be set to bytes=True. 352 | vtkViewer.cmap = mpl.cm.copper(np.arange(0.,1.,0.01),bytes=True) 353 | vtkViewer.Show() 354 | # Set limits of values to view 355 | vtkViewer.limits = [5.0,100.0] 356 | vtkViewer.Show() -------------------------------------------------------------------------------- /simpegViz/vtkTools.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | try: 3 | import vtk, vtk.util.numpy_support as npsup, pdb 4 | except Exception, e: 5 | print 'VTK import error. Please ensure you have VTK installed to use this visualization package.' 6 | from SimPEG.Utils import mkvc 7 | 8 | 9 | class vtkTools(object): 10 | """ 11 | Class that interacts with VTK visulization toolkit. 12 | 13 | """ 14 | 15 | def __init__(self): 16 | """ Initializes the VTK vtkTools. 17 | 18 | """ 19 | 20 | pass 21 | 22 | @staticmethod 23 | def makeCellVTKObject(mesh,model): 24 | """ 25 | Make and return a cell based VTK object for a simpeg mesh and model. 26 | 27 | Input: 28 | :param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK 29 | :param model, dictionary of numpy.array - Name('s) and array('s). Match number of cells 30 | 31 | Output: 32 | :rtype: vtkRecilinearGrid object 33 | :return: vtkObj 34 | """ 35 | 36 | # Deal with dimensionalities 37 | if mesh.dim >= 1: 38 | vX = mesh.vectorNx 39 | xD = mesh.nNx 40 | yD,zD = 1,1 41 | vY, vZ = np.array([0,0]) 42 | if mesh.dim >= 2: 43 | vY = mesh.vectorNy 44 | yD = mesh.nNy 45 | if mesh.dim == 3: 46 | vZ = mesh.vectorNz 47 | zD = mesh.nNz 48 | # Use rectilinear VTK grid. 49 | # Assign the spatial information. 50 | vtkObj = vtk.vtkRectilinearGrid() 51 | vtkObj.SetDimensions(xD,yD,zD) 52 | vtkObj.SetXCoordinates(npsup.numpy_to_vtk(vX,deep=1)) 53 | vtkObj.SetYCoordinates(npsup.numpy_to_vtk(vY,deep=1)) 54 | vtkObj.SetZCoordinates(npsup.numpy_to_vtk(vZ,deep=1)) 55 | 56 | # Assign the model('s) to the object 57 | for item in model.iteritems(): 58 | # Convert numpy array 59 | vtkDoubleArr = npsup.numpy_to_vtk(item[1],deep=1) 60 | vtkDoubleArr.SetName(item[0]) 61 | vtkObj.GetCellData().AddArray(vtkDoubleArr) 62 | 63 | vtkObj.GetCellData().SetActiveScalars(model.keys()[0]) 64 | vtkObj.Update() 65 | return vtkObj 66 | 67 | @staticmethod 68 | def makeFaceVTKObject(mesh,model): 69 | """ 70 | Make and return a face based VTK object for a simpeg mesh and model. 71 | 72 | Input: 73 | :param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK 74 | :param model, dictionary of numpy.array - Name('s) and array('s). 75 | Property array must be order hstack(Fx,Fy,Fz) 76 | 77 | Output: 78 | :rtype: vtkUnstructuredGrid object 79 | :return: vtkObj 80 | """ 81 | 82 | ## Convert simpeg mesh to VTK properties 83 | # Convert mesh nodes to vtkPoints 84 | vtkPts = vtk.vtkPoints() 85 | vtkPts.SetData(npsup.numpy_to_vtk(mesh.gridN,deep=1)) 86 | 87 | # Define the face "cells" 88 | # Using VTK_QUAD cell for faces (see VTK file format) 89 | nodeMat = mesh.r(np.arange(mesh.nN,dtype='int64'),'N','N','M') 90 | def faceR(mat,length): 91 | return mat.T.reshape((length,1)) 92 | # First direction 93 | nTFx = np.prod(mesh.nFx) 94 | FxCellBlock = np.hstack([ 4*np.ones((nTFx,1),dtype='int64'),faceR(nodeMat[:,:-1,:-1],nTFx),faceR(nodeMat[:,1: ,:-1],nTFx),faceR(nodeMat[:,1: ,1: ],nTFx),faceR(nodeMat[:,:-1,1: ],nTFx)] ) 95 | FyCellBlock = np.array([],dtype='int64') 96 | FzCellBlock = np.array([],dtype='int64') 97 | # Second direction 98 | if mesh.dim >= 2: 99 | nTFy = np.prod(mesh.nFy) 100 | FyCellBlock = np.hstack([ 4*np.ones((nTFy,1),dtype='int64'),faceR(nodeMat[:-1,:,:-1],nTFy),faceR(nodeMat[1: ,:,:-1],nTFy),faceR(nodeMat[1: ,:,1: ],nTFy),faceR(nodeMat[:-1,:,1: ],nTFy)] ) 101 | # Third direction 102 | if mesh.dim == 3: 103 | nTFz = np.prod(mesh.nFz) 104 | FzCellBlock = np.hstack([ 4*np.ones((nTFz,1),dtype='int64'),faceR(nodeMat[:-1,:-1,:],nTFz),faceR(nodeMat[1: ,:-1,:],nTFz),faceR(nodeMat[1: ,1: ,:],nTFz),faceR(nodeMat[:-1,1: ,:],nTFz)] ) 105 | # Cells -cell array 106 | FCellArr = vtk.vtkCellArray() 107 | FCellArr.SetNumberOfCells(mesh.nF) 108 | FCellArr.SetCells(mesh.nF,npsup.numpy_to_vtkIdTypeArray(np.vstack([FxCellBlock,FyCellBlock,FzCellBlock]),deep=1)) 109 | # Cell type 110 | FCellType = npsup.numpy_to_vtk(vtk.VTK_QUAD*np.ones(mesh.nF,dtype='uint8'),deep=1) 111 | # Cell location 112 | FCellLoc = npsup.numpy_to_vtkIdTypeArray(np.arange(0,mesh.nF*5,5,dtype='int64'),deep=1) 113 | 114 | ## Make the object 115 | vtkObj = vtk.vtkUnstructuredGrid() 116 | # Set the objects properties 117 | vtkObj.SetPoints(vtkPts) 118 | vtkObj.SetCells(FCellType,FCellLoc,FCellArr) 119 | 120 | # Assign the model('s) to the object 121 | for item in model.iteritems(): 122 | # Convert numpy array 123 | vtkDoubleArr = npsup.numpy_to_vtk(item[1],deep=1) 124 | vtkDoubleArr.SetName(item[0]) 125 | vtkObj.GetCellData().AddArray(vtkDoubleArr) 126 | 127 | vtkObj.GetCellData().SetActiveScalars(model.keys()[0]) 128 | vtkObj.Update() 129 | return vtkObj 130 | 131 | @staticmethod 132 | def makeEdgeVTKObject(mesh,model): 133 | """ 134 | Make and return a edge based VTK object for a simpeg mesh and model. 135 | 136 | Input: 137 | :param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK 138 | :param model, dictionary of numpy.array - Name('s) and array('s). 139 | Property array must be order hstack(Ex,Ey,Ez) 140 | 141 | Output: 142 | :rtype: vtkUnstructuredGrid object 143 | :return: vtkObj 144 | """ 145 | 146 | ## Convert simpeg mesh to VTK properties 147 | # Convert mesh nodes to vtkPoints 148 | vtkPts = vtk.vtkPoints() 149 | vtkPts.SetData(npsup.numpy_to_vtk(mesh.gridN,deep=1)) 150 | 151 | # Define the face "cells" 152 | # Using VTK_QUAD cell for faces (see VTK file format) 153 | nodeMat = mesh.r(np.arange(mesh.nN,dtype='int64'),'N','N','M') 154 | def edgeR(mat,length): 155 | return mat.T.reshape((length,1)) 156 | # First direction 157 | nTEx = np.prod(mesh.nEx) 158 | ExCellBlock = np.hstack([ 2*np.ones((nTEx,1),dtype='int64'),edgeR(nodeMat[:-1,:,:],nTEx),edgeR(nodeMat[1:,:,:],nTEx)]) 159 | # Second direction 160 | if mesh.dim >= 2: 161 | nTEy = np.prod(mesh.nEy) 162 | EyCellBlock = np.hstack([ 2*np.ones((nTEy,1),dtype='int64'),edgeR(nodeMat[:,:-1,:],nTEy),edgeR(nodeMat[:,1:,:],nTEy)]) 163 | # Third direction 164 | if mesh.dim == 3: 165 | nTEz = np.prod(mesh.nEz) 166 | EzCellBlock = np.hstack([ 2*np.ones((nTEz,1),dtype='int64'),edgeR(nodeMat[:,:,:-1],nTEz),edgeR(nodeMat[:,:,1:],nTEz)]) 167 | # Cells -cell array 168 | ECellArr = vtk.vtkCellArray() 169 | ECellArr.SetNumberOfCells(mesh.nE) 170 | ECellArr.SetCells(mesh.nE,npsup.numpy_to_vtkIdTypeArray(np.vstack([ExCellBlock,EyCellBlock,EzCellBlock]),deep=1)) 171 | # Cell type 172 | ECellType = npsup.numpy_to_vtk(vtk.VTK_LINE*np.ones(mesh.nE,dtype='uint8'),deep=1) 173 | # Cell location 174 | ECellLoc = npsup.numpy_to_vtkIdTypeArray(np.arange(0,mesh.nE*3,3,dtype='int64'),deep=1) 175 | 176 | ## Make the object 177 | vtkObj = vtk.vtkUnstructuredGrid() 178 | # Set the objects properties 179 | vtkObj.SetPoints(vtkPts) 180 | vtkObj.SetCells(ECellType,ECellLoc,ECellArr) 181 | 182 | # Assign the model('s) to the object 183 | for item in model.iteritems(): 184 | # Convert numpy array 185 | vtkDoubleArr = npsup.numpy_to_vtk(item[1],deep=1) 186 | vtkDoubleArr.SetName(item[0]) 187 | vtkObj.GetCellData().AddArray(vtkDoubleArr) 188 | 189 | vtkObj.GetCellData().SetActiveScalars(model.keys()[0]) 190 | vtkObj.Update() 191 | return vtkObj 192 | 193 | @staticmethod 194 | def makeRenderWindow(ren): 195 | renwin = vtk.vtkRenderWindow() 196 | renwin.AddRenderer(ren) 197 | iren = vtk.vtkRenderWindowInteractor() 198 | iren.GetInteractorStyle().SetCurrentStyleToTrackballCamera() 199 | iren.SetRenderWindow(renwin) 200 | 201 | return iren, renwin 202 | 203 | 204 | @staticmethod 205 | def closeRenderWindow(iren): 206 | renwin = iren.GetRenderWindow() 207 | renwin.Finalize() 208 | iren.TerminateApp() 209 | 210 | del iren, renwin 211 | 212 | @staticmethod 213 | def makeVTKActor(vtkObj): 214 | """ Makes a vtk mapper and Actor""" 215 | mapper = vtk.vtkDataSetMapper() 216 | mapper.SetInput(vtkObj) 217 | actor = vtk.vtkActor() 218 | actor.SetMapper(mapper) 219 | actor.GetProperty().SetColor(0,0,0) 220 | actor.GetProperty().SetRepresentationToWireframe() 221 | return actor 222 | 223 | @staticmethod 224 | def makeVTKLODActor(vtkObj,clipper): 225 | """Make LOD vtk Actor""" 226 | selectMapper = vtk.vtkDataSetMapper() 227 | selectMapper.SetInputConnection(clipper.GetOutputPort()) 228 | selectMapper.SetScalarVisibility(1) 229 | selectMapper.SetColorModeToMapScalars() 230 | selectMapper.SetScalarModeToUseCellData() 231 | selectMapper.SetScalarRange(clipper.GetInputDataObject(0,0).GetCellData().GetArray(0).GetRange()) 232 | 233 | selectActor = vtk.vtkLODActor() 234 | selectActor.SetMapper(selectMapper) 235 | selectActor.GetProperty().SetEdgeColor(1,0.5,0) 236 | selectActor.GetProperty().SetEdgeVisibility(0) 237 | selectActor.VisibilityOn() 238 | selectActor.SetScale(1.01, 1.01, 1.01) 239 | return selectActor 240 | 241 | @staticmethod 242 | def setScalar2View(vtkObj,scalarName): 243 | """ Sets the sclar to view """ 244 | useArr = vtkObj.GetCellData().GetArray(scalarName) 245 | if useArr == None: 246 | raise IOError('Nerty array {:s} in the vtkObject'.format(scalarName)) 247 | vtkObj.GetCellData().SetActiveScalars(scalarName) 248 | 249 | @staticmethod 250 | def makeRectiVTKVOIThres(vtkObj,VOI,limits): 251 | """Make volume of interest and threshold for rectilinear grid.""" 252 | # Check for the input 253 | cellCore = vtk.vtkExtractRectilinearGrid() 254 | cellCore.SetVOI(VOI) 255 | cellCore.SetInput(vtkObj) 256 | 257 | cellThres = vtk.vtkThreshold() 258 | cellThres.AllScalarsOn() 259 | cellThres.SetInputConnection(cellCore.GetOutputPort()) 260 | cellThres.ThresholdBetween(limits[0],limits[1]) 261 | cellThres.Update() 262 | return cellThres.GetOutput(), cellCore.GetOutput() 263 | 264 | @staticmethod 265 | def makeUnstructVTKVOIThres(vtkObj,extent,limits): 266 | """Make volume of interest and threshold for rectilinear grid.""" 267 | # Check for the input 268 | cellCore = vtk.vtkExtractUnstructuredGrid() 269 | cellCore.SetExtent(extent) 270 | cellCore.SetInput(vtkObj) 271 | 272 | cellThres = vtk.vtkThreshold() 273 | cellThres.AllScalarsOn() 274 | cellThres.SetInputConnection(cellCore.GetOutputPort()) 275 | cellThres.ThresholdBetween(limits[0],limits[1]) 276 | cellThres.Update() 277 | return cellThres.GetOutput(), cellCore.GetOutput() 278 | 279 | @staticmethod 280 | def makePlaneClipper(vtkObj,plane): 281 | """Makes a plane and clipper """ 282 | clipper = vtk.vtkClipDataSet() 283 | clipper.SetInputConnection(vtkObj.GetProducerPort()) 284 | clipper.SetClipFunction(plane) 285 | clipper.InsideOutOff() 286 | return clipper 287 | 288 | @staticmethod 289 | def makePlaneWidget(vtkObj,iren): 290 | """Make an interactive planeWidget""" 291 | 292 | # Associate the line widget with the interactor 293 | planeWidget = vtk.vtkImplicitPlaneWidget() 294 | planeWidget.SetInteractor(iren) 295 | planeWidget.SetInput(vtkObj ) 296 | planeWidget.SetPlaceFactor(1.05) # Increases the size of the widget bounds 297 | planeWidget.PlaceWidget(vtkObj.GetBounds()) 298 | b1,b2,b3 = vtkObj.GetBounds()[::2] 299 | planeWidget.SetOrigin(b1,b2,b3) 300 | #planeWidget.AddObserver("InteractionEvent", movePlane) 301 | planeWidget.SetOutsideBounds(0) # Not allow the widget to move outside the input bounds 302 | planeWidget.SetScaleEnabled(0) # Ability to scale with the mouse 303 | planeWidget.SetEnabled(1) # Starts the widget 304 | planeWidget.SetOutlineTranslation(0) # Abiltiy to move the widget with the mouse 305 | planeWidget.GetPlaneProperty().SetOpacity(0.1) 306 | return planeWidget 307 | 308 | 309 | @staticmethod 310 | def startRenderWindow(iren): 311 | """ Start a vtk rendering window""" 312 | iren.Initialize() 313 | renwin = iren.GetRenderWindow() 314 | renwin.Render() 315 | iren.Start() 316 | 317 | 318 | # Simple write/read VTK xml model functions. 319 | @staticmethod 320 | def writeVTPFile(fileName,vtkPolyObject): 321 | '''Function to write vtk polydata file (vtp).''' 322 | polyWriter = vtk.vtkXMLPolyDataWriter() 323 | polyWriter.SetInput(vtkPolyObject) 324 | polyWriter.SetFileName(fileName) 325 | polyWriter.Update() 326 | 327 | @staticmethod 328 | def writeVTUFile(fileName,vtkUnstructuredGrid): 329 | '''Function to write vtk unstructured grid (vtu).''' 330 | Writer = vtk.vtkXMLUnstructuredGridWriter() 331 | Writer.SetInput(vtkUnstructuredGrid) 332 | Writer.SetFileName(fileName) 333 | Writer.Update() 334 | 335 | @staticmethod 336 | def writeVTRFile(fileName,vtkRectilinearGrid): 337 | '''Function to write vtk rectilinear grid (vtr).''' 338 | Writer = vtk.vtkXMLRectilinearGridWriter() 339 | Writer.SetInput(vtkRectilinearGrid) 340 | Writer.SetFileName(fileName) 341 | Writer.Update() 342 | 343 | @staticmethod 344 | def writeVTSFile(fileName,vtkStructuredGrid): 345 | '''Function to write vtk structured grid (vts).''' 346 | Writer = vtk.vtkXMLStructuredGridWriter() 347 | Writer.SetInput(vtkStructuredGrid) 348 | Writer.SetFileName(fileName) 349 | Writer.Update() 350 | 351 | @staticmethod 352 | def readVTSFile(fileName): 353 | '''Function to read vtk structured grid (vts) and return a grid object.''' 354 | Reader = vtk.vtkXMLStructuredGridReader() 355 | Reader.SetFileName(fileName) 356 | Reader.Update() 357 | return Reader.GetOutput() 358 | 359 | @staticmethod 360 | def readVTUFile(fileName): 361 | '''Function to read vtk structured grid (vtu) and return a grid object.''' 362 | Reader = vtk.vtkXMLUnstructuredGridReader() 363 | Reader.SetFileName(fileName) 364 | Reader.Update() 365 | return Reader.GetOutput() 366 | 367 | @staticmethod 368 | def readVTRFile(fileName): 369 | '''Function to read vtk structured grid (vtr) and return a grid object.''' 370 | Reader = vtk.vtkXMLRectilinearGridReader() 371 | Reader.SetFileName(fileName) 372 | Reader.Update() 373 | return Reader.GetOutput() 374 | 375 | @staticmethod 376 | def readVTPFile(fileName): 377 | '''Function to read vtk structured grid (vtp) and return a grid object.''' 378 | Reader = vtk.vtkXMLPolyDataReader() 379 | Reader.SetFileName(fileName) 380 | Reader.Update() 381 | return Reader.GetOutput() 382 | 383 | --------------------------------------------------------------------------------