def SetRenderWindow(self,w): """ SetRenderWindow(w: vtkRenderWindow) Set a new render window to QVTKWidget and initialize the interactor as well """ if w == self.mRenWin: return if self.mRenWin: if system.systemType!='Linux': self.mRenWin.SetInteractor(None) if self.mRenWin.GetMapped(): self.mRenWin.Finalize() self.mRenWin = w if self.mRenWin: self.mRenWin.Register(None) if self.mRenWin.GetMapped(): self.mRenWin.Finalize() if system.systemType=='Linux': display = None try: display = int(QtGui.QX11Info.display()) except TypeError: # This was changed for PyQt4.2 if isinstance(QtGui.QX11Info.display(), QtGui.Display): display = sip.unwrapinstance(QtGui.QX11Info.display()) if display is not None: v = vtk.vtkVersion() version = [v.GetVTKMajorVersion(), v.GetVTKMinorVersion(), v.GetVTKBuildVersion()] display = hex(display)[2:] if version < [5, 7, 0]: vp = ('_%s_void_p\0x00' % display) elif version < [6, 2, 0]: vp = ('_%s_void_p' % display) else: vp = ('_%s_p_void' % display) self.mRenWin.SetDisplayId(vp) self.resizeWindow(1,1) self.mRenWin.SetWindowInfo(str(int(self.winId()))) if self.isVisible(): self.mRenWin.Start() if not self.mRenWin.GetInteractor(): #iren = vtk.vtkRenderWindowInteractor() iren = QVTKRenderWindowInteractor() # if system.systemType=='Darwin': # iren.InstallMessageProcOff() iren.SetRenderWindow(self.mRenWin) iren.Initialize() # if system.systemType=='Linux': # system.XDestroyWindow(self.mRenWin.GetGenericDisplayId(), # self.mRenWin.GetGenericWindowId()) self.mRenWin.SetWindowInfo(str(int(self.winId()))) self.resizeWindow(self.width(), self.height()) self.mRenWin.SetPosition(self.x(), self.y())
def QVTKRenderWidgetConeExample(): """A simple example that uses the QVTKRenderWindowInteractor class.""" # every QT app needs an app app = QtGui.QApplication(['QVTKRenderWindowInteractor']) # create the widget widget = QVTKRenderWindowInteractor() widget.Initialize() widget.Start() # if you dont want the 'q' key to exit comment this. widget.AddObserver("ExitEvent", lambda o, e, a=app: a.quit()) ren = vtk.vtkRenderer() widget.GetRenderWindow().AddRenderer(ren) cone = vtk.vtkConeSource() cone.SetResolution(8) coneMapper = vtk.vtkPolyDataMapper() coneMapper.SetInputConnection(cone.GetOutputPort()) coneActor = vtk.vtkActor() coneActor.SetMapper(coneMapper) ren.AddActor(coneActor) # show the widget widget.show() # start event processing app.exec_()
class RotationViewer(module_template.Viewer): """Uses mayavi to plot a sphere made up of small spheres as pixels. The colors indicate the responsability density.""" def __init__(self, parent=None): super(RotationViewer, self).__init__() #self._widget = QtGui.QWidget(parent) self._vtk_widget = QVTKRenderWindowInteractor(self._widget) # _vtk_widget is actually the RenderWindowInteractor self._vtk_widget.SetInteractorStyle(vtk.vtkInteractorStyleRubberBandPick()) #self._vtk_widget.Initialize() layout = QtGui.QVBoxLayout() layout.addWidget(self._vtk_widget) self._widget.setLayout(layout) self._renderer = vtk.vtkRenderer() self._vtk_widget.GetRenderWindow().AddRenderer(self._renderer) #self._mlab_widget = embedded_mayavi.MlabWidget() self._setup_done = False self._points = None self._default_sphere_n = 10 self._sphere = vtk_tools.SphereMap(self._default_sphere_n) self._renderer.AddViewProp(self._sphere.get_actor()) self._renderer.SetBackground(1., 1., 1.) #self._renderer.Render() def initialize(self): self._vtk_widget.Initialize() # def get_widget(self): # """Return the widget containing the view.""" # return self._vtk_widget def set_sampling_n(self, sampling_n): """Rerun when the array size changes.""" self._sphere.set_n(sampling_n) def get_coordinates(self): return self._sphere.get_coordinates() def get_number_of_points(): pass def plot_rotations(self, values): """Update the viewer to show the new values.""" if len(values) != self._sphere.get_number_of_points(): #raise ValueError("values must be array of length {0}. Length {1} array received.".format(self._sphere.get_number_of_points(), len(values))) sampling_n = icosahedral_sphere.points_to_n(len(values)) self.set_sampling_n(sampling_n) self._sphere.set_lookup_table(vtk_tools.get_lookup_table(0., values.max(), log=False, colorscale="jet", number_of_colors=1000)) self._sphere.set_values(values) #self._sphere #self._renderer.Render() self._vtk_widget.Render()
class MeshRenderWidget(QtGui.QWidget): def __init__(self, tree_widget): QtGui.QWidget.__init__(self) self.tree_widget = tree_widget self.tree_widget.mesh_item_changed.connect(self.meshItemChanged) self.mesh_file_name = '' self.mesh_renderer = None self.current_block_actors = {} self.current_sideset_actors = {} self.current_nodeset_actors = {} self.this_layout = QtGui.QVBoxLayout() self.setLayout(self.this_layout) self.vtkwidget = QVTKRenderWindowInteractor(self) self.renderer = vtk.vtkRenderer() self.renderer.SetBackground(0.2, 0.2, 0.2) self.renderer.SetBackground2(1, 1, 1) self.renderer.SetGradientBackground(1) self.renderer.ResetCamera() self.this_layout.addWidget(self.vtkwidget) self.this_layout.setStretchFactor(self.vtkwidget, 10) self.vtkwidget.setMinimumHeight(300) self.vtkwidget.GetRenderWindow().AddRenderer(self.renderer) self.interactor = self.vtkwidget.GetRenderWindow().GetInteractor() self.interactor.SetInteractorStyle( vtk.vtkInteractorStyleTrackballCamera()) self.vtkwidget.Initialize() self.vtkwidget.Start() self.controls_layout = QtGui.QHBoxLayout() self.left_controls_layout = QtGui.QVBoxLayout() self.block_view_group_box = QtGui.QGroupBox('Show Blocks') self.block_view_group_box.setMaximumWidth(150) # self.block_view_group_box.setMaximumHeight(200) self.block_view_layout = QtGui.QVBoxLayout() self.block_view_list = QtGui.QListView() self.block_view_model = QtGui.QStandardItemModel() self.block_view_model.itemChanged.connect(self._blockViewItemChanged) self.block_view_list.setModel(self.block_view_model) self.block_view_layout.addWidget(self.block_view_list) self.block_view_group_box.setLayout(self.block_view_layout) self.left_controls_layout.addWidget(self.block_view_group_box) self.controls_layout.addLayout(self.left_controls_layout) self.right_controls_layout = QtGui.QVBoxLayout() self.controls_layout.addLayout(self.right_controls_layout) self.view_mesh_checkbox = QtGui.QCheckBox('View Mesh') self.view_mesh_checkbox.setToolTip('Toggle viewing of mesh elements') self.view_mesh_checkbox.setCheckState(QtCore.Qt.Checked) self.view_mesh_checkbox.stateChanged.connect( self.viewMeshCheckboxChanged) self.right_controls_layout.addWidget(self.view_mesh_checkbox) self.highlight_group_box = QtGui.QGroupBox('Highlight') self.highlight_group_box.setMaximumHeight(70) self.highlight_group_box.setSizePolicy( QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed) # self.highlight_group_box.setMaximumWidth(200) self.highlight_layout = QtGui.QHBoxLayout() self.highlight_group_box.setLayout(self.highlight_layout) self.right_controls_layout.addWidget(self.highlight_group_box) self.highlight_block_label = QtGui.QLabel('Block:') self.highlight_block_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.highlight_block_combo = QtGui.QComboBox() # self.highlight_block_combo.setMaximumWidth(50) self.highlight_block_combo.setSizeAdjustPolicy( QtGui.QComboBox.AdjustToMinimumContentsLength) self.highlight_block_combo.setSizePolicy( QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed) self.highlight_block_combo.setToolTip('Highlight a block in the mesh') self.highlight_block_combo.currentIndexChanged[str].connect( self.showBlockSelected) self.highlight_layout.addWidget(self.highlight_block_label) self.highlight_layout.addWidget(self.highlight_block_combo) self.highlight_sideset_label = QtGui.QLabel('Sideset:') self.highlight_sideset_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.highlight_sideset_combo = QtGui.QComboBox() # self.highlight_sideset_combo.setMaximumWidth(50) self.highlight_sideset_combo.setSizeAdjustPolicy( QtGui.QComboBox.AdjustToMinimumContentsLength) self.highlight_sideset_combo.setSizePolicy( QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed) self.highlight_sideset_combo.setToolTip( 'Highlight a sideset in the mesh') self.highlight_sideset_combo.currentIndexChanged[str].connect( self.showSidesetSelected) self.highlight_layout.addWidget(self.highlight_sideset_label) self.highlight_layout.addWidget(self.highlight_sideset_combo) self.highlight_nodeset_label = QtGui.QLabel('Nodeset:') self.highlight_nodeset_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) self.highlight_nodeset_combo = QtGui.QComboBox() # self.highlight_nodeset_combo.setMaximumWidth(50) self.highlight_nodeset_combo.setSizeAdjustPolicy( QtGui.QComboBox.AdjustToMinimumContentsLength) self.highlight_nodeset_combo.setSizePolicy( QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed) self.highlight_nodeset_combo.setToolTip( 'Highlight a nodeset in the mesh') self.highlight_nodeset_combo.currentIndexChanged[str].connect( self.showNodesetSelected) self.highlight_layout.addWidget(self.highlight_nodeset_label) self.highlight_layout.addWidget(self.highlight_nodeset_combo) self.highlight_clear = QtGui.QPushButton('Clear') self.highlight_clear.setToolTip('Clear highlighting') self.highlight_clear.setDisabled(True) self.highlight_clear.clicked.connect(self.clearHighlight) self.highlight_layout.addWidget(self.highlight_clear) self.plane = vtk.vtkPlane() self.plane.SetOrigin(0, 0, 0) self.plane.SetNormal(1, 0, 0) self.clip_groupbox = QtGui.QGroupBox("Clip") self.clip_groupbox.setToolTip( 'Toggle clip mode to slice the mesh open along a plane') self.clip_groupbox.setCheckable(True) self.clip_groupbox.setChecked(False) self.clip_groupbox.setMaximumHeight(70) self.clip_groupbox.toggled[bool].connect(self._clippingToggled) clip_layout = QtGui.QHBoxLayout() self.clip_plane_combobox = QtGui.QComboBox() self.clip_plane_combobox.setToolTip( 'Direction of the normal for the clip plane') self.clip_plane_combobox.addItem('x') self.clip_plane_combobox.addItem('y') self.clip_plane_combobox.addItem('z') self.clip_plane_combobox.currentIndexChanged[str].connect( self._clipNormalChanged) clip_layout.addWidget(self.clip_plane_combobox) self.clip_plane_slider = QtGui.QSlider(QtCore.Qt.Horizontal) self.clip_plane_slider.setToolTip('Slide to change plane position') self.clip_plane_slider.setRange(0, 100) self.clip_plane_slider.setSliderPosition(50) self.clip_plane_slider.sliderMoved[int].connect(self._clipSliderMoved) clip_layout.addWidget(self.clip_plane_slider) # vbox->addStretch(1); self.clip_groupbox.setLayout(clip_layout) self.right_controls_layout.addWidget(self.clip_groupbox) self.this_layout.addLayout(self.controls_layout) self.this_layout.setStretchFactor(self.controls_layout, 1) self.bounds = {} self.bounds['x'] = [0.0, 0.0] self.bounds['y'] = [0.0, 0.0] self.bounds['z'] = [0.0, 0.0] # self.draw_edges_checkbox = QtGui.QCheckBox("View Mesh") # self.left_controls_layout.addWidget(self.draw_edges_checkbox) def clear(self): self.highlight_block_combo.clear() self.highlight_sideset_combo.clear() self.highlight_nodeset_combo.clear() for block_actor_name, block_actor in self.current_block_actors.items(): block_actor.hide() for sideset_actor_name, sideset_actor in self.current_sideset_actors.items( ): sideset_actor.hide() for nodeset_actor_name, nodeset_actor in self.current_nodeset_actors.items( ): nodeset_actor.hide() self.current_block_actors = {} self.current_sideset_actors = {} self.current_nodeset_actors = {} def meshItemChanged(self, item): # Disconnect some actions while we fill stuff in if self.mesh_renderer: self.highlight_block_combo.currentIndexChanged[str].disconnect( self.showBlockSelected) self.highlight_sideset_combo.currentIndexChanged[str].disconnect( self.showSidesetSelected) self.highlight_nodeset_combo.currentIndexChanged[str].disconnect( self.showNodesetSelected) self.clear() self.mesh_renderer = RendererFactory.getRenderer(self, item.table_data) if self.mesh_renderer: self.show() else: self.hide() return self.current_block_actors = self.mesh_renderer.block_actors self.current_sideset_actors = self.mesh_renderer.sideset_actors self.current_nodeset_actors = self.mesh_renderer.nodeset_actors self.block_view_model.clear() for block in self.mesh_renderer.blocks: block_display_name = str(block) if block in self.mesh_renderer.block_id_to_name: block_display_name += ' : ' + self.mesh_renderer.block_id_to_name[ block] item = QtGui.QStandardItem(str(block_display_name)) item.exodus_block = block item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable) item.setCheckState(QtCore.Qt.Checked) self.block_view_model.appendRow(item) for block_actor_name, block_actor in self.current_block_actors.items(): block_actor.show() block_actor.showEdges() block_names = [] for block_actor_id, block_actor in self.current_block_actors.items(): name = block_actor_id.strip(' ') if int(name) in self.mesh_renderer.block_id_to_name: name += ' : ' + self.mesh_renderer.block_id_to_name[int(name)] block_names.append(name) self.highlight_block_combo.addItem('') for block_actor_name in sorted( block_names, key=lambda name: int(name.split(' ')[0])): self.highlight_block_combo.addItem(str(block_actor_name)) sideset_names = [] for sideset_actor_id, sideset_actor in self.current_sideset_actors.items( ): sideset_actor.setColor(red) name = sideset_actor_id.strip(' ') if int(name) in self.mesh_renderer.sideset_id_to_name: name += ' : ' + self.mesh_renderer.sideset_id_to_name[int( name)] sideset_names.append(name) self.highlight_sideset_combo.addItem('') for sideset_actor_name in sorted( sideset_names, key=lambda name: int(name.split(' ')[0])): self.highlight_sideset_combo.addItem(sideset_actor_name) nodeset_names = [] for nodeset_actor_id, nodeset_actor in self.current_nodeset_actors.items( ): nodeset_actor.setColor(red) name = nodeset_actor_id.strip(' ') if int(name) in self.mesh_renderer.nodeset_id_to_name: name += ' : ' + self.mesh_renderer.nodeset_id_to_name[int( name)] nodeset_names.append(name) self.highlight_nodeset_combo.addItem('') for nodeset_actor_name in sorted( nodeset_names, key=lambda name: int(name.split(' ')[0])): self.highlight_nodeset_combo.addItem(nodeset_actor_name) self.highlight_block_combo.currentIndexChanged[str].connect( self.showBlockSelected) self.highlight_sideset_combo.currentIndexChanged[str].connect( self.showSidesetSelected) self.highlight_nodeset_combo.currentIndexChanged[str].connect( self.showNodesetSelected) self.setBounds() # Avoid z-buffer fighting vtk.vtkPolyDataMapper().SetResolveCoincidentTopologyToPolygonOffset() self.renderer.ResetCamera() self.vtkwidget.repaint() def setBounds(self): for actor_name, actor in self.current_block_actors.items(): current_bounds = actor.getBounds() self.bounds['x'][0] = min(self.bounds['x'][0], current_bounds[0]) self.bounds['x'][1] = max(self.bounds['x'][1], current_bounds[1]) self.bounds['y'][0] = min(self.bounds['y'][0], current_bounds[2]) self.bounds['y'][1] = max(self.bounds['y'][1], current_bounds[3]) self.bounds['z'][0] = min(self.bounds['z'][0], current_bounds[4]) self.bounds['z'][1] = max(self.bounds['z'][1], current_bounds[5]) def swapActors(self, current, new): for old_name, old_actor in current.items(): new[old_name].sync(old_actor) old_actor.hide() def _blockViewItemChanged(self, item): if item.checkState() == QtCore.Qt.Checked: self.current_block_actors[str(item.exodus_block)].show() else: self.current_block_actors[str(item.exodus_block)].hide() self.vtkwidget.repaint() def _clippingToggled(self, value): if value: self.swapActors(self.current_block_actors, self.mesh_renderer.clipped_block_actors) self.current_block_actors = self.mesh_renderer.clipped_block_actors self.swapActors(self.current_sideset_actors, self.mesh_renderer.clipped_sideset_actors) self.current_sideset_actors = self.mesh_renderer.clipped_sideset_actors self.swapActors(self.current_nodeset_actors, self.mesh_renderer.clipped_nodeset_actors) self.current_nodeset_actors = self.mesh_renderer.clipped_nodeset_actors self._clipNormalChanged(self.clip_plane_combobox.currentText()) else: self.swapActors(self.current_block_actors, self.mesh_renderer.block_actors) self.current_block_actors = self.mesh_renderer.block_actors self.swapActors(self.current_sideset_actors, self.mesh_renderer.sideset_actors) self.current_sideset_actors = self.mesh_renderer.sideset_actors self.swapActors(self.current_nodeset_actors, self.mesh_renderer.nodeset_actors) self.current_nodeset_actors = self.mesh_renderer.nodeset_actors self.vtkwidget.repaint() def _clipNormalChanged(self, value): self.plane.SetOrigin(self.bounds['x'][0], self.bounds['y'][0], self.bounds['z'][0]) if value == 'x': self.plane.SetNormal(1, 0, 0) elif value == 'y': self.plane.SetNormal(0, 1, 0) else: self.plane.SetNormal(0, 0, 1) self.clip_plane_slider.setSliderPosition(50) self._clipSliderMoved(50) def _clipSliderMoved(self, value): direction = str(self.clip_plane_combobox.currentText()) step_size = (self.bounds[direction][1] - self.bounds[direction][0]) / 100.0 steps = value distance = float(steps) * step_size position = self.bounds[direction][0] + distance old = self.plane.GetOrigin() self.plane.SetOrigin(position if direction == 'x' else old[0], position if direction == 'y' else old[1], position if direction == 'z' else old[2]) for actor_name, actor in self.current_sideset_actors.items(): actor.movePlane() for actor_name, actor in self.current_nodeset_actors.items(): actor.movePlane() for actor_name, actor in self.current_block_actors.items(): actor.movePlane() self.vtkwidget.repaint() def viewMeshCheckboxChanged(self, value): if value == QtCore.Qt.Checked: for actor_name, actor in self.current_sideset_actors.items(): actor.showEdges() for actor_name, actor in self.current_nodeset_actors.items(): actor.showEdges() for actor_name, actor in self.current_block_actors.items(): actor.showEdges() else: for actor_name, actor in self.current_sideset_actors.items(): actor.hideEdges() for actor_name, actor in self.current_nodeset_actors.items(): actor.hideEdges() for actor_name, actor in self.current_block_actors.items(): actor.hideEdges() self.vtkwidget.repaint() def clearBlockComboBox(self): self.highlight_block_combo.currentIndexChanged[str].disconnect( self.showBlockSelected) self.highlight_block_combo.setCurrentIndex(0) self.highlight_block_combo.currentIndexChanged[str].connect( self.showBlockSelected) def clearSidesetComboBox(self): self.highlight_sideset_combo.currentIndexChanged[str].disconnect( self.showSidesetSelected) self.highlight_sideset_combo.setCurrentIndex(0) self.highlight_sideset_combo.currentIndexChanged[str].connect( self.showSidesetSelected) def clearNodesetComboBox(self): self.highlight_nodeset_combo.currentIndexChanged[str].disconnect( self.showNodesetSelected) self.highlight_nodeset_combo.setCurrentIndex(0) self.highlight_nodeset_combo.currentIndexChanged[str].connect( self.showNodesetSelected) def showBlockSelected(self, block_name): if block_name != '': self.clearSidesetComboBox() self.clearNodesetComboBox() self.highlightBlock(str(block_name).split(' ')[0]) else: self.clearActors() def showSidesetSelected(self, sideset_name): if sideset_name != '': self.clearBlockComboBox() self.clearNodesetComboBox() self.highlightBoundary(str(sideset_name).split(' ')[0]) else: self.clearActors() def showNodesetSelected(self, nodeset_name): if nodeset_name != '': self.clearBlockComboBox() self.clearSidesetComboBox() self.highlightNodeset(str(nodeset_name).split(' ')[0]) else: self.clearActors() def highlightBoundary(self, boundary): self.highlight_clear.setDisabled(False) # Turn off all sidesets for actor_name, actor in self.current_sideset_actors.items(): actor.hide() # Turn off all nodesets for actor_name, actor in self.current_nodeset_actors.items(): actor.hide() # Turn solids to only edges... but only if they are visible for actor_name, actor in self.current_block_actors.items(): actor.setColor(black) actor.goWireframe() boundaries = boundary.strip("'").split(' ') for the_boundary in boundaries: if the_boundary in self.current_sideset_actors: self.current_sideset_actors[the_boundary].show() elif the_boundary in self.current_nodeset_actors: self.current_nodeset_actors[the_boundary].show() elif the_boundary in self.mesh_renderer.name_to_sideset_id: self.current_sideset_actors[str( self.mesh_renderer.name_to_sideset_id[the_boundary])].show( ) elif the_boundary in self.mesh_renderer.name_to_nodeset_id: self.current_nodeset_actors[str( self.mesh_renderer.name_to_nodeset_id[the_boundary])].show( ) self.vtkwidget.repaint() def highlightNodeset(self, boundary): self.highlight_clear.setDisabled(False) # Turn off all sidesets for actor_name, actor in self.current_sideset_actors.items(): actor.hide() # Turn off all nodesets for actor_name, actor in self.current_nodeset_actors.items(): actor.hide() # Turn solids to only edges... but only if they are visible for actor_name, actor in self.current_block_actors.items(): actor.setColor(black) actor.goWireframe() boundaries = boundary.strip("'").split(' ') for the_boundary in boundaries: if the_boundary in self.current_nodeset_actors: self.current_nodeset_actors[the_boundary].show() elif the_boundary in self.mesh_renderer.name_to_nodeset_id: self.current_nodeset_actors[str( self.mesh_renderer.name_to_nodeset_id[the_boundary])].show( ) self.vtkwidget.repaint() def highlightBlock(self, block): self.highlight_clear.setDisabled(False) # Turn off all sidesets for actor_name, actor in self.current_sideset_actors.items(): actor.hide() # Turn off all nodesets for actor_name, actor in self.current_nodeset_actors.items(): actor.hide() # Turn solids to only edges... for actor_name, actor in self.current_block_actors.items(): actor.setColor(black) actor.goWireframe() blocks = block.strip("'").split(' ') for the_block in blocks: if the_block in self.current_block_actors: self.current_block_actors[the_block].setColor(red) self.current_block_actors[the_block].goSolid() elif the_block in self.mesh_renderer.name_to_block_id: self.current_block_actors[str( self.mesh_renderer.name_to_block_id[the_block])].setColor( red) self.current_block_actors[str( self.mesh_renderer.name_to_block_id[the_block])].goSolid() self.vtkwidget.repaint() def clearActors(self): # Turn off all sidesets for actor_name, actor in self.current_sideset_actors.items(): actor.hide() # Turn off all nodesets for actor_name, actor in self.current_nodeset_actors.items(): actor.hide() # Show solids and edges - but only if something is visible for actor_name, actor in self.current_block_actors.items(): actor.setColor(white) actor.goSolid() self.vtkwidget.repaint() def clearHighlight(self): self.highlight_block_combo.setCurrentIndex(0) self.highlight_sideset_combo.setCurrentIndex(0) self.highlight_nodeset_combo.setCurrentIndex(0) self.highlight_clear.setDisabled(True) self.clearActors()
class Main(QtGui.QMainWindow): def resizeEvent(self, Event): pass #self.ModelView.resize(self.ui.ModelFrame.geometry().width()-15,self.ui.ModelFrame.geometry().height()-39) def __init__(self): QtGui.QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setWindowTitle( QtGui.QApplication.translate("MainWindow", "3DLP Slicer", None, QtGui.QApplication.UnicodeUTF8)) #load previous settings from config file here: self.parser = SafeConfigParser() filename = 'sliceconfig.ini' if hasattr(sys, '_MEIPASS'): # PyInstaller >= 1.6 os.chdir(sys._MEIPASS) filename = os.path.join(sys._MEIPASS, filename) APPNAME = '3DLP' APPDATA = os.path.join(os.environ['APPDATA'], APPNAME) if not os.path.isdir(os.path.join(APPDATA)): os.mkdir(os.path.join(APPDATA)) shutil.copy(filename, os.path.join(APPDATA, '')) self.parser.read(os.path.join(APPDATA, 'sliceconfig.ini')) self.LoadSettingsFromConfigFile() else: if not os.path.isfile(os.path.join(APPDATA, 'sliceconfig.ini')): shutil.copy(filename, os.path.join(APPDATA)) else: self.parser.read(os.path.join(APPDATA, 'sliceconfig.ini')) self.LoadSettingsFromConfigFile() else: #otherwise it's running in pydev environment: use the dev config file os.chdir(os.path.dirname(sys.argv[0])) filename = os.path.join(os.path.dirname(sys.argv[0]), filename) self.parser.read('sliceconfig.ini') self.LoadSettingsFromConfigFile() self.ren = vtk.vtkRenderer() self.ren.SetBackground(.4, .4, .4) # create the modelview widget self.ModelView = QVTKRenderWindowInteractor(self.ui.ModelFrame) self.ModelView.SetInteractorStyle(MyInteractorStyle()) self.ModelView.Initialize() self.ModelView.Start() self.renWin = self.ModelView.GetRenderWindow() self.renWin.AddRenderer(self.ren) self.ModelView.show() self.ModelView.resize(1006 - 17, 716 - 39) #self.ModelView.resize(self.ui.ModelFrame.geometry().width()-1,self.ui.ModelFrame.geometry().height()-1) self.modelList = [] def AddModel(self): filename = QtGui.QFileDialog.getOpenFileName(self, 'Open 3D Model', '.', '*.stl') if filename == '': #user hit cancel return modelObject = model(self, filename) self.modelList.append(modelObject) self.ui.modelList.addItem(os.path.basename(str(filename))) if len(self.modelList) == 1: self.FirstOpen() self.ren.ResetCamera() self.ModelView.Render() #update model view def FirstOpen(self): #create annotated cube anchor actor self.axesActor = vtk.vtkAnnotatedCubeActor() self.axesActor.SetXPlusFaceText('Right') self.axesActor.SetXMinusFaceText('Left') self.axesActor.SetYMinusFaceText('Front') self.axesActor.SetYPlusFaceText('Back') self.axesActor.SetZMinusFaceText('Bot') self.axesActor.SetZPlusFaceText('Top') self.axesActor.GetTextEdgesProperty().SetColor(.8, .8, .8) self.axesActor.GetZPlusFaceProperty().SetColor(.8, .8, .8) self.axesActor.GetZMinusFaceProperty().SetColor(.8, .8, .8) self.axesActor.GetXPlusFaceProperty().SetColor(.8, .8, .8) self.axesActor.GetXMinusFaceProperty().SetColor(.8, .8, .8) self.axesActor.GetYPlusFaceProperty().SetColor(.8, .8, .8) self.axesActor.GetYMinusFaceProperty().SetColor(.8, .8, .8) self.axesActor.GetTextEdgesProperty().SetLineWidth(2) self.axesActor.GetCubeProperty().SetColor(.2, .2, .2) self.axesActor.SetFaceTextScale(0.25) self.axesActor.SetZFaceTextRotation(90) #create orientation markers self.axes = vtk.vtkOrientationMarkerWidget() self.axes.SetOrientationMarker(self.axesActor) self.axes.SetInteractor(self.ModelView) self.axes.EnabledOn() self.axes.InteractiveOff() self.ui.Transform_groupbox.setEnabled(True) def SliceModel(self): try: if self.modelActor: #check to see if a model is loaded, if not it will throw an exception pass except: #self.modelActor doesn't exist (hasn't been instantiated with a model yet) QtGui.QMessageBox.critical( self, 'Error slicing model', "You must first load a model to slice it!", QtGui.QMessageBox.Ok) return self.outputFile = str( QFileDialog.getSaveFileName(self, "Save file", "", ".3dlp")) self.slicer = slicer.slicer(self) self.slicer.imageheight = int(self.imageHeight) self.slicer.imagewidth = int(self.imageWidth) # check to see if starting depth is less than ending depth!! this assumption is crucial self.slicer.startingdepth = float(self.startingDepth) self.slicer.endingdepth = float(self.endingDepth) self.slicer.layerincrement = float(self.slicingIncrement) self.slicer.OpenModel(self.filename) self.slicer.slice() def UpdateModelOpacity(self): try: if self.modelActor: #check to see if a model is loaded, if not it will throw an exception opacity, ok = QtGui.QInputDialog.getText( self, 'Model Opacity', 'Enter the desired opacity (0-100):') if not ok: #the user hit the "cancel" button return self.modelActor.GetProperty().SetOpacity(float(opacity) / 100) self.ren.Render() self.ModelView.Render() except: #self.modelActor doesn't exist (hasn't been instantiated with a model yet) QtGui.QMessageBox.critical( self, 'Error setting opacity', "You must first load a model to change its opacity!", QtGui.QMessageBox.Ok) def ModelIndexChanged(self, new, previous): modelObject = self.modelList[self.ui.modelList.currentRow()] self.ui.positionX.setValue(modelObject.CurrentXPosition) self.ui.positionY.setValue(modelObject.CurrentYPosition) self.ui.positionZ.setValue(modelObject.CurrentZPosition) self.ui.rotationX.setValue(modelObject.CurrentXRotation) self.ui.rotationY.setValue(modelObject.CurrentYRotation) self.ui.rotationZ.setValue(modelObject.CurrentZRotation) self.ui.scale.setValue(modelObject.CurrentScale) def Update_Position_X(self, position): modelObject = self.modelList[self.ui.modelList.currentRow()] transform = modelObject.transform transform.Translate((float(position) - modelObject.CurrentXPosition), 0.0, 0.0) modelObject.CurrentXPosition = modelObject.CurrentXPosition + ( float(position) - modelObject.CurrentXPosition) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetTransform(transform) transformFilter.SetInputConnection(modelObject.reader.GetOutputPort()) transformFilter.Update() modelObject.mapper.SetInputConnection(transformFilter.GetOutputPort()) modelObject.mapper.Update() self.ren.Render() self.ModelView.Render() def Update_Position_Y(self, position): modelObject = self.modelList[self.ui.modelList.currentRow()] transform = modelObject.transform transform.Translate(0.0, (float(position) - modelObject.CurrentYPosition), 0.0) modelObject.CurrentYPosition = modelObject.CurrentYPosition + ( float(position) - modelObject.CurrentYPosition) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetTransform(transform) transformFilter.SetInputConnection(modelObject.reader.GetOutputPort()) transformFilter.Update() modelObject.mapper.SetInputConnection(transformFilter.GetOutputPort()) modelObject.mapper.Update() self.ren.Render() self.ModelView.Render() def Update_Position_Z(self, position): modelObject = self.modelList[self.ui.modelList.currentRow()] transform = modelObject.transform transform.Translate(0.0, 0.0, (float(position) - modelObject.CurrentZPosition)) modelObject.CurrentZPosition = modelObject.CurrentZPosition + ( float(position) - modelObject.CurrentZPosition) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetTransform(transform) transformFilter.SetInputConnection(modelObject.reader.GetOutputPort()) transformFilter.Update() modelObject.mapper.SetInputConnection(transformFilter.GetOutputPort()) modelObject.mapper.Update() self.ren.Render() self.ModelView.Render() def Update_Rotation_X(self, rotation): modelObject = self.modelList[self.ui.modelList.currentRow()] transform = modelObject.transform transform.RotateX((float(rotation) - modelObject.CurrentXRotation)) modelObject.CurrentXRotation = modelObject.CurrentXRotation + ( float(rotation) - modelObject.CurrentXRotation) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetTransform(transform) transformFilter.SetInputConnection(modelObject.reader.GetOutputPort()) transformFilter.Update() modelObject.mapper.SetInputConnection(transformFilter.GetOutputPort()) modelObject.mapper.Update() self.ren.Render() self.ModelView.Render() def Update_Rotation_Y(self, rotation): modelObject = self.modelList[self.ui.modelList.currentRow()] transform = modelObject.transform transform.RotateY((float(rotation) - modelObject.CurrentYRotation)) modelObject.CurrentYRotation = modelObject.CurrentYRotation + ( float(rotation) - modelObject.CurrentYRotation) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetTransform(transform) transformFilter.SetInputConnection(modelObject.reader.GetOutputPort()) transformFilter.Update() modelObject.mapper.SetInputConnection(transformFilter.GetOutputPort()) modelObject.mapper.Update() self.ren.Render() self.ModelView.Render() def Update_Rotation_Z(self, rotation): modelObject = self.modelList[self.ui.modelList.currentRow()] transform = modelObject.transform transform.RotateZ((float(rotation) - modelObject.CurrentZRotation)) modelObject.CurrentZRotation = modelObject.CurrentZRotation + ( float(rotation) - modelObject.CurrentZRotation) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetTransform(transform) transformFilter.SetInputConnection(modelObject.reader.GetOutputPort()) transformFilter.Update() modelObject.mapper.SetInputConnection(transformFilter.GetOutputPort()) modelObject.mapper.Update() self.ren.Render() self.ModelView.Render() def Update_Scale(self, scale): modelObject = self.modelList[self.ui.modelList.currentRow()] transform = modelObject.transform self.reader = vtk.vtkSTLReader() self.reader.SetFileName(str(self.filename)) self.mapper = vtk.vtkPolyDataMapper() self.mapper.SetInputConnection(self.reader.GetOutputPort()) #create model actor self.actor = vtk.vtkActor() self.actor.GetProperty().SetColor(1, 1, 1) self.actor.GetProperty().SetOpacity(1) self.actor.SetMapper(self.mapper) #create outline mapper self.outline = vtk.vtkOutlineFilter() self.outline.SetInputConnection(self.reader.GetOutputPort()) self.outlineMapper = vtk.vtkPolyDataMapper() self.outlineMapper.SetInputConnection(self.outline.GetOutputPort()) #create outline actor self.outlineActor = vtk.vtkActor() self.outlineActor.SetMapper(self.outlineMapper) #add actors to parent render window self.parent.ren.AddActor(self.actor) self.parent.ren.AddActor(self.outlineActor) delta = modelObject.PreviousScale - modelObject.CurrentScale modelObject.transform #transform.Scale((float(scale)-modelObject.CurrentScale)/100.0, (float(scale)-modelObject.CurrentScale)/100.0, (float(scale)-modelObject.CurrentScale)/100.0) transform.Scale modelObject.CurrentScale = modelObject.CurrentScale + ( float(scale) - modelObject.CurrentScale) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetTransform(modelObject.transform) transformFilter.SetInputConnection(modelObject.reader.GetOutputPort()) transformFilter.Update() modelObject.mapper.SetInputConnection(transformFilter.GetOutputPort()) modelObject.mapper.Update() self.ren.Render() self.ModelView.Render() def LoadSettingsFromConfigFile(self): self.imageHeight = int( self.parser.get('slicing_settings', 'Image_Height')) self.imageWidth = int( self.parser.get('slicing_settings', 'Image_Width')) self.startingDepth = int( self.parser.get('slicing_settings', 'Starting_Depth')) self.endingDepth = int( self.parser.get('slicing_settings', 'Ending_Depth')) self.slicingIncrement = int( self.parser.get('slicing_settings', 'Slicing_Increment')) self.slicingplane = self.parser.get('slicing_settings', 'Slicing_Plane') def OpenSettingsDialog(self): self.SettingsDialog = StartSettingsDialog(self) self.connect(self.SettingsDialog, QtCore.SIGNAL('ApplySettings()'), self.getSettingsDialogValues) self.SettingsDialog.imageHeight.setText(str(self.imageHeight)) self.SettingsDialog.imageWidth.setText(str(self.imageWidth)) self.SettingsDialog.startingDepth.setText(str(self.startingDepth)) self.SettingsDialog.endingDepth.setText(str(self.endingDepth)) self.SettingsDialog.slicingIncrement.setText(str( self.slicingIncrement)) self.slicingplaneDict = {"XZ": 0, "XY": 1, "YZ": 2} try: self.SettingsDialog.slicingPlane.setCurrentIndex( self.slicingplaneDict[self.slicingplane]) except: #anything other than a valid entry will default to XZ (index 0) self.SettingsDialog.slicingPlane.setCurrentIndex(0) self.SettingsDialog.exec_() def getSettingsDialogValues(self): self.imageHeight = int(self.SettingsDialog.imageHeight.text()) self.parser.set('slicing_settings', 'Image_Height', "%s" % self.imageHeight) self.imageWidth = int(self.SettingsDialog.imageWidth.text()) self.parser.set('slicing_settings', 'Image_Width', "%s" % self.imageWidth) self.startingDepth = int(self.SettingsDialog.startingDepth.text()) self.parser.set('slicing_settings', 'Starting_Depth', "%s" % self.startingDepth) self.endingDepth = int(self.SettingsDialog.endingDepth.text()) self.parser.set('slicing_settings', 'Ending_Depth', "%s" % self.endingDepth) self.slicingIncrement = int( self.SettingsDialog.slicingIncrement.text()) self.parser.set('slicing_settings', 'Slicing_Increment', "%s" % self.slicingIncrement) self.slicingplane = self.SettingsDialog.slicingPlane.currentText() self.parser.set('slicing_settings', 'Slicing_Plane', "%s" % self.slicingplane) filename = 'sliceconfig.ini' if hasattr(sys, '_MEIPASS'): # PyInstaller >= 1.6 APPNAME = '3DLP' APPDATA = os.path.join(os.environ['APPDATA'], APPNAME) filename = os.path.join(APPDATA, filename) outputini = open( filename, 'w' ) #open a file pointer for the config file parser to write changes to self.parser.write(outputini) outputini.close() #done writing config file changes else: #otherwise it's running in pydev environment: use the dev config file os.chdir(os.path.dirname(sys.argv[0])) filename = os.path.join(os.path.dirname(sys.argv[0]), filename) outputini = open( filename, 'w' ) #open a file pointer for the config file parser to write changes to self.parser.write(outputini) outputini.close() #done writing config file changes
class MainWindow(QtGui.QMainWindow, display.Ui_MainWindow): write = pyqtSignal(float, float, int, list) pointcloud_changed = pyqtSignal(list) need_pointcloud_setup = pyqtSignal() def __init__(self): super(self.__class__, self).__init__() self.setupUi(self) #Instance Variables self.point_array = [] self.vl = QtGui.QVBoxLayout() self.vtkWidget = QVTKRenderWindowInteractor(self.frame) self.vl.addWidget(self.vtkWidget) self.frame.setLayout(self.vl) print(self.frame.height, self.frame.width) self.renderer = vtk.vtkRenderer() self.pointCloud = v.VtkPointCloud() self.renderWindowInteractor = vtk.vtkRenderWindowInteractor() self.setup_vtk self.ser = 0 #Signal slots of buttons self.startButton.clicked.connect(lambda: self.start_scanning(self.ser)) self.stopButton.clicked.connect(lambda: self.stop_scanning(self.ser)) #Actions for menu bar self.actionSave_CSV.triggered.connect( lambda: write_CSV(self.point_array)) self.actionSave_STL.triggered.connect( lambda: write_STL(self.pointCloud)) self.actionClear.triggered.connect(lambda: self.clear_pointcloud()) #Scan thread self.scan_thread = ScanThread(self) self.write.connect(self.write_to_browser) self.pointcloud_changed.connect(self.update_pointcloud) self.need_pointcloud_setup.connect(self.setup_vtk) def write_something(self, x): self.textBrowser.append(x) def setup_vtk(self): # Renderer self.renderer.AddActor(self.pointCloud.vtkActor) self.renderer.SetBackground(0.0, 0.0, 0.0) self.renderer.ResetCamera() self.vtkWidget.GetRenderWindow().AddRenderer(self.renderer) self.vtkWidget.GetRenderWindow().Render() #self.vtkWidget.GetRenderWindow().SetSize(732,487) self.vtkWidget.Initialize() def update_vtk(self): # Renderer self.renderer.ResetCamera() # Render Window self.vtkWidget.GetRenderWindow().Render() def start_scanning(self, ser): #This is the enable signal to start scanning self.textBrowser.append("Start Scanning \n") QtGui.QApplication.processEvents() self.serial_setup() #Set the correct speed if (self.radioButton_slow.isChecked()): self.ser.write('2') self.textBrowser.append("Speed set to slow \n") elif (self.radioButton_medium.isChecked()): self.ser.write('3') self.textBrowser.append("Speed set to medium \n") elif (self.radioButton_fast.isChecked()): self.textBrowser.append("Speed set to fast \n") self.ser.write('4') #Send enable setting self.ser.write('1') #self.generate_pointcloud() if not self.scan_thread.isRunning(): self.scan_thread.start() def stop_scanning(self, ser): if self.scan_thread.isRunning(): self.scan_thread.terminate() #Disable signal for scanning self.textBrowser.append("Stop Scanning \n") QtGui.QApplication.processEvents() ser.write('0') #self.vtkWidget.Start() def serial_setup(self): if self.ser == 0: self.ser = serial.Serial('COM3', 9600) #On windows, starting the serial port takes sometime. According to the arduino website, sleeping for 2 seconds kis a way of getting around it. time.sleep(2) def write_to_browser(self, pan_angle, tilt_angle, distance, point): self.textBrowser.append("pan: %f tilt: %f distance:%f \n" % (pan_angle, tilt_angle, distance)) self.textBrowser.append("x: %f y: %f z: %f \n" % (point[0], point[1], point[2])) def update_pointcloud(self, point): self.point_array.append(point) self.pointCloud.addPoint(point) self.update_vtk() def clear_pointcloud(self): del self.point_array[:] self.textBrowser.setText("") self.pointCloud.clearPoints() self.update_vtk()
class ParallelCoordinatesWidget(QCellWidget): def __init__(self, parent=None): QCellWidget.__init__(self, parent) centralLayout = QtGui.QVBoxLayout() self.setLayout(centralLayout) centralLayout.setMargin(0) centralLayout.setSpacing(0) self.view = vtk.vtkContextView() self.widget = QVTKRenderWindowInteractor( self, rw=self.view.GetRenderWindow(), iren=self.view.GetInteractor()) self.chart = vtk.vtkChartParallelCoordinates() self.view.GetScene().AddItem(self.chart) self.layout().addWidget(self.widget) # Create a annotation link to access selection in parallel coordinates view self.annotationLink = vtk.vtkAnnotationLink() # If you don't set the FieldType explicitly it ends up as UNKNOWN (as of 21 Feb 2010) # See vtkSelectionNode doc for field and content type enum values self.annotationLink.GetCurrentSelection().GetNode(0).SetFieldType( 1) # Point self.annotationLink.GetCurrentSelection().GetNode(0).SetContentType( 4) # Indices # Connect the annotation link to the parallel coordinates representation self.chart.SetAnnotationLink(self.annotationLink) self.annotationLink.AddObserver("AnnotationChangedEvent", self.selectionCallback) def updateContents(self, inputPorts): (self.coord, matrix) = inputPorts if self.coord is not None: self.coord.register(self) self.createTable(matrix) self.widget.Initialize() # Capture window into history for playback # Call this at the end to capture the image after rendering QCellWidget.updateContents(self, inputPorts) def updateSelection(self, selectedIds): if len(selectedIds) == 0: return Ids = VN.numpy_to_vtkIdTypeArray(np.array(selectedIds), deep=True) node = vtk.vtkSelectionNode() node.SetContentType(vtk.vtkSelectionNode.INDICES) node.SetFieldType(vtk.vtkSelectionNode.POINT) node.SetSelectionList(Ids) selection = vtk.vtkSelection() selection.AddNode(node) self.annotationLink.SetCurrentSelection(selection) self.widget.Render() def createTable(self, matrix): table = vtk.vtkTable() for col, attr in zip(matrix.values.T, matrix.attributes): column = VN.numpy_to_vtk(col.copy(), deep=True) column.SetName(attr) table.AddColumn(column) self.chart.GetPlot(0).SetInput(table) min_ = matrix.values.min() - 0.01 max_ = matrix.values.max() + 0.01 for i in range(self.chart.GetNumberOfAxes()): self.chart.GetAxis(i).SetRange(min_, max_) self.chart.GetAxis(i).SetBehavior(vtk.vtkAxis.FIXED) # self.chart.GetAxis(i).SetPosition(vtk.vtkAxis.LEFT) # self.chart.GetAxis(i).GetTitleProperties().SetOrientation(30) def selectionCallback(self, caller, event): if self.coord is None: return annSel = self.annotationLink.GetCurrentSelection() if annSel.GetNumberOfNodes() > 0: idxArr = annSel.GetNode(0).GetSelectionList() if idxArr.GetNumberOfTuples() > 0: self.coord.unregister(self) self.coord.notifyModules(VN.vtk_to_numpy(idxArr)) self.coord.register(self)
class ModelmapViewer(module_template.Viewer): """Uses vtk to display the model in 3D as an isosurface or a slice. This is not a widget but contains one, accessible with get_widget()""" def __init__(self, parent=None): super(ModelmapViewer, self).__init__(parent) self._surface_algorithm = None self._surface_actor = None self._volume_scalars = None self._volume = None self._surface_level = 0.5 self._color = (0.2, 0.8, 0.2) self._planes = [] self._volume_max = 0. self._volume_numpy = None self._vtk_widget = QVTKRenderWindowInteractor( self._widget) # _vtk_widget is actually the RenderWindowInteractor self._vtk_widget.SetInteractorStyle( vtk.vtkInteractorStyleRubberBandPick()) layout = QtGui.QVBoxLayout() layout.addWidget(self._vtk_widget) self._widget.setLayout(layout) #self._vtk_widget.Initialize() #self._vtk_widget.Start() self._renderer = vtk.vtkRenderer() self._renderer.SetDraw(0) self._vtk_render_window = self._vtk_widget.GetRenderWindow() self._vtk_render_window.AddRenderer(self._renderer) #self._renderer = self._vtk_widget.GetRenderWindow().GetRenderer() self._lut = vtk_tools.get_lookup_table(0., 1., log=False, colorscale="jet") self._create_volume_map() #self._setup_slices() #self._setup_surface() white = (1., 1., 1.) self._renderer.SetBackground(white) #self.set_view_type(VIEW_TYPE.slice) #self._vtk_widget.GetRenderWindow().Render() def initialize(self): super(ModelmapViewer, self).initialize() self._vtk_widget.Initialize() self._setup_slices() self._setup_surface() #self.set_view_type(VIEW_TYPE.surface) self.set_view_type(VIEW_TYPE.slice) #self._vtk_widget.GetRenderWindow().Render() self._renderer.ResetCamera() # camera = self._renderer.GetActiveCamera() # camera.SetPosition(2., 2., 2.) # camera.SetFocalPoint(0., 0., 0.) self._vtk_render_window.Render() # print self._renderer.GetVolumes() # print self._renderer.VisibleActorCount() # print self._surface_actor.GetBounds() # print self._renderer.GetActiveCamera().GetPosition() def set_active(self, state): super(ModelmapViewer, self).set_active(state) self._renderer.SetDraw(int(state)) def _create_volume_map(self): """Create the vtk objects containing the data.""" self._volume_max = 1. self._volume = vtk.vtkImageData() default_side = 100 self._volume.SetExtent(0, default_side - 1, 0, default_side - 1, 0, default_side - 1) self._volume_numpy = numpy.zeros((default_side, ) * 3, dtype="float32", order="C") self._volume_numpy[:] = 0. self._volume_max = self._volume_numpy.max() self._volume_scalars = vtk.vtkFloatArray() self._volume_scalars.SetNumberOfValues(default_side**3) self._volume_scalars.SetNumberOfComponents(1) self._volume_scalars.SetName("Values") self._volume_scalars.SetVoidArray(self._volume_numpy, default_side**3, 1) self._volume.GetPointData().SetScalars(self._volume_scalars) def _setup_surface(self): """Create the isosurface object, mapper and actor""" self._surface_level = INIT_SURFACE_LEVEL self._surface_algorithm = vtk.vtkMarchingCubes() if VTK_VERSION < 6: self._surface_algorithm.SetInput(self._volume) else: self._surface_algorithm.SetInputData(self._volume) self._surface_algorithm.ComputeNormalsOn() self._surface_algorithm.SetValue(0, self._surface_level) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(self._surface_algorithm.GetOutputPort()) mapper.ScalarVisibilityOff() self._surface_actor = vtk.vtkActor() self._surface_actor.GetProperty().SetColor(self._color[0], self._color[1], self._color[2]) self._surface_actor.SetMapper(mapper) self._renderer.AddViewProp(self._surface_actor) def _setup_slices(self): """Create the slices. No actor required in this case""" picker = vtk.vtkCellPicker() picker_tolerance = 0.005 picker.SetTolerance(picker_tolerance) text_color = (0., 0., 0.) if len(self._planes) != 0: raise RuntimeError("planes initialized twice") self._planes.append(vtk.vtkImagePlaneWidget()) if VTK_VERSION < 6: self._planes[0].SetInput(self._volume) else: self._planes[0].SetInputData(self._volume) self._planes[0].UserControlledLookupTableOn() self._planes[0].SetLookupTable(self._lut) self._planes[0].SetPlaneOrientationToXAxes() self._planes[0].SetSliceIndex( self._volume.GetExtent()[1] / 2) # GetExtent returns a six length array, begin-end pairs self._planes[0].DisplayTextOn() self._planes[0].GetTextProperty().SetColor(text_color) self._planes[0].SetPicker(picker) self._planes[0].SetLeftButtonAction(1) self._planes[0].SetMiddleButtonAction(2) self._planes[0].SetRightButtonAction(0) self._planes[0].SetInteractor(self._vtk_widget) # self._planes[0].On() self._planes.append(vtk.vtkImagePlaneWidget()) if VTK_VERSION < 6: self._planes[1].SetInput(self._volume) else: self._planes[1].SetInputData(self._volume) self._planes[1].UserControlledLookupTableOn() self._planes[1].SetLookupTable(self._lut) self._planes[1].SetPlaneOrientationToZAxes() self._planes[1].SetSliceIndex( self._volume.GetExtent()[5] / 2) # GetExtent returns a six length array, begin-end pairs self._planes[1].DisplayTextOn() self._planes[1].GetTextProperty().SetColor(text_color) self._planes[1].SetPicker(picker) self._planes[1].SetLeftButtonAction(1) self._planes[1].SetMiddleButtonAction(2) self._planes[1].SetRightButtonAction(0) self._planes[1].SetInteractor(self._vtk_widget) # self._planes[1].On() def set_surface_visibility(self, state): """Hide or show the surface, used when swithching between the surface and""" if state: self._surface_actor.SetVisibility(1) else: self._surface_actor.SetVisibility(0) def set_slice_visibility(self, state): """Hide or show the slices, used when swithching between the surface and""" if state: self._planes[0].SetEnabled(1) self._planes[1].SetEnabled(1) else: self._planes[0].SetEnabled(0) self._planes[1].SetEnabled(0) def set_view_type(self, view_type): """Switch between viewing slices or isosurface.""" if view_type == VIEW_TYPE.surface: self.set_slice_visibility(False) self.set_surface_visibility(True) elif view_type == VIEW_TYPE.slice: self.set_surface_visibility(False) self.set_slice_visibility(True) def _update_surface_level(self): """Set the isosurface level based on the relative level in _surface_level and the maximum value of the current model.""" if self._surface_algorithm != None: self._surface_algorithm.SetValue( 0, self._surface_level * self._volume_max) self._surface_algorithm.Modified() self._vtk_widget.Render() def set_surface_level(self, value): """Change the relative isosurface level""" if value < 0. or value > 1.: raise ValueError("Surface value must be in [0.,1.], was %g\n", value) self._surface_level = value self._update_surface_level() def get_surface_level(self): """Get the relative isosurface level""" return self._surface_level def plot_map(self, new_data_array): """Update the viwer to show the provided map.""" if (new_data_array.shape != self._volume_numpy.shape): self.plot_map_init(new_data_array) return self._volume_numpy[:, :, :] = new_data_array self._volume_max = new_data_array.max() self._lut.SetTableRange(new_data_array.min(), new_data_array.max()) self._update_surface_level() self._volume_scalars.Modified() #self._vtk_widget.GetRenderWindow().Render() self._vtk_render_window.Render() def plot_map_init(self, new_data_array): """As opposed to plot_map() this function accepts maps of different side than the active one""" self._volume_max = new_data_array.max() old_extent = numpy.array(self._volume.GetExtent()) self._volume.SetExtent(0, new_data_array.shape[0] - 1, 0, new_data_array.shape[1] - 1, 0, new_data_array.shape[2] - 1) self._volume_numpy = numpy.ascontiguousarray(new_data_array, dtype="float32") self._volume_scalars = vtk.vtkFloatArray() self._volume_scalars.SetNumberOfValues( numpy.product(self._volume_numpy.shape)) self._volume_scalars.SetNumberOfComponents(1) self._volume_scalars.SetName("Values") self._volume_scalars.SetVoidArray( self._volume_numpy, numpy.product(self._volume_numpy.shape), 1) self._volume.GetPointData().SetScalars(self._volume_scalars) # self._volume_scalars.SetNumberOfValues(new_data_array.shape[0]*new_data_array.shape[1]*new_data_array.shape[2]) # for i, this_value in enumerate(numpy.ravel(new_data_array.swapaxes(0, 2))): # self._volume_scalars.SetValue(i, this_value) self._lut.SetTableRange(new_data_array.min(), new_data_array.max()) #self._volume.GetPointData().SetScalars(self._volume_scalars) self._update_surface_level() self._volume_scalars.Modified() self._volume.Modified() new_extent = numpy.array(self._volume.GetExtent()) scaling_factors = numpy.float64(new_extent[1::2]) / numpy.float64( old_extent[1::2]) self._planes[0].SetOrigin( numpy.array(self._planes[0].GetOrigin() * scaling_factors)) self._planes[0].SetPoint1( numpy.array(self._planes[0].GetPoint1() * scaling_factors)) self._planes[0].SetPoint2( numpy.array(self._planes[0].GetPoint2() * scaling_factors)) self._planes[1].SetOrigin( numpy.array(self._planes[1].GetOrigin() * scaling_factors)) self._planes[1].SetPoint1( numpy.array(self._planes[1].GetPoint1() * scaling_factors)) self._planes[1].SetPoint2( numpy.array(self._planes[1].GetPoint2() * scaling_factors)) # self._planes[0].Modified() # self._planes[1].Modified() self._planes[0].UpdatePlacement() self._planes[1].UpdatePlacement() self._vtk_widget.Render() self._renderer.Render()
class SliceViewer(module_template.Viewer): """Plots the slices using vtk.""" def __init__(self, data, parent): super(SliceViewer, self).__init__() self._data = data self._lut = None self._actors = {} self._camera = None #self._slice_generator = SliceGenerator(self._data.get_image_side(), self._data.get_curvature()) #self._workspace = QtGui.QWorkspace() self._widget = QtGui.QWidget(parent) self._vtk_widget = QVTKRenderWindowInteractor(self._widget) self._vtk_widget.SetInteractorStyle( vtk.vtkInteractorStyleRubberBandPick()) #self._vtk_widget = QtGui.QPushButton("Foo", parent=self._widget) layout = QtGui.QVBoxLayout() #layout.addWidget(self._workspace) layout.addWidget(self._vtk_widget) #self._workspace.addWindow(self._vtk_widget) self._widget.setLayout(layout) # self._vtk_widget.Initialize() # self._vtk_widget.Start() self._renderer = vtk.vtkRenderer() self._renderer.SetDraw(0) self._vtk_render_window = self._vtk_widget.GetRenderWindow() self._vtk_render_window.AddRenderer(self._renderer) #self._setup_slice_view() def initialize(self): #pass self._vtk_widget.Initialize() self._setup_slice_view() self._slice_generator = SliceGenerator(self._data.get_image_side(), self._data.get_curvature()) def set_active(self, state): super(SliceViewer, self).set_active(state) self._renderer.SetDraw(int(state)) def _draw(self): if VTK_VERSION < 6: self._vtk_render_window.Render() else: if self._vtk_render_window.IsDrawable(): self._vtk_render_window.Render() def _setup_slice_view(self): """Setup background, camera and LUT.""" self._renderer.SetBackground(1, 1, 1) # camera self._camera = vtk.vtkCamera() self._camera.SetPosition(130, 130, 170) self._camera.SetFocalPoint(0., 0., 0.) self._camera.SetViewUp(0, 0, 1) self._renderer.SetActiveCamera(self._camera) # self._lut = vtk_tools.get_lookup_table(self._data.get_total_min(), self._data.get_total_max(), # log=True, colorscale="jet") self._lut = vtk_tools.get_lookup_table(0.1, 10., log=True, colorscale="jet") def _update_lut(self): """Call after new images were added to update the LUT to include the entire range.""" # self._lut = vtk_tools.get_lookup_table(self._data.get_total_min(), self._data.get_total_max(), # log=True, colorscale="jet") #self._lut.SetTableRange(self._data.get_total_min(), self._data.get_total_max()) self._lut.SetTableRange( max(self._data.get_total_min(), 0.0001 * self._data.get_total_max()), self._data.get_total_max()) self._lut.Build() self._draw() def _add_poly_data(self, this_poly_data, identifier): """Add a polydata and give it an id by which it can be accessed later.""" if identifier in self._actors: raise ValueError("Actor with identifier %d is already plotted" % identifier) mapper = vtk.vtkPolyDataMapper() #mapper.SetInput(this_poly_data) if VTK_VERSION < 6: mapper.SetInput(this_poly_data) else: mapper.SetInputData(this_poly_data) mapper.SetScalarModeToUsePointData() mapper.UseLookupTableScalarRangeOn() self._update_lut() mapper.SetLookupTable(self._lut) actor = vtk.vtkActor() actor.SetMapper(mapper) #actor.GetProperty().SetOpacity(0.999999) self._actors[identifier] = actor self._renderer.AddActor(actor) #self._renderer.UseDepthPeelingOn() def _remove_poly_data(self, identifier): """Remove polydata with the specified id.""" if not identifier in self._actors: raise ValueError( "Trying to remove actor with id %d that doesn't exist." % identifier) self._renderer.RemoveActor(self._actors[identifier]) del self._actors[identifier] def add_slice(self, index): """Add the image with the specified index to the view.""" self._add_poly_data( self._slice_generator.get_slice(self._data.get_image(index), self._data.get_rotation(index)), index) self._draw() def add_multiple_slices(self, index_list): """Add all the specified images to the view.""" for index in index_list: self._add_poly_data( self._slice_generator.get_slice( self._data.get_image(index), self._data.get_rotation(index)), index) self._draw() def remove_slice(self, index, render=True): """Remove the specified image from the view.""" self._remove_poly_data(index) #self._vtk_widget.GetRenderWindow().Render() if render: self._draw() def remove_all_slices(self): """Clear the view.""" for index in self.get_all_indices(): self._remove_poly_data(index) def get_all_indices(self): """Get all ids currently known to the viewer.""" return self._actors.keys()
class SimulationGui(QtGui.QMainWindow): """ class for the graphical user interface """ # TODO enable closing plot docks by right-clicking their name # TODO add ability to stop an simulation # TODO add ability to stop regime execution runSimulation = pyqtSignal() playbackTimeChanged = pyqtSignal() regimeFinished = pyqtSignal() finishedRegimeBatch = pyqtSignal() def __init__(self): # constructor of the base class QtGui.QMainWindow.__init__(self) self._logger = logging.getLogger(self.__class__.__name__) # Create Simulation Backend self.guiProgress = None self.cmdProgress = None self.sim = SimulatorInteractor(self) self.runSimulation.connect(self.sim.run_simulation) self.sim.simulation_finished.connect(self.simulation_finished) self.sim.simulation_failed.connect(self.simulation_failed) self.currentDataset = None # sim setup viewer self.targetView = SimulatorView(self) self.targetView.setModel(self.sim.target_model) self.targetView.expanded.connect(self.target_view_changed) self.targetView.collapsed.connect(self.target_view_changed) # sim results viewer self.result_view = QtGui.QTreeView() # the docking area allows to rearrange the user interface at runtime self.area = pg.dockarea.DockArea() # Window properties self.setCentralWidget(self.area) self.resize(1000, 700) self.setWindowTitle("PyMoskito") res_path = get_resource("mosquito.png") icon = QtGui.QIcon(res_path) self.setWindowIcon(icon) # create docks self.propertyDock = pg.dockarea.Dock("Properties") self.vtkDock = pg.dockarea.Dock("Simulation") self.regimeDock = pg.dockarea.Dock("Regimes") self.dataDock = pg.dockarea.Dock("Data") self.logDock = pg.dockarea.Dock("Log") self.plotDocks = [] self.plotDocks.append(pg.dockarea.Dock("Placeholder")) self.plotWidgets = [] self.timeLines = [] # arrange docks self.area.addDock(self.vtkDock, "right") self.area.addDock(self.regimeDock, "left", self.vtkDock) self.area.addDock(self.propertyDock, "bottom", self.regimeDock) self.area.addDock(self.dataDock, "bottom", self.propertyDock) self.area.addDock(self.plotDocks[-1], "bottom", self.vtkDock) self.area.addDock(self.logDock, "bottom", self.dataDock) # add widgets to the docks self.propertyDock.addWidget(self.targetView) # vtk window self.vtkLayout = QtGui.QVBoxLayout() self.frame = QtGui.QFrame() self.vtkWidget = QVTKRenderWindowInteractor(self.frame) self.vtkLayout.addWidget(self.vtkWidget) self.frame.setLayout(self.vtkLayout) self.vtkDock.addWidget(self.frame) self.vtk_renderer = vtk.vtkRenderer() self.vtkWidget.GetRenderWindow().AddRenderer(self.vtk_renderer) # check if there is a registered visualizer available_vis = get_registered_visualizers() self._logger.info("found visualizers: {}".format( [name for cls, name in available_vis])) if available_vis: # instantiate the first one self._logger.info("loading visualizer '{}'".format( available_vis[0][1])) self.visualizer = available_vis[0][0](self.vtk_renderer) self.vtkWidget.Initialize() else: self.visualizer = None # regime window self.regime_list = QtGui.QListWidget(self) self.regime_list.setSelectionMode( QtGui.QAbstractItemView.ExtendedSelection) self.regimeDock.addWidget(self.regime_list) self.regime_list.itemDoubleClicked.connect(self.regime_dclicked) self._regimes = [] self.regime_file_name = "" # data window self.dataList = QtGui.QListWidget(self) self.dataDock.addWidget(self.dataList) self.dataList.itemDoubleClicked.connect(self.create_plot) # actions for simulation control self.actSimulate = QtGui.QAction(self) self.actSimulate.setText("Simulate") self.actSimulate.setIcon(QtGui.QIcon(get_resource("simulate.png"))) self.actSimulate.triggered.connect(self.start_simulation) # actions for animation control self.actPlayPause = QtGui.QAction(self) self.actPlayPause.setText("Play") self.actPlayPause.setIcon(QtGui.QIcon(get_resource("play.png"))) self.actPlayPause.setDisabled(True) self.actPlayPause.triggered.connect(self.play_animation) self.actStop = QtGui.QAction(self) self.actStop.setText("Stop") self.actStop.setIcon(QtGui.QIcon(get_resource("stop.png"))) self.actStop.setDisabled(True) self.actStop.triggered.connect(self.stop_animation) self.speedDial = QtGui.QDial() self.speedDial.setDisabled(True) self.speedDial.setMinimum(0) self.speedDial.setMaximum(100) self.speedDial.setValue(50) self.speedDial.setSingleStep(1) self.speedDial.resize(24, 24) self.speedDial.valueChanged.connect(self.update_playback_gain) self.timeSlider = QtGui.QSlider(QtCore.Qt.Horizontal, self) self.timeSlider.setMinimum(0) self.timeSliderRange = 1000 self.timeSlider.setMaximum(self.timeSliderRange) self.timeSlider.setTickInterval(1) self.timeSlider.setTracking(True) self.timeSlider.setDisabled(True) self.timeSlider.valueChanged.connect(self.update_playback_time) self.playbackTime = 0 self.playbackGain = 1 self.currentStepSize = 0 self.currentEndTime = 0 self.playbackTimer = QTimer() self.playbackTimer.timeout.connect(self.increment_playback_time) self.playbackTimeChanged.connect(self.update_gui) self.playbackTimeout = 33 # in [ms] -> 30 fps self.actSave = QtGui.QAction(self) self.actSave.setText('Save') self.actSave.setIcon(QtGui.QIcon(get_resource("save.png"))) self.actSave.setDisabled(True) self.actSave.triggered.connect(self.export_simulation_data) self.actLoadRegimes = QtGui.QAction(self) self.actLoadRegimes.setText("load regimes") self.actLoadRegimes.setIcon(QtGui.QIcon(get_resource("load.png"))) self.actLoadRegimes.setDisabled(False) self.actLoadRegimes.triggered.connect(self.load_regime_dialog) self.actExecuteRegimes = QtGui.QAction(self) self.actExecuteRegimes.setText("execute all regimes") self.actExecuteRegimes.setIcon( QtGui.QIcon(get_resource("execute_regimes.png"))) self.actExecuteRegimes.setDisabled(True) self.actExecuteRegimes.triggered.connect(self.execute_regimes_clicked) self.actPostprocessing = QtGui.QAction(self) self.actPostprocessing.setText("launch postprocessor") self.actPostprocessing.setIcon( QtGui.QIcon(get_resource("processing.png"))) self.actPostprocessing.setDisabled(False) self.actPostprocessing.triggered.connect(self.postprocessing_clicked) self.act_reset_camera = QtGui.QAction(self) self.act_reset_camera.setText("reset camera") self.act_reset_camera.setIcon( QtGui.QIcon(get_resource("reset_camera.png"))) self.act_reset_camera.setDisabled(not self.visualizer.can_reset_view) self.act_reset_camera.triggered.connect(self.reset_camera_clicked) # toolbar for control self.toolbarSim = QtGui.QToolBar("Simulation") self.toolbarSim.setIconSize(QtCore.QSize(32, 32)) self.addToolBar(self.toolbarSim) self.toolbarSim.addAction(self.actLoadRegimes) self.toolbarSim.addAction(self.actSave) self.toolbarSim.addSeparator() self.toolbarSim.addAction(self.actSimulate) self.toolbarSim.addAction(self.actExecuteRegimes) self.toolbarSim.addSeparator() self.toolbarSim.addAction(self.actPlayPause) self.toolbarSim.addAction(self.actStop) self.toolbarSim.addWidget(self.speedDial) self.toolbarSim.addWidget(self.timeSlider) self.toolbarSim.addAction(self.actPostprocessing) self.toolbarSim.addAction(self.act_reset_camera) self.postprocessor = None # regime management self.runningBatch = False self._current_regime_index = 0 self._regimes = [] self.regimeFinished.connect(self.run_next_regime) self.finishedRegimeBatch.connect(self.regime_batch_finished) # log dock self.logBox = QPlainTextEditLogger(self) self.logBox.setLevel(logging.INFO) formatter = logging.Formatter( fmt="%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%H:%M:%S") self.logBox.setFormatter(formatter) self.log_filter = PostFilter(invert=True) self.logBox.addFilter(self.log_filter) logging.getLogger().addHandler(self.logBox) self.logDock.addWidget(self.logBox.widget) # status bar self.status = QtGui.QStatusBar(self) self.setStatusBar(self.status) self.statusLabel = QtGui.QLabel("Ready.") self.statusBar().addPermanentWidget(self.statusLabel) self.timeLabel = QtGui.QLabel("current time: 0.0") self.statusBar().addPermanentWidget(self.timeLabel) # shortcuts self.delShort = QtGui.QShortcut( QtGui.QKeySequence(QtCore.Qt.Key_Delete), self.regime_list) self.delShort.activated.connect(self.remove_regime_items) self.shortOpenRegime = QtGui.QShortcut(QtGui.QKeySequence.Open, self) self.shortOpenRegime.activated.connect(self.load_regime_dialog) self.shortSaveResult = QtGui.QShortcut(QtGui.QKeySequence.Save, self) self.shortSaveResult.activated.connect(self.export_simulation_data) self.shortSaveResult.setEnabled(False) self.shortSpeedUp = QtGui.QShortcut(QtGui.QKeySequence.ZoomIn, self) self.shortSpeedUp.activated.connect(self.increment_playback_speed) self.shortSpeedDown = QtGui.QShortcut(QtGui.QKeySequence.ZoomOut, self) self.shortSpeedDown.activated.connect(self.decrement_playback_speed) self.shortSpeedReset = QtGui.QShortcut( QtGui.QKeySequence(QtCore.Qt.CTRL + QtCore.Qt.Key_0), self) self.shortSpeedReset.activated.connect(self.reset_playback_speed) self.shortRunSimulation = QtGui.QShortcut(QtGui.QKeySequence('F5'), self) self.shortRunSimulation.activated.connect(self.start_simulation) self.shortRunRegimeBatch = QtGui.QShortcut(QtGui.QKeySequence('F6'), self) self.shortRunRegimeBatch.activated.connect( self.execute_regimes_clicked) self.shortRunPostprocessing = QtGui.QShortcut(QtGui.QKeySequence('F7'), self) self.shortRunPostprocessing.activated.connect( self.postprocessing_clicked) self.shortPlayPause = QtGui.QShortcut( QtGui.QKeySequence(QtCore.Qt.Key_Space), self) self.shortPlayPause.activated.connect(self.play_animation) self.shortPlayPause.setEnabled(False) self.postprocessor = None self._logger.info("Simulation GUI is up and running.") def set_visualizer(self, vis): self.visualizer = vis self.vtkWidget.Initialize() def play_animation(self): """ play the animation """ # self.statusLabel.setText('playing animation') self.actPlayPause.setText("Pause") self.actPlayPause.setIcon(QtGui.QIcon(get_resource("pause.png"))) self.actPlayPause.triggered.disconnect(self.play_animation) self.actPlayPause.triggered.connect(self.pause_animation) self.shortPlayPause.activated.disconnect(self.play_animation) self.shortPlayPause.activated.connect(self.pause_animation) self.playbackTimer.start(self.playbackTimeout) def pause_animation(self): """ pause the animation """ # self.statusLabel.setText('pausing animation') self.playbackTimer.stop() self.actPlayPause.setText("Play") self.actPlayPause.setIcon(QtGui.QIcon(get_resource("play.png"))) self.actPlayPause.triggered.disconnect(self.pause_animation) self.actPlayPause.triggered.connect(self.play_animation) self.shortPlayPause.activated.disconnect(self.pause_animation) self.shortPlayPause.activated.connect(self.play_animation) def stop_animation(self): """ pause the animation """ # self.statusLabel.setText('stopping animation') if self.actPlayPause.text() == "Pause": # animation is playing -> stop it self.playbackTimer.stop() self.actPlayPause.setText("Play") self.actPlayPause.setIcon(QtGui.QIcon(get_resource("play.png"))) self.actPlayPause.triggered.disconnect(self.pause_animation) self.actPlayPause.triggered.connect(self.play_animation) self.shortPlayPause.activated.disconnect(self.pause_animation) self.shortPlayPause.activated.connect(self.play_animation) self.timeSlider.setValue(0) def start_simulation(self): """ start the simulation and disable start button """ regime_name = str( self.regime_list.item(self._current_regime_index).text()) self.statusLabel.setText(u"simulating {}".format(regime_name)) self._logger.info(u"Simulating: {}".format(regime_name)) self.actSimulate.setDisabled(True) self.shortRunSimulation.setEnabled(False) self.shortRunRegimeBatch.setEnabled(False) self.actExecuteRegimes.setDisabled(True) self.guiProgress = QtGui.QProgressBar(self) self.sim.simulationProgressChanged.connect(self.guiProgress.setValue) self.statusBar().addWidget(self.guiProgress) self.runSimulation.emit() def export_simulation_data(self, ok): """ query the user for a custome name and export the current simulation results :param ok: unused parameter from QAction.triggered() Signal """ res, ok = QtGui.QInputDialog.getText( self, u"PyMoskito", u"Please specify regime a name", QtGui.QLineEdit.Normal, self._regimes[self._current_regime_index]["Name"]) if not ok: return name = unicode(res.toUtf8(), encoding="utf-8") if not name: self._logger.warning(u"empty regime name specified!") self._save_data(name) def _save_data(self, name): """ save current data-set :param name: name of the file """ self.currentDataset.update({"regime name": name}) path = os.path.join(os.path.pardir, "results", "simulation", self.regime_file_name) # check for path existence if not os.path.isdir(path): os.makedirs(path) # pmr - PyMoskito Result file_name = os.path.join( path, time.strftime("%Y%m%d-%H%M%S") + "_" + name + ".pmr") with open(file_name.encode("utf-8"), "wb") as f: cPickle.dump(self.currentDataset, f, protocol=2) self.statusLabel.setText(u"results saved to {}".format(file_name)) self._logger.info(u"results saved to {}".format(file_name)) def load_regime_dialog(self): regime_path = os.path.join("../regimes/") file_name = unicode(QtGui.QFileDialog.getOpenFileName( self, "Open Regime File", regime_path, "Simulation Regime files (*.sreg)").toUtf8(), encoding="utf-8") if not file_name: return self.load_regimes_from_file(file_name) def load_regimes_from_file(self, file_name): """ load simulation regime from file :param file_name: """ self.regime_file_name = os.path.split(file_name)[-1][:-5] self._logger.info(u"loading regime file: {0}".format( self.regime_file_name)) with open(file_name.encode("utf-8"), "r") as f: self._regimes += yaml.load(f) self._update_regime_list() if self._regimes: self.actExecuteRegimes.setDisabled(False) self._logger.info("loaded {} regimes".format(len(self._regimes))) self.statusBar().showMessage( u"loaded {} regimes.".format(len(self._regimes)), 1000) return def _update_regime_list(self): self.regime_list.clear() for reg in self._regimes: self._logger.debug("adding '{}' to regime list".format( reg["Name"])) self.regime_list.addItem(reg["Name"]) def remove_regime_items(self): if self.regime_list.currentRow() >= 0: # flag all selected files as invalid items = self.regime_list.selectedItems() for item in items: del self._regimes[self.regime_list.row(item)] self.regime_list.takeItem(self.regime_list.row(item)) def regime_dclicked(self, item): """ applies the selected regime to the current target :param item: """ self.apply_regime_by_name(str(item.text())) def apply_regime_by_name(self, regime_name): """ :param regime_name: :return: """ # get regime idx try: idx = map(itemgetter("Name"), self._regimes).index(regime_name) except ValueError as e: self._logger.info( "apply_regime_by_name(): Error no regime called {0}".format( regime_name)) return # apply self._apply_regime_by_idx(idx) def _apply_regime_by_idx(self, index=0): if index >= len(self._regimes): self._logger.error("applyRegime: index error! ({})".format(index)) return reg_name = self._regimes[index]["Name"] self.statusBar().showMessage("regime {} applied.".format(reg_name), 1000) self._logger.info("applying regime '{}'".format(reg_name)) self._current_regime_index = index self.sim.set_regime(self._regimes[index]) def execute_regimes_clicked(self): """ execute all regimes in the current list """ self.runningBatch = True self._current_regime_index = -1 self.regimeFinished.emit() def run_next_regime(self): """ executes the next regime """ # are we finished? if self._current_regime_index == len(self._regimes) - 1: self.finishedRegimeBatch.emit() return self._apply_regime_by_idx(self._current_regime_index + 1) self.start_simulation() def regime_batch_finished(self): self.runningBatch = False self.actExecuteRegimes.setDisabled(False) # self._current_regime_index = 0 self.statusLabel.setText("All regimes have been simulated!") self.actSave.setDisabled(True) def simulation_finished(self, data): """ main hook to be called by the simulation interface if integration is finished integration finished, enable play button and update plots :param data: dict with simulation data """ self._logger.info(u"simulation finished") self.statusLabel.setText(u"simulation finished.") self.actSimulate.setDisabled(False) self.shortRunSimulation.setEnabled(True) self.shortRunRegimeBatch.setEnabled(True) self.actPlayPause.setDisabled(False) self.shortPlayPause.setEnabled(True) self.shortSaveResult.setEnabled(True) self.actStop.setDisabled(False) self.actSave.setDisabled(False) self.speedDial.setDisabled(False) self.timeSlider.setDisabled(False) self.sim.simulationProgressChanged.disconnect( self.guiProgress.setValue) self.statusBar().removeWidget(self.guiProgress) self.timeSlider.triggerAction(QtGui.QAbstractSlider.SliderToMinimum) self.currentDataset = data self._read_results() self._update_data_list() self._update_plots() self.stop_animation() # self.playAnimation() if self.runningBatch: regime_name = self._regimes[self._current_regime_index]["Name"] self._save_data(regime_name) self.regimeFinished.emit() else: self.actExecuteRegimes.setDisabled(False) def simulation_failed(self, data): """ integration failed, enable play button and update plots :param data: """ self.statusLabel.setText(u"simulation failed!") self.simulation_finished(data) def _read_results(self): self.currentStepSize = 1.0 / self.currentDataset["results"][ "Simulation"]['measure rate'] self.currentEndTime = self.currentDataset["results"]["Simulation"][ "end time"] self.validData = True def add_plot_to_dock(self, plot_widget): self.d3.addWidget(plot_widget) def increment_playback_speed(self): self.speedDial.setValue(self.speedDial.value() + self.speedDial.singleStep()) def decrement_playback_speed(self): self.speedDial.setValue(self.speedDial.value() - self.speedDial.singleStep()) def reset_playback_speed(self): self.speedDial.setValue(self.speedDial.range() / 2) def increment_playback_time(self): """ go one time step forward in playback """ increment = self.playbackGain * self.playbackTimeout / 1000 if self.playbackTime + increment <= self.currentEndTime: self.playbackTime += increment pos = self.playbackTime / self.currentEndTime * self.timeSliderRange self.timeSlider.blockSignals(True) self.timeSlider.setValue(pos) self.timeSlider.blockSignals(False) self.playbackTimeChanged.emit() else: self.pause_animation() return def update_playback_gain(self, val): """ adjust playback time to slider value :param val: """ self.playbackGain = 10**(5.0 * (val - self.speedDial.maximum() / 2) / self.speedDial.maximum()) def update_playback_time(self): """ adjust playback time to slider value """ self.playbackTime = self.timeSlider.value( ) / self.timeSliderRange * self.currentEndTime self.playbackTimeChanged.emit() return def update_gui(self): """ updates the graphical user interface, including: - timestamp - visualisation - time cursor in diagrams """ if not self.validData: return self.timeLabel.setText(u"current time: %4f" % self.playbackTime) # update time cursor in plots self._update_time_cursor() # update state of rendering if self.visualizer: state = self.interpolate(self.currentDataset["results"]["Solver"]) self.visualizer.update_scene(state) self.vtkWidget.GetRenderWindow().Render() def interpolate(self, data): """ find corresponding item in data-set that fits the current playback time :param data: data-set in which the correct datum has to be found :return: datum fitting the current playback time """ idx = next(( index for index, val in enumerate(self.currentDataset["results"]["time"]) if val >= self.playbackTime), None) if idx is None: self._logger.info( u"interpolate(): Error no entry found for t={0}".format( self.playbackTime)) return None else: if len(data.shape) == 1: return data[idx] elif len(data.shape) == 2: return data[idx, :] else: self._logger.info( u"interpolate(): Error Dimension {0} not understood.". format(data.shape)) return None def _update_data_list(self): self.dataList.clear() for module, results in self.currentDataset["results"].iteritems(): if not isinstance(results, np.ndarray): continue if len(results.shape) == 1: self.dataList.insertItem(0, "{0}".format(module)) elif len(results.shape) == 2: for col in range(results.shape[1]): self.dataList.insertItem(0, "{0}.{1}".format(module, col)) elif len(results.shape) == 3: for col in range(results.shape[1]): self.dataList.insertItem(0, "{0}.{1}".format(module, col)) def create_plot(self, item): """ creates a plot widget corresponding to the ListItem :param item: ListItem """ title = str(item.text()) data = self._get_data_by_name(title) t = self.currentDataset["results"]["time"] dock = pg.dockarea.Dock(title) self.area.addDock(dock, "above", self.plotDocks[-1]) widget = pg.PlotWidget(title=title) widget.plot(x=t, y=data) time_line = pg.InfiniteLine(self.playbackTime, angle=90, movable=False, pen=pg.mkPen("#FF0000", width=2.0)) widget.getPlotItem().addItem(time_line) # enable grid widget.showGrid(True, True) dock.addWidget(widget) self.plotDocks.append(dock) self.plotWidgets.append(widget) self.timeLines.append(time_line) def _get_data_by_name(self, name): tmp = name.split(".") if len(tmp) == 1: data = self.currentDataset["results"][tmp[0]] # if the data-set contains 1d array -> convert to float data = [float(x) for x in data] elif len(tmp) == 2: if len(self.currentDataset["results"][tmp[0]].shape) == 2: data = self.currentDataset["results"][tmp[0]][:, tmp[1]] if len(self.currentDataset["results"][tmp[0]].shape ) == 3: # data-set has the structure [ [[1]], [[2]] ] data = self.currentDataset['results'][tmp[0]][..., tmp[1], 0] return data def _update_time_cursor(self): """ updates the time lines of all plot windows """ for line in self.timeLines: line.setValue(self.playbackTime) def _update_plots(self): """ plot the fresh simulation data """ for dock in self.plotDocks: for widget in dock.widgets: if not self.dataList.findItems(dock.name(), QtCore.Qt.MatchExactly): # no data for this plot -> reset it widget.getPlotItem().clear() # TODO remove tab from dock and del instance else: widget.getPlotItem().clear() x_data = self.currentDataset["results"]["time"] y_data = self._get_data_by_name(dock.name()) widget.getPlotItem().plot(x=x_data, y=y_data) def target_view_changed(self, index): self.targetView.resizeColumnToContents(0) def postprocessing_clicked(self): """ starts the post- and metaprocessing application """ self._logger.info(u"launching postprocessor") self.statusBar().showMessage(u"launching postprocessor", 1000) if self.postprocessor is None: self.postprocessor = PostProcessor() self.postprocessor.show() def reset_camera_clicked(self): """ reset camera in vtk window """ self.visualizer.reset_camera() self.vtkWidget.GetRenderWindow().Render()
class VTKCanvas(QtGui.QFrame): ''' the Qt4 frame that holds the main VTK canvas ''' def __init__(self, parent, Qt4GUI): super(VTKCanvas, self).__init__(parent) # dictionary to keep track of tree widget items that correspond to actors/icons - used to handle vtk->Qt4 scene changes self.actors_to_tree_widget_items = {} # Qt4 GUI that this canvas is associated with self.Qt4GUI = Qt4GUI # camera perspective type check self.camera_perspective = False # setup the vtk renderers - one for objects, one for overlay icons/text (which always renders on top) self.vtk_renderer = vtk.vtkRenderer() # setup the vtk interactor self.vtk_interactor = QVTKRenderWindowInteractor(self) # setup the vtk render window self.vtk_render_window = self.vtk_interactor.GetRenderWindow() self.vtk_render_window.AddRenderer(self.vtk_renderer) self.vtk_render_window.SetInteractor(self.vtk_interactor) #setup the layout of the vtk interactor in Qt self.layout = QtGui.QHBoxLayout() self.layout.addWidget(self.vtk_interactor) self.layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.layout) def setupTimerCallback(self, targetFPS=30): # calling this function will setup a timer and callback to continuously render the scene at the target FPS self.vtk_interactor.AddObserver('TimerEvent', self.requestUpdate) self.vtk_interactor.CreateRepeatingTimer(long(targetFPS)) def requestUpdate(self, obj, event): # request a render update of the scene self.vtk_render_window.Render() def start(self): # setup the vtk background - as default, set to light self.vtk_renderer.GradientBackgroundOn() self.setBackgroundLight() # setup the default camera self.camera_perspective = False self.defaultPerspectiveCamera() # setup a default light kit (simple sun illumination + camera spotlight) self.light_kit = vtk.vtkLightKit() self.light_kit.MaintainLuminanceOn() self.light_kit.AddLightsToRenderer(self.vtk_renderer) # add the orientation axes to the bottom left of the canvas self.Qt4GUI.addOrientationAxes() # setup the default base grid - 1x1km, 10m squares self.Qt4GUI.addGrid(['grids', '1 km x 1 km, 10 m'], 1000, 10) # startup vtk self.vtk_interactor.Initialize() self.vtk_interactor.Start() def resetCamera(self): if self.camera_perspective: self.camera_perspective = False self.defaultPerspectiveCamera() else: self.camera_perspective = True self.defaultTopDownCamera() def defaultPerspectiveCamera(self): self.Qt4GUI.camera_perspective_signal.emit(True) if not self.camera_perspective: self.vtk_renderer.SetActiveCamera(vtk.vtkCamera()) self.vtk_interactor.SetInteractorStyle(TerrainInteractorStyle()) self.vtk_renderer.GetActiveCamera().SetViewUp(0, 0, 1) self.vtk_renderer.GetActiveCamera().SetPosition(0, 1, 10) self.vtk_renderer.GetActiveCamera().SetFocalPoint(0, 0, 0) self.vtk_renderer.GetActiveCamera().Azimuth(135) self.vtk_renderer.GetActiveCamera().Elevation(86) self.vtk_renderer.GetActiveCamera().Dolly(0.4) self.vtk_renderer.GetActiveCamera().Zoom(1) self.vtk_renderer.ResetCameraClippingRange() self.camera_perspective = True self.vtk_interactor.Render() def perspectiveCamera(self): self.Qt4GUI.camera_perspective_signal.emit(True) if not self.camera_perspective: curr_fp = self.vtk_renderer.GetActiveCamera().GetFocalPoint() curr_pos = [curr_fp[0], curr_fp[1] + 1, 10] curr_fp = [curr_fp[0], curr_fp[1], 0] self.vtk_renderer.SetActiveCamera(vtk.vtkCamera()) self.vtk_interactor.SetInteractorStyle(TerrainInteractorStyle()) self.vtk_renderer.GetActiveCamera().SetViewUp(0, 0, 1) self.vtk_renderer.GetActiveCamera().SetPosition(curr_pos) self.vtk_renderer.GetActiveCamera().SetFocalPoint(curr_fp) self.vtk_renderer.GetActiveCamera().Azimuth(135) self.vtk_renderer.GetActiveCamera().Elevation(86) self.vtk_renderer.GetActiveCamera().Dolly(0.4) self.vtk_renderer.GetActiveCamera().Zoom(1) self.vtk_renderer.ResetCameraClippingRange() self.camera_perspective = True self.vtk_interactor.Render() def defaultTopDownCamera(self): self.Qt4GUI.camera_perspective_signal.emit(False) if self.camera_perspective: self.vtk_renderer.SetActiveCamera(vtk.vtkCamera()) self.vtk_interactor.SetInteractorStyle(TopDownInteractorStyle()) self.vtk_renderer.GetActiveCamera().SetViewUp(0, 1, 0) self.vtk_renderer.GetActiveCamera().ParallelProjectionOn() self.vtk_renderer.GetActiveCamera().SetParallelScale(1000) self.vtk_renderer.GetActiveCamera().SetPosition(0, 0, 1e4) self.vtk_renderer.GetActiveCamera().SetFocalPoint(0, 0, 0) self.vtk_renderer.GetActiveCamera().Elevation(0) self.vtk_renderer.GetActiveCamera().Azimuth(0) self.vtk_renderer.GetActiveCamera().Dolly(0.4) self.vtk_renderer.GetActiveCamera().Zoom(100) self.vtk_renderer.ResetCameraClippingRange() self.camera_perspective = False self.vtk_interactor.Render() def topDownCamera(self): self.Qt4GUI.camera_perspective_signal.emit(False) if self.camera_perspective: curr_fp = self.vtk_renderer.GetActiveCamera().GetFocalPoint() curr_pos = [curr_fp[0], curr_fp[1], 1e4] curr_fp = [curr_fp[0], curr_fp[1], 0] self.vtk_renderer.SetActiveCamera(vtk.vtkCamera()) self.vtk_interactor.SetInteractorStyle(TopDownInteractorStyle()) self.vtk_renderer.GetActiveCamera().SetViewUp(0, 1, 0) self.vtk_renderer.GetActiveCamera().ParallelProjectionOn() self.vtk_renderer.GetActiveCamera().SetParallelScale(1000) self.vtk_renderer.GetActiveCamera().SetPosition(curr_pos) self.vtk_renderer.GetActiveCamera().SetFocalPoint(curr_fp) self.vtk_renderer.GetActiveCamera().Elevation(0) self.vtk_renderer.GetActiveCamera().Azimuth(0) self.vtk_renderer.GetActiveCamera().Dolly(0.4) self.vtk_renderer.GetActiveCamera().Zoom(100) self.vtk_renderer.ResetCameraClippingRange() self.camera_perspective = False self.vtk_interactor.Render() def setBackgroundLight(self): self.Qt4GUI.background_light_signal.emit(True) self.vtk_renderer.SetBackground2(220.0 / 255, 225.0 / 255, 235.0 / 255) self.vtk_renderer.SetBackground(105.0 / 255, 135.0 / 255, 155.0 / 255) self.vtk_interactor.Render() def setBackgroundDark(self): self.Qt4GUI.background_light_signal.emit(False) self.vtk_renderer.SetBackground(0.0 / 255, 10.0 / 255, 15.0 / 255) self.vtk_renderer.SetBackground2(60.0 / 255, 80.0 / 255, 110.0 / 255) self.vtk_interactor.Render() def addActorFrameAxes(self, tree_widget): frame_axes = Primitives.Axes() frame_axes.AxisLabelsOff() frame_axes.VisibilityOff() self.vtk_renderer.AddActor(frame_axes) self.vtk_interactor.Render() return frame_axes def removeActorFrameAxes(self, actor): self.vtk_renderer.RemoveActor(actor) self.vtk_interactor.Render() def addActor(self, tree_widget, actor): self.actors_to_tree_widget_items[actor] = tree_widget self.vtk_renderer.AddActor(actor) self.vtk_interactor.Render() def removeActor(self, actor): del self.actors_to_tree_widget_items[actor] self.vtk_renderer.RemoveActor(actor) self.vtk_interactor.Render() def replaceActor(self, remove_actor, tree_widget, actor): self.removeActor(remove_actor) self.addActor(tree_widget, actor) def setActorVisibility(self, actor, visible): if visible: actor.VisibilityOn() else: actor.VisibilityOff() self.vtk_interactor.Render() def setActorScale(self, actor, scale): if actor.GetClassName() == "vtkAxesActor": actor.SetTotalLength(scale, scale, scale) else: if actor.__class__ == Billboards.TextBillboard or actor.__class__ == Billboards.ImageBillboard: # billboards have no scaling return actor.SetScale(scale) self.vtk_interactor.Render() def getActorScale(self, actor): if actor.GetClassName() == "vtkAxesActor": return actor.GetTotalLength() else: if actor.__class__ == Billboards.TextBillboard or actor.__class__ == Billboards.ImageBillboard: # billboards have no scaling return [1, 1, 1] return actor.GetScale() def setActorOpacity(self, actor, opacity): actor.GetProperty().SetOpacity(opacity) self.vtk_interactor.Render() def getActorOpacity(self, actor): return actor.GetProperty().GetOpacity() def setActorPointSize(self, actor, size): actor.GetProperty().SetPointSize(size) self.vtk_interactor.Render() def getActorPointSize(self, actor): return actor.GetProperty().GetPointSize() def setActorLineWidth(self, actor, width): actor.GetProperty().SetLineWidth(width) self.vtk_interactor.Render() def getActorLineWidth(self, actor): return actor.GetProperty().GetLineWidth() def setActorToSurface(self, actor): if actor.__class__ == Billboards.TextBillboard or actor.__class__ == Billboards.ImageBillboard: # billboards have no render mode return actor.GetProperty().EdgeVisibilityOff() actor.GetProperty().SetRepresentationToSurface() self.vtk_interactor.Render() def setActorToWireframe(self, actor): if actor.__class__ == Billboards.TextBillboard or actor.__class__ == Billboards.ImageBillboard: # billboards have no render mode return actor.GetProperty().EdgeVisibilityOff() actor.GetProperty().SetRepresentationToWireframe() self.vtk_interactor.Render() def setActorToSurfaceEdges(self, actor): if actor.__class__ == Billboards.TextBillboard or actor.__class__ == Billboards.ImageBillboard: # billboards have no render mode return actor.GetProperty().EdgeVisibilityOn() actor.GetProperty().SetRepresentationToSurface() self.vtk_interactor.Render() def setActorToPoints(self, actor): if actor.__class__ == Billboards.TextBillboard or actor.__class__ == Billboards.ImageBillboard: # billboards have no render mode return actor.GetProperty().EdgeVisibilityOff() actor.GetProperty().SetRepresentationToPoints() self.vtk_interactor.Render() def getActorRenderMode(self, actor): if actor.__class__ == Billboards.TextBillboard or actor.__class__ == Billboards.ImageBillboard: # billboards have no render mode return None, None edge = actor.GetProperty().GetEdgeVisibility() mode = actor.GetProperty().GetRepresentation() return edge, mode def getActorColor(self, actor): return actor.GetProperty().GetColor() def setActorColor(self, actor, r, g, b): actor.GetProperty().SetColor(r, g, b) self.vtk_interactor.Render() def setActorTexture(self, actor, image_path): if actor.__class__ == Billboards.TextBillboard: # text billboards have no texture return if image_path[-4:].lower() == '.jpg' or image_path[-4:].lower( ) == '.jpeg': reader = vtk.vtkJPEGReader() reader.SetFileName(image_path) reader.Update() elif image_path[-4:].lower() == '.png': reader = vtk.vtkPNGReader() reader.SetFileName(image_path) reader.Update() texture = vtk.vtkTexture() texture.RepeatOn() texture.SetInputConnection(reader.GetOutputPort()) actor.SetTexture(texture) # polydata = actor.GetMapper().GetInput() # pointdata = polydata.GetPointData() # celldata = polydata.GetCellData() # numtuples = celldata.GetNumberOfTuples() # numpolygons = polydata.GetNumberOfPolys() self.vtk_interactor.Render() def removeActorTexture(self, actor): actor.SetTexture(None) self.vtk_interactor.Render() def setActorOffset(self, actor, x_offset, y_offset, z_offset): if actor.__class__ == Billboards.TextBillboard or actor.__class__ == Billboards.ImageBillboard: # billboards are unaffected by offset changes pass else: actor.SetPosition(x_offset, y_offset, z_offset) self.vtk_interactor.Render() def setActorOrientation(self, actor, roll, pitch, yaw): actor.SetOrientation(roll, pitch, yaw) self.vtk_interactor.Render()
class ExodusResultRenderWidget(QtGui.QWidget): def __init__(self, input_file_widget, execution_widget, qt_app, application): QtGui.QWidget.__init__(self) self.input_file_widget = input_file_widget self.qt_app = qt_app self.application = application self.plane = vtk.vtkPlane() self.plane.SetOrigin(-1000, 0, 0) self.plane.SetNormal(1, 0, 0) self.exodus_result = None # The multiple (from adaptivity) self.exodus_results = [] self.timestep_to_exodus_result = {} self.file_name = None self.setupLuts() # The multiple (from adaptivity) file names we know of self.file_names = [] self.current_max_timestep = 0 # Whether or not there is new data to read self.new_stuff_to_read = False self.timer = QtCore.QTimer() self.timer.stop() self.timer.setInterval(100) self.timer.timeout.connect(self._updateData) self.execution_widget = execution_widget self.execution_widget.run_started.connect(self._runStarted) self.execution_widget.run_stopped.connect(self._runStopped) self.execution_widget.timestep_begin.connect(self._timestepBegin) self.execution_widget.timestep_end.connect(self._timestepEnd) self.main_layout = QtGui.QHBoxLayout() # self.main_layout.setSpacing(0) self.right_layout = QtGui.QVBoxLayout() self.left_layout = QtGui.QVBoxLayout() self.left_widget = QtGui.QWidget() self.left_widget.setMaximumWidth(1) self.left_widget.setLayout(self.left_layout) self.left_layout.setSizeConstraint(QtGui.QLayout.SetMinimumSize) self.main_layout.addWidget(self.left_widget) self.right_layout.setStretchFactor(self.left_layout, 0.01) self.main_layout.addLayout(self.right_layout) # self.setMinimumWidth(700) self.setLayout(self.main_layout) self.vtkwidget = QVTKRenderWindowInteractor(self) # self.vtkwidget.setMinimumHeight(300) # Create background, default to the gradient look self.renderer = vtk.vtkRenderer() self._showBlackBackgroundChanged(0) self.renderer.ResetCamera() self.right_layout.addWidget(self.vtkwidget) self.right_layout.setStretchFactor(self.vtkwidget, 100) self.vtkwidget.show() self.vtkwidget.GetRenderWindow().AddRenderer(self.renderer) self.vtkwidget.GetRenderWindow().GetInteractor().SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera()) self.vtkwidget.Initialize() self.vtkwidget.Start() self.first = True self.exodus_result = None self.has_displacements = False self.current_displacement_magnitude = 1.0 self.current_scale_x_magnitude = 1.0 self.current_scale_y_magnitude = 1.0 self.current_scale_z_magnitude = 1.0 self.current_variable = None self.current_component = None # Holds a mapping of variable name to contour choices so they can be restored when variables are selected self.contour_choices = {} # If we are currently restoring contours then don't save the intermediate ones self.currently_restoring_contours = False self.setupControls() self.modifyUI() ''' This will be called after the interface is completely setup to allow an application to modify this tab ''' def modifyUI(self): pass ''' Return the name to use for this tab ''' def name(self): return 'Visualize' def setupControls(self): self.controls_widget = QtGui.QWidget() self.controls_layout = QtGui.QVBoxLayout() self.bottom_controls_layout = QtGui.QHBoxLayout() self.left_layout.addLayout(self.controls_layout) self.main_layout.setStretchFactor(self.left_layout, 0.1) # self.main_layout.addLayout(self.bottom_controls_layout) self.leftest_controls_layout = QtGui.QVBoxLayout() self.left_controls_layout = QtGui.QVBoxLayout() self.right_controls_layout = QtGui.QVBoxLayout() self.block_view_group_box = QtGui.QGroupBox('Show Blocks') # self.block_view_group_box.setMaximumWidth(200) # self.block_view_group_box.setMaximumHeight(200) self.block_view_layout = QtGui.QVBoxLayout() self.block_view_list = QtGui.QListView() self.block_view_model = QtGui.QStandardItemModel() self.block_view_model.itemChanged.connect(self._blockViewItemChanged) self.block_view_list.setModel(self.block_view_model) self.block_view_layout.addWidget(self.block_view_list) self.block_view_group_box.setLayout(self.block_view_layout) self.leftest_controls_layout.addWidget(self.block_view_group_box) self.controls_layout.addLayout(self.leftest_controls_layout) self.controls_layout.addLayout(self.left_controls_layout) self.controls_layout.addLayout(self.right_controls_layout) self.controls_layout.setStretchFactor(self.leftest_controls_layout,1.0) self.controls_layout.setStretchFactor(self.left_controls_layout,1.5) self.controls_layout.setStretchFactor(self.right_controls_layout,4.0) self.automatic_update_checkbox = QtGui.QCheckBox("Automatically Update") self.automatic_update_checkbox.setToolTip('Toggle automattically reading new timesteps as they finish computing') self.automatic_update_checkbox.setCheckState(QtCore.Qt.Checked) self.automatically_update = True self.automatic_update_checkbox.stateChanged[int].connect(self._automaticUpdateChanged) # self.left_controls_layout.addWidget(self.automatic_update_checkbox) # Create Group for viewer controls # Create the View Mesh toggle self.toggle_groupbox = QtGui.QGroupBox("View") self.toggle_groupbox.setMaximumHeight(70) self.toggle_layout = QtGui.QHBoxLayout() self.toggle_groupbox.setMaximumHeight(70) self.draw_edges_checkbox = QtGui.QCheckBox("View Mesh") self.draw_edges_checkbox.setToolTip('Show mesh elements') self.draw_edges_checkbox.stateChanged[int].connect(self._drawEdgesChanged) self.toggle_layout.addWidget(self.draw_edges_checkbox, alignment=QtCore.Qt.AlignHCenter) # Add a button for toggling the scalebar legend self.hide_scalebar_checkbox = QtGui.QCheckBox("Scalebar") self.hide_scalebar_checkbox.setToolTip('Toggle visibility of colorbar') self.hide_scalebar_checkbox.setCheckState(QtCore.Qt.Checked) self.hide_scalebar_checkbox.stateChanged[int].connect(self._hideScalebarChanged) self.toggle_layout.addWidget(self.hide_scalebar_checkbox, alignment=QtCore.Qt.AlignHCenter) # Add a button for toggling background to black self.show_black_background_checkbox = QtGui.QCheckBox("Black") self.show_black_background_checkbox.setToolTip('Toggle a black/gradient background') self.show_black_background_checkbox.stateChanged[int].connect(self._showBlackBackgroundChanged) self.toggle_layout.addWidget(self.show_black_background_checkbox, alignment=QtCore.Qt.AlignHCenter) # Create a vertical layout and add the toggles self.toggle_groupbox.setLayout(self.toggle_layout) self.reset_layout = QtGui.QVBoxLayout() self.reset_layout.addWidget(self.toggle_groupbox) self.displace_groupbox = QtGui.QGroupBox("Displace") self.displace_groupbox.setCheckable(True) self.displace_groupbox.setChecked(True) self.displace_groupbox.setDisabled(True) self.displace_groupbox.setMaximumHeight(70) self.displace_groupbox.toggled[bool].connect(self._displaceToggled) self.displace_layout = QtGui.QHBoxLayout() self.displace_layout.setSpacing(0) self.displace_groupbox.setLayout(self.displace_layout) self.displace_magnitude_label = QtGui.QLabel("Multiplier: ") self.displace_magnitude_text = QtGui.QLineEdit("1.0") self.displace_magnitude_text.setMaximumWidth(50) self.displace_magnitude_text.setMinimumWidth(10) self.displace_magnitude_text.returnPressed.connect(self._displaceMagnitudeTextReturn) self.displace_layout.addWidget(self.displace_magnitude_label, alignment=QtCore.Qt.AlignRight) self.displace_layout.addWidget(self.displace_magnitude_text, alignment=QtCore.Qt.AlignLeft) self.reset_layout.addWidget(self.displace_groupbox) self.scale_groupbox = QtGui.QGroupBox("Scale") self.scale_groupbox.setCheckable(True) self.scale_groupbox.setChecked(False) self.scale_groupbox.setDisabled(False) self.scale_groupbox.setMaximumHeight(70) self.scale_groupbox.toggled[bool].connect(self._scaleToggled) self.scale_layout = QtGui.QHBoxLayout() self.scale_layout.setSpacing(0) self.scale_groupbox.setLayout(self.scale_layout) self.scale_x_label = QtGui.QLabel("x: ") self.scale_x_text = QtGui.QLineEdit("1.0") self.scale_x_text.setMinimumWidth(10) self.scale_x_text.setMaximumWidth(50) self.scale_y_label = QtGui.QLabel("y: ") self.scale_y_text = QtGui.QLineEdit("1.0") self.scale_y_text.setMinimumWidth(10) self.scale_y_text.setMaximumWidth(50) self.scale_z_label = QtGui.QLabel("z: ") self.scale_z_text = QtGui.QLineEdit("1.0") self.scale_z_text.setMinimumWidth(10) self.scale_z_text.setMaximumWidth(50) self.scale_x_text.returnPressed.connect(self._scaleMagnitudeTextReturn) self.scale_y_text.returnPressed.connect(self._scaleMagnitudeTextReturn) self.scale_z_text.returnPressed.connect(self._scaleMagnitudeTextReturn) self.scale_layout.addWidget(self.scale_x_label, alignment=QtCore.Qt.AlignRight) self.scale_layout.addWidget(self.scale_x_text, alignment=QtCore.Qt.AlignLeft) self.scale_layout.addWidget(self.scale_y_label, alignment=QtCore.Qt.AlignRight) self.scale_layout.addWidget(self.scale_y_text, alignment=QtCore.Qt.AlignLeft) self.scale_layout.addWidget(self.scale_z_label, alignment=QtCore.Qt.AlignRight) self.scale_layout.addWidget(self.scale_z_text, alignment=QtCore.Qt.AlignLeft) self.reset_layout.addWidget(self.scale_groupbox) self.clip_groupbox = QtGui.QGroupBox("Clip") self.clip_groupbox.setToolTip('Toggle clipping mode where the solution can be sliced open') self.clip_groupbox.setCheckable(True) self.clip_groupbox.setChecked(False) self.clip_groupbox.setMaximumHeight(70) self.clip_groupbox.toggled[bool].connect(self._clippingToggled) clip_layout = QtGui.QHBoxLayout() self.clip_plane_combobox = QtGui.QComboBox() self.clip_plane_combobox.setToolTip('Direction of the normal for the clip plane') self.clip_plane_combobox.addItem('x') self.clip_plane_combobox.addItem('y') self.clip_plane_combobox.addItem('z') self.clip_plane_combobox.currentIndexChanged[str].connect(self._clipNormalChanged) clip_layout.addWidget(self.clip_plane_combobox) self.clip_plane_slider = QtGui.QSlider(QtCore.Qt.Horizontal) self.clip_plane_slider.setToolTip('Slide to change plane position') self.clip_plane_slider.setRange(0, 100) self.clip_plane_slider.setSliderPosition(50) self.clip_plane_slider.sliderReleased.connect(self._clipSliderReleased) self.clip_plane_slider.sliderMoved[int].connect(self._clipSliderMoved) clip_layout.addWidget(self.clip_plane_slider) # vbox->addStretch(1); self.clip_groupbox.setLayout(clip_layout) self.reset_layout.addWidget(self.clip_groupbox) self.view_layout = QtGui.QHBoxLayout() self.open_button = QtGui.QPushButton('Open') self.open_button.setMaximumWidth(100) self.open_button.setToolTip('Open an existing result') self.open_button.clicked.connect(self._clickedOpen) self.view_layout.addWidget(self.open_button, alignment=QtCore.Qt.AlignHCenter) self.save_button = QtGui.QPushButton('Save') self.save_button.setMaximumWidth(100) self.save_button.setToolTip('Save the current view to a file') self.save_button.clicked.connect(self._saveView) self.view_layout.addWidget(self.save_button, alignment=QtCore.Qt.AlignHCenter) self.reset_button = QtGui.QPushButton('Reset') self.reset_button.setMaximumWidth(100) self.reset_button.setToolTip('Recenter the camera on the current result') self.reset_button.clicked.connect(self._resetView) self.view_layout.addWidget(self.reset_button, alignment=QtCore.Qt.AlignHCenter) self.reset_layout.addLayout(self.view_layout) self.right_controls_layout.addLayout(self.reset_layout) self.contour_groupbox = QtGui.QGroupBox("Contour") # self.contour_groupbox.setMaximumHeight(10) # self.contour_groupbox.setMaximumHeight(70) # contour_groupbox_policy = QtGui.QSizePolicy() self.contour_groupbox.setSizePolicy(QtGui.QSizePolicy.Fixed,QtGui.QSizePolicy.Fixed) self.contour_layout = QtGui.QVBoxLayout() self.contour_groupbox.setLayout(self.contour_layout) self.variable_contour_layout = QtGui.QHBoxLayout() self.contour_layout.addLayout(self.variable_contour_layout) self.contour_label = QtGui.QLabel("Contour:") self.variable_contour = QtGui.QComboBox() self.variable_contour_is_nodal = {} self.variable_contour.setToolTip('Which variable to color by') self.variable_contour.currentIndexChanged[int].connect(self._contourVariableSelected) # self.variable_contour_layout.addWidget(self.contour_label, alignment=QtCore.Qt.AlignRight) self.variable_contour_layout.addWidget(self.variable_contour, alignment=QtCore.Qt.AlignHCenter) # self.component_layout = QtGui.QHBoxLayout() self.component_label = QtGui.QLabel("Component:") self.variable_component = QtGui.QComboBox() self.variable_component.setToolTip('If the variable is a vector this selects what component of that vector (or the Magnitude) to color by') self.variable_component.currentIndexChanged[str].connect(self._variableComponentSelected) # self.component_layout.addWidget(self.component_label, alignment=QtCore.Qt.AlignRight) # self.component_layout.addWidget(self.variable_component, alignment=QtCore.Qt.AlignLeft) # self.variable_contour_layout.addLayout(self.component_layout) self.variable_contour_layout.addWidget(self.variable_component, alignment=QtCore.Qt.AlignHCenter) self.minmax_contour_layout = QtGui.QVBoxLayout() self.contour_layout.addLayout(self.minmax_contour_layout) self.min_groupbox = QtGui.QGroupBox("Min") self.min_layout = QtGui.QHBoxLayout() self.min_groupbox.setLayout(self.min_layout) self.min_radio_layout = QtGui.QVBoxLayout() self.min_current_radio = QtGui.QRadioButton('Current') self.min_current_radio.setChecked(QtCore.Qt.Checked) self.min_current_radio.toggled.connect(self._updateContours) self.min_global_radio = QtGui.QRadioButton('Global') self.min_global_radio.toggled.connect(self._updateContours) self.min_radio_layout.addWidget(self.min_current_radio) # self.min_radio_layout.addWidget(self.min_global_radio) self.min_custom_layout = QtGui.QHBoxLayout() self.min_custom_layout.setSpacing(0) self.min_custom_radio = QtGui.QRadioButton() self.min_custom_radio.toggled.connect(self._updateContours) self.min_custom_text = QtGui.QLineEdit() self.min_custom_text.returnPressed.connect(self._updateContours) self.min_custom_text.setDisabled(True) self.min_custom_text.setMaximumWidth(100) self.min_custom_layout.addWidget(self.min_custom_radio, alignment=QtCore.Qt.AlignLeft) self.min_custom_layout.addWidget(self.min_custom_text, alignment=QtCore.Qt.AlignLeft) self.min_custom_layout.addStretch() self.min_layout.addLayout(self.min_radio_layout) self.min_layout.addLayout(self.min_custom_layout) self.minmax_contour_layout.addWidget(self.min_groupbox) self.max_groupbox = QtGui.QGroupBox("Max") self.max_layout = QtGui.QHBoxLayout() self.max_groupbox.setLayout(self.max_layout) self.max_radio_layout = QtGui.QVBoxLayout() self.max_current_radio = QtGui.QRadioButton('Current') self.max_current_radio.setChecked(QtCore.Qt.Checked) self.max_current_radio.toggled.connect(self._updateContours) self.max_global_radio = QtGui.QRadioButton('Global') self.max_global_radio.toggled.connect(self._updateContours) self.max_radio_layout.addWidget(self.max_current_radio) # self.max_radio_layout.addWidget(self.max_global_radio) self.max_custom_layout = QtGui.QHBoxLayout() self.max_custom_layout.setSpacing(0) self.max_custom_radio = QtGui.QRadioButton() self.max_custom_radio.toggled.connect(self._updateContours) self.max_custom_text = QtGui.QLineEdit() self.max_custom_text.returnPressed.connect(self._updateContours) self.max_custom_text.setDisabled(True) self.max_custom_text.setMaximumWidth(100) self.max_custom_layout.addWidget(self.max_custom_radio, alignment=QtCore.Qt.AlignLeft) self.max_custom_layout.addWidget(self.max_custom_text, alignment=QtCore.Qt.AlignLeft) self.max_custom_layout.addStretch() self.max_layout.addLayout(self.max_radio_layout) self.max_layout.addLayout(self.max_custom_layout) self.minmax_contour_layout.addWidget(self.max_groupbox) # self.component_layout = QtGui.QHBoxLayout() self.color_scheme_label = QtGui.QLabel("Color Scheme:") self.color_scheme_component = QtGui.QComboBox() self.color_scheme_component.addItem('HSV (Cool to Warm)') self.color_scheme_component.addItem('Diverging (Blue to Red)') self.color_scheme_component.addItem('Shock') self.color_scheme_component.setToolTip('The color scheme used byt the render view') self.color_scheme_component.currentIndexChanged[str].connect(self._colorSchemeSelected) # self.component_layout.addWidget(self.component_label, alignment=QtCore.Qt.AlignRight) # self.component_layout.addWidget(self.variable_component, alignment=QtCore.Qt.AlignLeft) # self.variable_contour_layout.addLayout(self.component_layout) self.minmax_contour_layout.addWidget(self.color_scheme_component) self.left_controls_layout.addWidget(self.contour_groupbox) self.beginning_button = QtGui.QToolButton() self.beginning_button.setToolTip('Go to first timestep') self.beginning_button.setIcon(QtGui.QIcon(pathname + '/resources/from_paraview/pqVcrFirst32.png')) self.beginning_button.clicked.connect(self._beginningClicked) self.back_button = QtGui.QToolButton() self.back_button.setToolTip('Previous timestep') self.back_button.setIcon(QtGui.QIcon(pathname + '/resources/from_paraview/pqVcrBack32.png')) self.back_button.clicked.connect(self._backClicked) self.play_button = QtGui.QToolButton() self.play_button.setToolTip('Play through the currently computed timesteps') self.play_button.setIcon(QtGui.QIcon(pathname + '/resources/from_paraview/pqVcrPlay32.png')) self.play_button.clicked.connect(self._playClicked) self.pause_button = QtGui.QToolButton() self.pause_button.setToolTip('If playing this will pause playback') self.pause_button.setDisabled(True) self.pause_button.setIcon(QtGui.QIcon(pathname + '/resources/from_paraview/pqVcrPause32.png')) self.pause_button.clicked.connect(self._pauseClicked) self.forward_button = QtGui.QToolButton() self.forward_button.setToolTip('Next timestep') self.forward_button.setIcon(QtGui.QIcon(pathname + '/resources/from_paraview/pqVcrForward32.png')) self.forward_button.clicked.connect(self._forwardClicked) self.last_button = QtGui.QToolButton() self.last_button.setToolTip('Go to last timestep') self.last_button.setIcon(QtGui.QIcon(pathname + '/resources/from_paraview/pqVcrLast32.png')) self.last_button.clicked.connect(self._lastClicked) self.loop_button = QtGui.QToolButton() self.loop_button.setToolTip('Toggle replaying all timesteps when the end is reached during playback. Note that as new timesteps finish they will automatically be picked up and added to the end of the sequence.') self.loop_button.setCheckable(True) self.loop_button.setIcon(QtGui.QIcon(pathname + '/resources/from_paraview/pqVcrLoop24.png')) self.loop_button.toggled.connect(self._loopClicked) self.currently_looping = False self.time_slider_label = QtGui.QLabel("Timestep:") self.time_slider = QtGui.QSlider(QtCore.Qt.Horizontal) self.time_slider.setToolTip('Slide to select a timestep to display') # self.time_slider.setMaximumWidth(600) self.time_slider.valueChanged.connect(self._timeSliderChanged) self.time_slider.sliderReleased.connect(self._timeSliderReleased) self.time_slider_textbox = QtGui.QLineEdit() self.time_slider_textbox.setToolTip('Enter a number and press Enter to go to that timestep') self.time_slider_textbox.setMaximumWidth(30) self.time_slider_textbox.setMinimumWidth(30) self.time_slider_textbox.returnPressed.connect(self._sliderTextboxReturn) self.time_groupbox = QtGui.QGroupBox("Time") self.time_groupbox.setMaximumHeight(70) self.time_layout = QtGui.QHBoxLayout() self.time_layout.addWidget(self.beginning_button) self.time_layout.addWidget(self.back_button) self.time_layout.addWidget(self.play_button) self.time_layout.addWidget(self.pause_button) self.time_layout.addWidget(self.forward_button) self.time_layout.addWidget(self.last_button) self.time_layout.addWidget(self.loop_button) self.time_layout.addWidget(self.time_slider_label, alignment=QtCore.Qt.AlignRight) self.time_layout.addWidget(self.time_slider) self.time_layout.addWidget(self.time_slider_textbox, alignment=QtCore.Qt.AlignLeft) self.time_groupbox.setLayout(self.time_layout) self.right_layout.addWidget(self.time_groupbox) def _updateControls(self): self.old_contour = self.variable_contour.currentText() self.variable_contour.clear() self.has_displacements = False for variable in self.exodus_result.current_nodal_variables: if 'ObjectId' not in variable: self.variable_contour.addItem(variable) item_num = self.variable_contour.count()-1 self.variable_contour.setItemIcon(item_num,QtGui.QIcon(pathname + '/resources/from_paraview/pqNodalData16.png')) self.variable_contour_is_nodal[item_num] = True if 'disp' in variable: self.has_displacements = True for variable in self.exodus_result.current_elemental_variables: if 'ObjectId' not in variable: self.variable_contour.addItem(variable) item_num = self.variable_contour.count()-1 self.variable_contour.setItemIcon(item_num,QtGui.QIcon(pathname + '/resources/from_paraview/pqElemData16.png')) self.variable_contour_is_nodal[item_num] = False if 'disp' in variable: self.has_displacements = True if self.has_displacements: self.displace_groupbox.setDisabled(False) self.block_view_model.clear() for block in self.exodus_result.blocks: block_display_name = str(block) if block in self.exodus_result.block_to_name: block_display_name += ' : ' + self.exodus_result.block_to_name[block] item = QtGui.QStandardItem(str(block_display_name)) item.exodus_block = block item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable) item.setCheckState(QtCore.Qt.Checked) self.block_view_model.appendRow(item) # Try to restore back to the view of the variable we were looking at found_index = self.variable_contour.findText(self.old_contour) if found_index != -1: self.variable_contour.setCurrentIndex(found_index) else: # If this variable doesn't exist then we are probably running a new simulation... try to reset the camera self._resetView() self.time_slider.setMinimum(0) self.time_slider.setMaximum(self.current_max_timestep) def setupLuts(self): self.luts = [] # HSV (Blue to REd) Default lut = vtk.vtkLookupTable() lut.SetHueRange(0.667, 0.0) lut.SetNumberOfColors(256) lut.Build() self.luts.append(lut) # Diverging (Cool to Warm) color scheme ctf = vtk.vtkColorTransferFunction() ctf.SetColorSpaceToDiverging() ctf.AddRGBPoint(0.0, 0.230, 0.299, 0.754) ctf.AddRGBPoint(1.0, 0.706, 0.016, 0.150) cc = list() for i in xrange(256): cc.append(ctf.GetColor(float(i) / 255.0)) lut = vtk.vtkLookupTable() lut.SetNumberOfColors(256) for i, item in enumerate(cc): lut.SetTableValue(i, item[0], item[1], item[2], 1.0) lut.Build() self.luts.append(lut) # Shock ctf = vtk.vtkColorTransferFunction() min = 93698.4 max = 230532 ctf.AddRGBPoint(self._normalize(min, max, 93698.4), 0.0, 0.0, 1.0) ctf.AddRGBPoint(self._normalize(min, max, 115592.0), 0.0, 0.905882, 1.0) ctf.AddRGBPoint(self._normalize(min, max, 138853.0), 0.0941176, 0.733333, 0.027451) ctf.AddRGBPoint(self._normalize(min, max, 159378.0), 1.0, 0.913725, 0.00784314) ctf.AddRGBPoint(self._normalize(min, max, 181272.0), 1.0, 0.180392, 0.239216) ctf.AddRGBPoint(self._normalize(min, max, 203165.0), 1.0, 0.701961, 0.960784) ctf.AddRGBPoint(self._normalize(min, max, 230532.0), 1.0, 1.0, 1.0) cc = list() for i in xrange(256): cc.append(ctf.GetColor(float(i) / 255.0)) lut = vtk.vtkLookupTable() lut.SetNumberOfColors(256) for i, item in enumerate(cc): lut.SetTableValue(i, item[0], item[1], item[2], 1.0) lut.Build() self.luts.append(lut) self.current_lut = self.luts[0] def _normalize(self, min, max, value): return (value - min) / (max - min) def _blockViewItemChanged(self, item): if item.checkState() == QtCore.Qt.Checked: self.exodus_result.showBlock(item.exodus_block) self.exodus_result.reader.Update() self.exodus_result.geom.Update() self.current_bounds = self.exodus_result.actor.GetBounds() self._updateContours() else: self.exodus_result.hideBlock(item.exodus_block) self.exodus_result.reader.Update() self.exodus_result.geom.Update() self.current_bounds = self.exodus_result.actor.GetBounds() self._updateContours() def _displaceToggled(self, value): self._timeSliderReleased() def _scaleToggled(self, value): self._timeSliderReleased() def _displaceMagnitudeTextReturn(self): self.current_displacement_magnitude = float(self.displace_magnitude_text.text()) self._timeSliderReleased() def _scaleMagnitudeTextReturn(self): self.current_scale_x_magnitude = float(self.scale_x_text.text()) self.current_scale_y_magnitude = float(self.scale_y_text.text()) self.current_scale_z_magnitude = float(self.scale_z_text.text()) self._timeSliderReleased() def _drawEdgesChanged(self, value): if value == QtCore.Qt.Checked: self.exodus_result.actor.GetProperty().EdgeVisibilityOn() self.exodus_result.clip_actor.GetProperty().EdgeVisibilityOn() else: self.exodus_result.actor.GetProperty().EdgeVisibilityOff() self.exodus_result.clip_actor.GetProperty().EdgeVisibilityOff() self.vtkwidget.repaint() ## # A method for toggling visiability of the scale bar legend, it is controlled # by the 'Hide Scalebar' toggle on the Visualize tab # @param value The interger value from the checkbox (1=checked) def _hideScalebarChanged(self, value): # Show when checked if value == QtCore.Qt.Checked: self.exodus_result.scalar_bar.VisibilityOn() # Hide when unchecked else: self.exodus_result.scalar_bar.VisibilityOff() # Update the GUI self.vtkwidget.repaint() ## # A method for toggling black background or gradient background, it is controlled # by the 'Black Background' toggle on the Visualize tab # @param value The interger value from the checkbox (1=checked) def _showBlackBackgroundChanged(self, value): # Black when checked if value == QtCore.Qt.Checked: self.renderer.SetBackground(0,0,0) self.renderer.SetGradientBackground(0) #self.renderer.ResetCamera() # Gradient when unchecked else: self.renderer.SetBackground(0,0,0) self.renderer.SetBackground(0.2,0.2,0.2) self.renderer.SetBackground2(1,1,1) self.renderer.SetGradientBackground(1) #self.renderer.ResetCamera() # Update thew GUI self.vtkwidget.repaint() def _fillComponentCombo(self, variable_name, components): self.variable_component.clear() self.variable_component.addItem('Magnitude') num_components = components[variable_name] if num_components > 1 and self.exodus_result.current_dim >= 2: self.variable_component.setDisabled(False) self.variable_component.addItem('X') self.variable_component.addItem('Y') else: self.variable_component.setDisabled(True) if num_components > 1 and self.exodus_result.current_dim == 3: self.variable_component.addItem('Z') def _contourVariableSelected(self, index): value_string = str(self.variable_contour.itemText(index)) self.current_variable = value_string self.current_variable_index = index if index in self.variable_contour_is_nodal: self.current_variable_is_nodal = self.variable_contour_is_nodal[index] else: self.current_variable_is_nodal = True self.currently_restoring_contours = True # Maybe results haven't been written yet... if not self.exodus_result.data.GetPointData().GetVectors(value_string) and not self.exodus_result.data.GetCellData().GetVectors(value_string): return if value_string in self.exodus_result.current_nodal_components: self._fillComponentCombo(value_string, self.exodus_result.current_nodal_components) elif value_string in self.exodus_result.current_elemental_components: self._fillComponentCombo(value_string, self.exodus_result.current_elemental_components) if self.current_variable not in self.contour_choices: self.contour_choices[self.current_variable] = ContourChoices() self.contour_choices[self.current_variable].restore(self) self.currently_restoring_contours = False def _variableComponentSelected(self, value): value_string = str(value) self.current_component = value_string if value_string == 'Magnitude': self.component_index = -1 elif value_string == 'X': self.component_index = 0 elif value_string == 'Y': self.component_index = 1 elif value_string == 'Z': self.component_index = 2 self._updateContours() def _updateContours(self): self.exodus_result.setColorScheme(self.current_lut) if self.component_index == -1: self.exodus_result.lut.SetVectorModeToMagnitude() elif self.component_index == 0: self.exodus_result.lut.SetVectorModeToComponent() self.exodus_result.lut.SetVectorComponent(0) elif self.component_index == 1: self.exodus_result.lut.SetVectorModeToComponent() self.exodus_result.lut.SetVectorComponent(1) elif self.component_index == 2: self.exodus_result.lut.SetVectorModeToComponent() self.exodus_result.lut.SetVectorComponent(2) if self.clip_groupbox.isChecked(): self.exodus_result.clipper.Modified() self.exodus_result.clipper.Update() self.exodus_result.clip_geom.Update() self.exodus_result.clip_mapper.Update() data = None if self.current_variable_is_nodal and self.current_variable in self.exodus_result.current_nodal_components: data = self.exodus_result.data.GetPointData().GetVectors(self.current_variable) self.exodus_result.mapper.SetScalarModeToUsePointFieldData() self.exodus_result.clip_mapper.SetScalarModeToUsePointFieldData() elif self.current_variable in self.exodus_result.current_elemental_components: data = self.exodus_result.data.GetCellData().GetVectors(self.current_variable) self.exodus_result.mapper.SetScalarModeToUseCellFieldData() self.exodus_result.clip_mapper.SetScalarModeToUseCellFieldData() self.exodus_result.mapper.SelectColorArray(self.current_variable) self.exodus_result.clip_mapper.SelectColorArray(self.current_variable) if data: self.current_range = data.GetRange(self.component_index) if self.min_current_radio.isChecked(): self.min_custom_text.setText(str(self.current_range[0])) self.min_custom_text.setCursorPosition(0) if self.max_current_radio.isChecked(): self.max_custom_text.setText(str(self.current_range[1])) self.max_custom_text.setCursorPosition(0) if self.min_custom_radio.isChecked(): self.min_custom_text.setDisabled(False) else: self.min_custom_text.setDisabled(True) if self.max_custom_radio.isChecked(): self.max_custom_text.setDisabled(False) else: self.max_custom_text.setDisabled(True) min = 0.0 try: min = float(self.min_custom_text.displayText()) except: min = 0.0 max = 0.0 try: max = float(self.max_custom_text.displayText()) except: max = 0.0 if self.current_variable not in self.contour_choices: self.contour_choices[self.current_variable] = ContourChoices() if not self.currently_restoring_contours: self.contour_choices[self.current_variable].save(self) the_range = (min, max) if min <= max: self.exodus_result.mapper.SetScalarRange(the_range) self.exodus_result.clip_mapper.SetScalarRange(the_range) self.exodus_result.scalar_bar.SetTitle(self.current_variable) self.renderer.AddActor2D(self.exodus_result.scalar_bar) self.vtkwidget.repaint() def _colorSchemeSelected(self, value): self.current_lut = self.luts[self.color_scheme_component.currentIndex()] self._updateContours() def _openFile(self, file_name): self._clear() self.base_stamp = os.path.getmtime(file_name) self.file_name = str(file_name) self.new_stuff_to_read = True self._updateData() self._updateData() # Call it again to read any adaptive results self._lastClicked() # Go to the last timestep self._resetView() # Reset the camera def _clickedOpen(self): file_name = QtGui.QFileDialog.getOpenFileName(self, "Open Result", "~/", "Input Files (*.e)") if not isinstance(file_name, basestring): # This happens when using pyside file_name = file_name[0] if file_name: self._openFile(file_name) def _resetView(self): self.renderer.ResetCamera() fp = self.renderer.GetActiveCamera().GetFocalPoint() p = self.renderer.GetActiveCamera().GetPosition() dist = math.sqrt( (p[0]-fp[0])**2 + (p[1]-fp[1])**2 + (p[2]-fp[2])**2 ) self.renderer.GetActiveCamera().SetPosition(fp[0], fp[1], fp[2]+dist) self.renderer.GetActiveCamera().SetViewUp(0.0, 1.0, 0.0) self.vtkwidget.repaint() def _saveView(self): file_name = QtGui.QFileDialog.getSaveFileName(self, "Image File Name", "~/", "Image Files (*.png)") if not isinstance(file_name, basestring): # This happens when using pyside file_name = file_name[0] if file_name != '': w2i = vtk.vtkWindowToImageFilter() writer = vtk.vtkPNGWriter() w2i.SetInput(self.vtkwidget.GetRenderWindow()) w2i.Update() writer.SetInputConnection(w2i.GetOutputPort()) writer.SetFileName(str(file_name)) self.vtkwidget.GetRenderWindow().Render() writer.Write() def _automaticUpdateChanged(self, value): if value == QtCore.Qt.Checked: self.automatically_update = True else: self.automatically_update = False def _beginningClicked(self): self.time_slider.setSliderPosition(0) self._timeSliderReleased() def _backClicked(self): self.time_slider.setSliderPosition(self.time_slider.sliderPosition()-1) self._timeSliderReleased() def _playClicked(self): self.play_button.setDisabled(True) self.pause_button.setDisabled(False) self.currently_playing = True first = True while((first or self.currently_looping) and self.currently_playing): first = False # If the slider is at the end then start over self.qt_app.processEvents() time.sleep(0.02) self.qt_app.processEvents() if self.time_slider.sliderPosition() == self.time_slider.maximum(): self.time_slider.setSliderPosition(0) while self.time_slider.sliderPosition() < self.time_slider.maximum(): self.time_slider.setSliderPosition(self.time_slider.sliderPosition()+1) self.qt_app.processEvents() self._timeSliderReleased() time.sleep(0.02) self.qt_app.processEvents() if not self.currently_playing: break self.play_button.setDisabled(False) self.pause_button.setDisabled(True) def _pauseClicked(self): self.play_button.setDisabled(False) self.pause_button.setDisabled(True) self.currently_playing = False def _forwardClicked(self): self.time_slider.setSliderPosition(self.time_slider.sliderPosition()+1) self._timeSliderReleased() def _lastClicked(self): self.time_slider.setSliderPosition(self.time_slider.maximum()) self._timeSliderReleased() def _loopClicked(self, state): if state: self.currently_looping = True else: self.currently_looping = False def _timeSliderChanged(self): self.time_slider_textbox.setText(str(self.time_slider.sliderPosition())) def _timeSliderReleased(self): textbox_string = self.time_slider_textbox.text() if textbox_string == '': textbox_string = str(self.exodus_result.min_timestep) if int(textbox_string) in self.timestep_to_exodus_result: for actor in self.exodus_result.current_actors: self.renderer.RemoveActor(actor) self.exodus_result = self.timestep_to_exodus_result[int(textbox_string)] if self.clip_groupbox.isChecked(): self.renderer.AddActor(self.exodus_result.clip_actor) if self.draw_edges_checkbox.checkState() == QtCore.Qt.Checked: self.exodus_result.clip_actor.GetProperty().EdgeVisibilityOn() else: self.exodus_result.clip_actor.GetProperty().EdgeVisibilityOff() else: self.renderer.AddActor(self.exodus_result.actor) if self.draw_edges_checkbox.checkState() == QtCore.Qt.Checked: self.exodus_result.actor.GetProperty().EdgeVisibilityOn() else: self.exodus_result.actor.GetProperty().EdgeVisibilityOff() num_block_view_items = self.block_view_model.rowCount() for i in xrange(num_block_view_items): item = self.block_view_model.item(i) if item.checkState() == QtCore.Qt.Checked: self.exodus_result.showBlock(item.exodus_block) else: self.exodus_result.hideBlock(item.exodus_block) if self.has_displacements and self.displace_groupbox.isChecked(): self.exodus_result.reader.SetApplyDisplacements(1) self.exodus_result.reader.SetDisplacementMagnitude(float(self.current_displacement_magnitude)) else: self.exodus_result.reader.SetApplyDisplacements(0) if self.scale_groupbox.isChecked(): self.exodus_result.actor.SetScale(self.current_scale_x_magnitude, self.current_scale_y_magnitude, self.current_scale_z_magnitude) else: self.exodus_result.actor.SetScale(1.0, 1.0, 1.0) if self.exodus_result.reader: self.exodus_result.reader.SetTimeStep(self.timestep_to_timestep[int(textbox_string)]) self.exodus_result.reader.Update() self.exodus_result.geom.Update() self.current_bounds = self.exodus_result.actor.GetBounds() self._updateContours() def _sliderTextboxReturn(self): self.time_slider.setSliderPosition(int(self.time_slider_textbox.text())) self._timeSliderReleased() def _associateResultsWithTimesteps(self): self.timestep_to_exodus_result = {} self.timestep_to_timestep = {} self.current_max_timestep = -1 for result in self.exodus_results: result.reader.UpdateTimeInformation() min = result.reader.GetTimeStepRange()[0] max = result.reader.GetTimeStepRange()[1] for timestep in xrange(min, max+1): self.current_max_timestep += 1 self.timestep_to_exodus_result[self.current_max_timestep] = result self.timestep_to_timestep[self.current_max_timestep] = timestep def _updateData(self): # Check to see if there are new exodus files with adapted timesteps in them. if self.file_name and self.exodus_result: for file_name in sorted(glob.glob(self.file_name + '-s*')): file_stamp = os.path.getmtime(file_name) if int(file_stamp) >= int(self.base_stamp) and int(file_stamp) <= int(time.time() - 1) and file_name not in self.file_names: self.file_names.append(file_name) exodus_result = ExodusResult(self, self.plane) exodus_result.setFileName(file_name, self.current_lut) self.exodus_results.append(exodus_result) self.new_stuff_to_read = True if not self.exodus_result: if not self.file_name: # Might have been set by opening a file output_file_names = self.input_file_widget.getOutputFileNames() else: output_file_names = [self.file_name] output_file = '' for file_name in output_file_names: if '.e' in file_name and os.path.exists(file_name): file_stamp = os.path.getmtime(file_name) if int(file_stamp) >= int(self.base_stamp) and int(file_stamp) <= int(time.time() - 1) and file_name not in self.file_names: self.file_name = file_name self.exodus_result = ExodusResult(self, self.plane) self.exodus_result.setFileName(file_name, self.current_lut) self.exodus_results.append(self.exodus_result) self.current_max_timestep = self.exodus_result.max_timestep self.renderer.AddActor(self.exodus_result.actor) self._drawEdgesChanged(self.draw_edges_checkbox.checkState()) if self.first: self.first = False self.renderer.ResetCamera() # Avoid z-buffer fighting vtk.vtkPolyDataMapper().SetResolveCoincidentTopologyToPolygonOffset() if self.clip_groupbox.isChecked(): _clippingToggled(True) self.vtkwidget.repaint() self._updateControls() self.time_slider.setSliderPosition(self.current_max_timestep) if self.new_stuff_to_read and self.exodus_result and self.automatically_update: self._associateResultsWithTimesteps() # self.exodus_result.reader.UpdateTimeInformation() # range = self.exodus_result.reader.GetTimeStepRange() # self.exodus_result.min_timestep = range[0] # self.exodus_result.max_timestep = range[1] self.time_slider.setMinimum(0) # Only automatically move forward if they're on the current step if self.time_slider.sliderPosition() == self.time_slider.maximum(): self.time_slider.setMaximum(self.current_max_timestep) self.time_slider.setSliderPosition(self.current_max_timestep) self._timeSliderReleased() if self.clip_groupbox.isChecked(): self._clipSliderReleased() self.vtkwidget.repaint() else: self.time_slider.setMaximum(self.current_max_timestep) self.new_stuff_to_read = False def _timestepBegin(self): self.new_stuff_to_read = True def _timestepEnd(self): pass def _clear(self): self.application.addExodusResultActors(self.renderer) self.file_name = None self.file_names = [] if not self.exodus_result: return for actor in self.exodus_result.current_actors: self.renderer.RemoveActor(actor) del self.exodus_result.current_actors[:] self.exodus_result = None self.exodus_results = [] self.timestep_to_exodus_result = {} def _runStarted(self): # Set the base time self.base_stamp = time.time() self._clear() self.timer.start() def _finalRead(self): self.new_stuff_to_read = True # Set this to true so we get one more update # Do it twice in case of adapted results self._updateData() self._updateData() def _runStopped(self): self.timer.stop() self.run_stopped_timer = QtCore.QTimer() self.run_stopped_timer.setInterval(1000) # Wait a second before updating the plots one last time self.run_stopped_timer.setSingleShot(True) self.run_stopped_timer.timeout.connect(self._finalRead) self.run_stopped_timer.start() def _clippingToggled(self, value): if value: self.renderer.RemoveActor(self.exodus_result.current_actor) self.renderer.AddActor(self.exodus_result.clip_actor) self.exodus_result.current_actor = self.exodus_result.clip_actor self.clip_plane_slider.setSliderPosition(50) self._clipSliderMoved(50) self._clipSliderReleased() else: self.renderer.RemoveActor(self.exodus_result.current_actor) self.renderer.AddActor(self.exodus_result.actor) self.exodus_result.current_actor = self.exodus_result.actor self.vtkwidget.repaint() def _clipNormalChanged(self, value): self.plane.SetOrigin(self.current_bounds[0], self.current_bounds[2], self.current_bounds[4]) if value == 'x': self.plane.SetNormal(1, 0, 0) elif value == 'y': self.plane.SetNormal(0, 1, 0) else: self.plane.SetNormal(0, 0, 1) self.clip_plane_slider.setSliderPosition(50) self._clipSliderMoved(50) self.vtkwidget.repaint() def _clipSliderReleased(self): self._updateContours() self.vtkwidget.repaint() def _clipSliderMoved(self, value): direction = str(self.clip_plane_combobox.currentText()) min = 0 max = 0 if direction == 'x': min = self.current_bounds[0] max = self.current_bounds[1] elif direction == 'y': min = self.current_bounds[2] max = self.current_bounds[3] elif direction == 'z': min = self.current_bounds[4] max = self.current_bounds[5] step_size = (max - min)/100.0 steps = value distance = float(steps)*step_size position = min + distance old = self.plane.GetOrigin() self.plane.SetOrigin(position if direction == 'x' else old[0], position if direction == 'y' else old[1], position if direction == 'z' else old[2]) self._updateContours() self.vtkwidget.repaint()
tool2.toggled.connect(editSwc) toolbar1.addAction(tool2) tool3 = QtGui.QAction(toolbar1) tool3_icon = QtGui.QIcon() tool3_icon.addFile(r'G:\sulei\workplace\TraceTool\Resource\Science.png') tool3.setIcon(tool3_icon) tool3.triggered.connect(changeLineWidth) toolbar1.addAction(tool3) mainwin.addToolBar(toolbar1) mainwin.setMenuBar(menubar1) mainwin_location = QtCore.QRect(600, 300, 400, 400) mainwin.setMaximumSize(400, 400) mainwin.setGeometry(mainwin_location) central_widget = QtGui.QWidget(mainwin) mainwin.setCentralWidget(central_widget) layout1 = QtGui.QHBoxLayout() central_widget.setLayout(layout1) vtk_widget = QVTKRenderWindowInteractor(central_widget) vtk_widget.setMinimumSize(50, 50) layout1.addWidget(vtk_widget) vtk_widget.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) ren = vtk.vtkRenderer() style1 = SwcEditStyle() iren = vtk_widget.GetRenderWindow().GetInteractor() iren.SetInteractorStyle(style1) vtk_widget.Initialize() vtk_widget.Start() mainwin.show() sys.exit(app.exec_())
class MeshViewer(QtGui.QWidget): app = QtGui.QApplication(sys.argv) """ Qt GUI for visu. the output """ def __init__(self, truss, algo): QtGui.QWidget.__init__(self) self.truss = truss self.algo = algo self.algo.dhook = self self.running = 'init' print "starting MeshViewer init..." self.__setupGUI() self.__setupVTK() self.app.lastWindowClosed.connect(self.app.quit) self.show() print "MeshViewer ready." def closeEvent(self, event): self.algo.stopit=True self.running='running' # sort de "while self.running=='pause'" print "GUI killed!" QtGui.QWidget.closeEvent(self,event) def start(self): self.app.exec_() def __setupGUI(self): self.setWindowTitle("MeshViewer") self.resize(800, 600) # vtk window self.vtkwidget = QVTKRenderWindowInteractor(self) # "self" sinon, rien ne s'affiche self.vtkwidget.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)) self.vtkwidget.setMinimumSize(QtCore.QSize(300, 300)); self.vtkwidget.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding) self.vtkwidget.Initialize() self.renderer = vtk.vtkRenderer() self.renderer.SetBackground(1.0, 1.0, 1.0) self.vtkwidget.GetRenderWindow().AddRenderer(self.renderer) style = vtk.vtkInteractorStyleTrackballCamera() self.vtkwidget.SetInteractorStyle(style) hbox = QtGui.QHBoxLayout() self.setLayout(hbox) hbox.addWidget(self.vtkwidget) pan = QtGui.QFrame() pan.setMaximumSize(QtCore.QSize(200,999999)) hbox.addWidget(pan) vbox = QtGui.QVBoxLayout() pan.setLayout(vbox) self.startBut = QtGui.QPushButton(self.tr("start!")) self.connect(self.startBut, QtCore.SIGNAL("clicked()"), self.startSlot) vbox.addWidget(self.startBut) groupBox = QtGui.QGroupBox("Infos") self.steplabel = QtGui.QLabel("step # 0") self.loadlabel = QtGui.QLabel("lambda = %2.8f" % 0) gbox = QtGui.QVBoxLayout() groupBox.setLayout(gbox) gbox.addWidget(self.steplabel) gbox.addWidget(self.loadlabel) vbox.addWidget(groupBox) vbox.addStretch(1) def startSlot(self): if self.running=='init': self.startBut.setText('Pause') # on demarre et on affiche "pause" self.running='running' self.algo.run() self.startBut.setText("Quit") self.running='quit' elif self.running=='running': # on stoppe et on affiche 'continue" self.running='pause' self.startBut.setText("Continue") while self.running=='pause': self.app.processEvents(QtCore.QEventLoop.WaitForMoreEvents) elif self.running=='pause': self.running='running' self.startBut.setText("Pause") elif self.running=='quit': self.app.quit() def disableStart(self): self.startBut.setDisabled(True) def __setupVTK(self): # polydata self.__createPolyData() self.poly = PolyData(self.polydata) self.renderer.AddActor(self.poly.actor) self.renderer.AddActor2D(self.poly.pointLabels) self.resetCamera() def resetCamera(self): self.renderer.ResetCamera() cam1 = self.renderer.GetActiveCamera() # 3D if 0: cam1.Elevation(35) cam1.SetViewUp(0, 1, 0) cam1.Azimuth(30) #2D else: cam1.Elevation(0) cam1.SetViewUp(0, 1, 0) cam1.Azimuth(0) self.renderer.ResetCameraClippingRange() def display(self, step, lamda): self.steplabel.setText("step # %d" % step) self.loadlabel.setText("lambda = %2.8f" % lamda) self.points.Reset() self.vertices.Reset() self.lines.Reset() self.scalars.Reset() # points nmap={} i=0 for nod in self.truss.nodes: nmap[nod.nb]=i self.points.InsertPoint(i, nod.x, nod.y, 0.0) self.scalars.InsertNextValue(nod.nb) # node cells vertex = vtk.vtkVertex() vertex.GetPointIds().SetId(0, i) self.vertices.InsertNextCell(vertex) i+=1 self.points.Modified() self.vertices.Modified() for bar in self.truss.bars: line = vtk.vtkLine() ids = line.GetPointIds() ids.SetNumberOfIds(2) for j in range(len(bar.nodes)): ids.SetId(j, nmap[bar.nodes[j].nb]) self.lines.InsertNextCell(line) self.lines.Modified() self.polydata.Modified() self.render() def ragequit(self): print "rage quit!" self.algo.stopit=True self.app.quit() def render(self): # draw the scene self.vtkwidget.Render() self.app.processEvents() def refresh(self): self.app.processEvents() def __createPolyData(self): print 'creating vtkPolyData...' self.points = vtk.vtkPoints() self.polydata = vtk.vtkPolyData() self.vertices = vtk.vtkCellArray() self.lines = vtk.vtkCellArray() self.polydata.SetPoints(self.points) self.polydata.SetVerts(self.vertices) self.polydata.SetLines(self.lines) # points self.scalars = vtk.vtkFloatArray() self.scalars.SetNumberOfComponents(1) self.polydata.GetPointData().SetScalars(self.scalars) nmap={} i=0 for nod in self.truss.nodes: nmap[nod.nb]=i self.points.InsertPoint(i, nod.x, nod.y, 0.0) self.scalars.InsertNextValue(nod.nb) # node cells vertex = vtk.vtkVertex() vertex.GetPointIds().SetId(0, i) self.vertices.InsertNextCell(vertex) i+=1 self.points.Modified() self.vertices.Modified() for bar in self.truss.bars: line = vtk.vtkLine() ids = line.GetPointIds() ids.SetNumberOfIds(2) for j in range(len(bar.nodes)): ids.SetId(j, nmap[bar.nodes[j].nb]) self.lines.InsertNextCell(line) self.lines.Modified()