def __init__(self, main_wnd): # self.AddObserver('LeftButtonPressEvent', self.left_button_press_event) # self.AddObserver('MouseMoveEvent', self.mouse_move_event) # self.mouse_motion_flag = 0 # self.ren = self.iren.FindPokedRenderer(0, 0) self.ren = main_wnd.render self.renWin = self.ren.GetRenderWindow() self.iren = self.renWin.GetInteractor() self.grid = main_wnd.grid self.actors = [] self.node_ids = [] self.picker = vtk.vtkPointPicker() self.picker_points = [] # self.area_picker = vtk.vtkAreaPicker() self.area_picker = vtk.vtkRenderedAreaPicker() self.area_picker.SetRenderer(self.ren) self.Rotating = 0 self.Panning = 0 self.Zooming = 0 self.SinglePick = 0 self.BoxPick = 0 self.SinglePickRelease = 0 self.BoxPickRelease = 0 self.iren.AddObserver('LeftButtonPressEvent', self.PickEvent) self.iren.AddObserver('LeftButtonReleaseEvent', self.PickEvent) self.iren.AddObserver("MiddleButtonPressEvent", self.MoveEvent) self.iren.AddObserver("MiddleButtonReleaseEvent", self.MoveEvent) self.iren.AddObserver("MouseMoveEvent", self.MouseMove) self.iren.AddObserver("KeyPressEvent", self.Keypress)
def _pick_visible_ids(self, xmin, ymin, xmax, ymax): """ Does an area pick of all the visible ids inside the box """ #vcs = vtk.vtkVisibleCellSelector() area_picker = vtk.vtkRenderedAreaPicker() area_picker.AreaPick(xmin, ymin, xmax, ymax, self.parent.rend)
def OpenAddBoundaryDlg(self): self.style = vtk.vtkInteractorStyleRubberBand2D() self.position=[0.0,0.0,0.0,0.0] self.statusbar.showMessage('Select Boundary Elements') self.style.area_picker = vtk.vtkRenderedAreaPicker() self.style.AddObserver("LeftButtonReleaseEvent", self.leftButtonReleaseEvent) self.style.SetDefaultRenderer(self.renderer) self.renWinInteract.SetInteractorStyle(self.style) self.renWinInteract.SetPicker(self.style.area_picker)
def enable_cell_picking(self, mesh=None, callback=None, through=True, show=True, show_message=True, style='wireframe', line_width=5, color='pink', font_size=18, **kwargs): """ Enables picking of cells. Press "r" to enable retangle based selection. Press "r" again to turn it off. Selection will be saved to ``self.picked_cells``. Also press "p" to pick a single cell under the mouse location. Uses last input mesh for input by default. Warning ------- Visible cell picking (``through=False``) is known to not perfrom well and produce incorrect selections on non-triangulated meshes if using any grpahics card other than NVIDIA. A warning will be thrown if the mesh is not purely triangles when using visible cell selection. Parameters ---------- mesh : pyvista.Common, optional UnstructuredGrid grid to select cells from. Uses last input grid by default. callback : function, optional When input, calls this function after a selection is made. The picked_cells are input as the first parameter to this function. through : bool, optional When True (default) the picker will select all cells through the mesh. When False, the picker will select only visible cells on the mesh's surface. show : bool Show the selection interactively show_message : bool, str Show the message about how to use the cell picking tool. If this is a string, that will be the message shown. kwargs : optional All remaining keyword arguments are used to control how the selection is intereactively displayed """ if hasattr(self, 'notebook') and self.notebook: raise AssertionError( 'Cell picking not available in notebook plotting') if mesh is None: if not hasattr(self, 'mesh'): raise Exception('Input a mesh into the Plotter class first or ' 'or set it in this function') mesh = self.mesh def end_pick_helper(picker, event_id): if show: # Use try incase selection is empty try: self.add_mesh(self.picked_cells, name='_cell_picking_selection', style=style, color=color, line_width=line_width, pickable=False, reset_camera=False, **kwargs) except RuntimeError: pass if callback is not None and self.picked_cells.n_cells > 0: callback(self.picked_cells) # TODO: Deactivate selection tool return def through_pick_call_back(picker, event_id): extract = vtk.vtkExtractGeometry() mesh.cell_arrays['orig_extract_id'] = np.arange(mesh.n_cells) extract.SetInputData(mesh) extract.SetImplicitFunction(picker.GetFrustum()) extract.Update() self.picked_cells = pyvista.wrap(extract.GetOutput()) return end_pick_helper(picker, event_id) def visible_pick_call_back(picker, event_id): x0, y0, x1, y1 = self.get_pick_position() selector = vtk.vtkOpenGLHardwareSelector() selector.SetFieldAssociation( vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS) selector.SetRenderer(self.renderer) selector.SetArea(x0, y0, x1, y1) cellids = selector.Select().GetNode(0) if cellids is None: # No selection return selection = vtk.vtkSelection() selection.AddNode(cellids) extract = vtk.vtkExtractSelectedIds() extract.SetInputData(0, mesh) extract.SetInputData(1, selection) extract.Update() self.picked_cells = pyvista.wrap(extract.GetOutput()) return end_pick_helper(picker, event_id) area_picker = vtk.vtkRenderedAreaPicker() if through: area_picker.AddObserver(vtk.vtkCommand.EndPickEvent, through_pick_call_back) else: # check if mesh is triangulated or not # Reference: # https://github.com/pyvista/pyvista/issues/277 # https://github.com/pyvista/pyvista/pull/281 message = "Surface picking non-triangulated meshes is known to "\ "not work properly with non-NVIDIA GPUs. Please "\ "consider triangulating your mesh:\n"\ "\t`.extract_geometry().tri_filter()`" if (not isinstance(mesh, pyvista.PolyData) or mesh.faces.size % 4 or not np.all(mesh.faces.reshape(-1, 4)[:, 0] == 3)): logging.warning(message) area_picker.AddObserver(vtk.vtkCommand.EndPickEvent, visible_pick_call_back) self.enable_rubber_band_style() self.iren.SetPicker(area_picker) # Now add text about cell-selection if show_message: if show_message is True: show_message = "Press R to toggle selection tool" if not through: show_message += "\nPress P to pick a single cell under the mouse" self.add_text(str(show_message), font_size=font_size, name='_cell_picking_message') return
def om_display_vtp(f, n = 0): """ This function displays a VTK::vtp file generated with OpenMEEG. Such a file defines a polydata, containing points and triangles of several meshes which are labelled through a vtkAbstractArray (Strings) associated to the cells (mesh names). Results of the forward problem (or a cortical mapping) can be seen thanks to arrays associated to points and cells (respectively potentials and normals currents). """ welcome = """Welcome\n\n Switch the button: To either see Potentials (on points) or Currents (on triangles)\n Move the slider to see all sources (columns of the input matrix)\n Press 'r': To select points/cells.\n""" # This callback function does updates the mappers for where n is the slider value def CleanPickData(object, event): for i in range(4): rens[i].RemoveActor(selactor) if buttonWidget.GetRepresentation().GetState(): PickData(object, event, selactor, 1, view, text_init) else: PickData(object, event, selactor, 0, view, text_init) def SelectSource(object, event): # object will be the slider2D slidervalue = int(round(object.GetRepresentation().GetValue())) for i in range(4): mappers[i].GetInput().GetPointData().SetActiveScalars("Potentials-"+str(slidervalue)) mappers[i].GetInput().GetCellData().SetActiveScalars("Currents-"+str(slidervalue)) renWin.SetWindowName(renWin.GetWindowName()[0:(renWin.GetWindowName().find('-')+1)]+str(slidervalue)) UpdateColorBar(colorBars[i], mappers[i]) # This callback function does updates the Scalar Mode To Use def SelectMode(object, event): # object will be the buttonWidget for i in range(4): if (object.GetRepresentation().GetState()): mappers[i].SetScalarModeToUseCellData() renWin.SetWindowName(renWin.GetWindowName().replace('Potentials','Currents')) else: mappers[i].SetScalarModeToUsePointData() renWin.SetWindowName(renWin.GetWindowName().replace('Currents','Potentials')) UpdateColorBar(colorBars[i], mappers[i]) # A window with an interactor renWin = vtk.vtkRenderWindow() renWin.SetSize(600, 600) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) iren.SetInteractorStyle(vtk.vtkInteractorStyleRubberBandPick()) # A picker (to pick points/cells) picker = vtk.vtkRenderedAreaPicker() iren.SetPicker(picker) # Read the input file reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(f); reader.Update() poly = reader.GetOutput() renWin.SetWindowName(f+' Potentials-'+str(n)) # determine the number of sources nb_sources = 0 for i in range(poly.GetPointData().GetNumberOfArrays()): if poly.GetPointData().GetGlobalIds('Potentials-'+str(i)): nb_sources += 1 if n < nb_sources: poly.GetPointData().SetActiveScalars('Potentials-'+str(n)) poly.GetCellData().SetActiveScalars('Currents-'+str(n)) # Get the mesh names cell_labels = poly.GetCellData().GetAbstractArray(0) assert(cell_labels.GetName()=='Names') s = set(); nb_meshes = 0; cell_ids = list() for i in range(cell_labels.GetNumberOfValues()): s.add(cell_labels.GetValue(i)) if len(s)>nb_meshes: # if a label is added, store the ID for the connectivity filter cell_ids.append(i) nb_meshes += 1 # Number of meshes assert(nb_meshes<=4) # Multiple viewports: 4 xmins = [0,.5,0,.5]; xmaxs = [0.5,1,0.5,1]; ymins = [0,0,.5,.5]; ymaxs = [0.5,0.5,1,1] mappers = [vtk.vtkPolyDataMapper() for i in range(4)] colorBars = [vtk.vtkScalarBarActor() for i in range(4)] actors = [vtk.vtkActor() for i in range(4)] rens = [vtk.vtkRenderer() for i in range(4)] for i in range(4): rens[i].SetViewport(xmins[i],ymins[i],xmaxs[i],ymaxs[i]); # Display the meshes if (i < nb_meshes): # Create a connectivity filter based on cell seeded region (to display # only one mesh per viewport) conn = vtk.vtkPolyDataConnectivityFilter() conn.SetInput(poly) conn.SetExtractionModeToCellSeededRegions() conn.AddSeed(cell_ids[i]); conn.Update() actor_meshname = vtk.vtkTextActor(); actor_meshname.SetInput(cell_labels.GetValue(cell_ids[i])); actor_meshname.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport(); actor_meshname.SetPosition(0.5, 0.85); tprop = actor_meshname.GetTextProperty(); tprop.SetFontSize(30) tprop.SetFontFamilyToArial(); tprop.SetColor(1, 1, 1); tprop.SetJustificationToCentered() mappers[i].SetInputConnection(conn.GetOutputPort()) mappers[i].SetScalarModeToUsePointData(); mappers[i].Update() if nb_sources: rens[i].AddActor2D(colorBars[i]) actors[i].SetMapper(mappers[i]) rens[i].AddActor2D(actor_meshname) rens[i].AddActor(actors[i]) if (i == 0): cam = rens[i].GetActiveCamera() rens[i].ResetCamera() else: # Create a plane to cut plane = vtk.vtkPlane(); plane.SetOrigin(0,0,0); plane.SetNormal(1,0,0); # Create cutter extract = vtk.vtkExtractPolyDataGeometry(); extract.SetInput(poly) extract.SetImplicitFunction(plane); extract.ExtractBoundaryCellsOff() mappers[i].SetInputConnection(extract.GetOutputPort()) mappers[i].SetScalarModeToUsePointData(); mappers[i].Update() # Create plane actor actors[i].SetMapper(mappers[i]) rens[i].AddActor(actors[i]) rens[i].SetActiveCamera(cam) if nb_sources: UpdateColorBar(colorBars[i], mappers[i]) renWin.AddRenderer(rens[i]) renWin.Render(); if nb_sources > 1: # Slider sliderWidget = vtk.vtkSliderWidget() slider = vtk.vtkSliderRepresentation2D(); slider.SetMaximumValue(nb_sources-1) slider.SetValue(n); slider.SetEndCapLength(0.01); slider.SetLabelFormat('%1.0f') slider.SetSliderWidth(0.05); slider.SetSliderLength(1./nb_sources) slider.GetPoint1Coordinate().SetCoordinateSystemToNormalizedViewport() slider.GetPoint1Coordinate().SetValue(.0 ,0.02) slider.GetPoint2Coordinate().SetCoordinateSystemToNormalizedViewport() slider.GetPoint2Coordinate().SetValue(1. ,0.02); sliderWidget.SetInteractor(iren); sliderWidget.SetRepresentation(slider); sliderWidget.SetAnimationModeToAnimate(); sliderWidget.EnabledOn(); sliderWidget.AddObserver("InteractionEvent", SelectSource); if not nb_sources == 0: # The button for choosing Potentials/Currents buttonWidget = vtk.vtkButtonWidget() button = vtk.vtkTexturedButtonRepresentation2D(); button.SetNumberOfStates(2) tex1r = vtk.vtkImageData(); tex2r = vtk.vtkImageData(); prop = vtk.vtkTextProperty(); prop.SetFontSize(24); prop.SetColor(1,0,0); prop.SetBold(2); prop.SetShadow(2); str2im = vtk.vtkFreeTypeStringToImage() str2im.RenderString(prop,'Potentials',tex1r) str2im.RenderString(prop,'Currents',tex2r) button.SetButtonTexture(0, tex1r) button.SetButtonTexture(1, tex2r) buttonWidget.SetInteractor(iren); buttonWidget.SetRepresentation(button); button.SetPlaceFactor(1); button.PlaceWidget([0., 100, 50, 500, 0, 0]); buttonWidget.On() buttonWidget.AddObserver(vtk.vtkCommand.StateChangedEvent,SelectMode); # Selection selactor = vtk.vtkActor() view = vtk.vtkContextView(); view.GetRenderWindow().SetWindowName('Plot') view.GetRenderWindow().SetPosition(600, 0); view.GetRenderWindow().SetSize(600, 600) # Welcome text text_init = vtk.vtkTextActor() text_init.SetPosition(10, 300) text_init.SetInput(welcome) text_init.GetTextProperty().SetColor(1.0, 0.0, 0.0) view.GetRenderer().AddActor2D(text_init) view.GetInteractor().Initialize() iren.AddObserver(vtk.vtkCommand.EndPickEvent,CleanPickData) iren.Initialize() iren.Start()
def om_display_vtk(f,d = 0,n = 0): """ This function displays a VTK::vtk file generated with OpenMEEG. Such a file defines a polydata, containing points and triangles of a single mesh. Most often a EEG helmet mesh and associated leadfield. """ welcome = """Welcome\n\n Move the slider to see all sources (columns of the input matrix)\n Press 'r': To select points/cells.\n""" # This callback function does updates the mappers for where n is the slider value def CleanPickData(object, event): ren.RemoveActor(selactor) PickData(object, event, selactor, 0, view, text_init) def SelectSource(object, event): # object will be the slider2D slidervalue = int(round(object.GetRepresentation().GetValue())) mapper.GetInput().GetPointData().SetActiveScalars("Potentials-"+str(slidervalue)) renWin.SetWindowName(renWin.GetWindowName()[0:(renWin.GetWindowName().find('-')+1)]+str(slidervalue)) UpdateColorBar(colorBar, mapper) # A window with an interactor renWin = vtk.vtkRenderWindow() renWin.SetSize(600, 600) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) iren.SetInteractorStyle(vtk.vtkInteractorStyleRubberBandPick()) # A picker (to pick points/cells) picker = vtk.vtkRenderedAreaPicker() iren.SetPicker(picker) # Read the input file reader = vtk.vtkPolyDataReader() reader.SetFileName(f); reader.Update() poly = reader.GetOutput() renWin.SetWindowName(f+' Potentials-'+str(n)) # determine the number of sources nb_sources = 0 for i in range(poly.GetPointData().GetNumberOfArrays()): if poly.GetPointData().GetGlobalIds('Potentials-'+str(i)): nb_sources += 1 if nb_sources == 0: #the file doesn't provide potentials if not d.__class__ == int: assert(d.shape[0] == poly.GetNumberOfPoints()) nb_sources = d.shape[1] pot = [vtk.vtkDoubleArray() for j in range(d.shape[1])] for j in range(d.shape[1]): pot[j].SetName('Potentials-'+str(j)) for i in range(d.shape[0]): pot[j].InsertNextValue(d[i,j]) poly.GetPointData().AddArray(pot[j]) poly.Update() if not poly.GetPointData().GetGlobalIds('Indices'): ind = vtk.vtkUnsignedIntArray() ind.SetName('Indices') for i in range(poly.GetNumberOfPoints()): ind.InsertNextValue(i) poly.GetPointData().AddArray(ind) poly.GetPointData().SetActiveScalars('Potentials-'+str(n)) mapper = vtk.vtkPolyDataMapper() colorBar = vtk.vtkScalarBarActor() actor = vtk.vtkActor() ren = vtk.vtkRenderer() mapper.SetInput(poly) mapper.SetScalarModeToUsePointData(); mapper.Update() actor.SetMapper(mapper) ren.AddActor(actor) if nb_sources: ren.AddActor2D(colorBar) UpdateColorBar(colorBar, mapper) renWin.AddRenderer(ren) renWin.Render() if nb_sources > 1: # Slider sliderWidget = vtk.vtkSliderWidget() slider = vtk.vtkSliderRepresentation2D(); slider.SetMaximumValue(nb_sources-1) slider.SetValue(n); slider.SetEndCapLength(0.01); slider.SetLabelFormat('%1.0f') slider.SetSliderWidth(0.05); slider.SetSliderLength(1./nb_sources) slider.GetPoint1Coordinate().SetCoordinateSystemToNormalizedViewport() slider.GetPoint1Coordinate().SetValue(.0, 0.02) slider.GetPoint2Coordinate().SetCoordinateSystemToNormalizedViewport() slider.GetPoint2Coordinate().SetValue(1., 0.02); sliderWidget.SetInteractor(iren); sliderWidget.SetRepresentation(slider); sliderWidget.SetAnimationModeToAnimate(); sliderWidget.EnabledOn(); sliderWidget.AddObserver("InteractionEvent", SelectSource); # Selection selactor = vtk.vtkActor() view = vtk.vtkContextView(); view.GetRenderWindow().SetWindowName('Plot') view.GetRenderWindow().SetPosition(600, 0); view.GetRenderWindow().SetSize(600, 600) # Welcome text text_init = vtk.vtkTextActor() text_init.SetPosition(10, 300) text_init.SetInput(welcome) text_init.GetTextProperty().SetColor(1.0, 0.0, 0.0) view.GetRenderer().AddActor2D(text_init) view.GetInteractor().Initialize() iren.AddObserver(vtk.vtkCommand.EndPickEvent,CleanPickData) iren.Initialize() iren.Start()
def enable_cell_picking(self, mesh=None, callback=None, through=True, show=True, show_message=True, style='wireframe', line_width=5, color='pink', font_size=18, start=False, **kwargs): """Enable picking at cells. Press "r" to enable retangle based selection. Press "r" again to turn it off. Selection will be saved to ``self.picked_cells``. Also press "p" to pick a single cell under the mouse location. When using ``through=False``, and multiple meshes are being picked, the picked cells in ````self.picked_cells`` will be a :class:`MultiBlock` dataset for each mesh's selection. Uses last input mesh for input by default. Warning ------- Visible cell picking (``through=False``) will only work if the mesh is displayed with a ``'surface'`` representation style (the default). Parameters ---------- mesh : pyvista.DataSet, optional Mesh to select cells from. When ``through`` is ``True``, uses last input mesh by default. When ``through`` is ``False``, all meshes in the scene are available for picking and this argument is ignored. If you would like to only pick a single mesh in the scene, use the ``pickable=False`` argument when adding the other meshes to the scene. callback : function, optional When input, calls this function after a selection is made. The picked_cells are input as the first parameter to this function. through : bool, optional When True (default) the picker will select all cells through the mesh. When False, the picker will select only visible cells on the mesh's surface. show : bool Show the selection interactively style : str Visualization style of the selection. One of the following: ``style='surface'``, ``style='wireframe'``, ``style='points'``. Defaults to ``'wireframe'``. line_width : float, optional Thickness of selected mesh edges. Default 5. color : str The color of the selected mesh is shown. show_message : bool, str Show the message about how to use the cell picking tool. If this is a string, that will be the message shown. font_size : int Sets the size of the message. start : bool Automatically start the cell selection tool. kwargs : optional All remaining keyword arguments are used to control how the selection is intereactively displayed. """ if mesh is None: if not hasattr(self, 'mesh') or self.mesh is None: raise AttributeError( 'Input a mesh into the Plotter class first or ' 'or set it in this function') mesh = self.mesh self_ = weakref.ref(self) # make sure to consistently use renderer renderer_ = weakref.ref(self.renderer) def end_pick_helper(picker, event_id): # Merge the selection into a single mesh picked = self_().picked_cells if isinstance(picked, pyvista.MultiBlock): if picked.n_blocks > 0: picked = picked.combine() else: picked = pyvista.UnstructuredGrid() # Check if valid is_valid_selection = picked.n_cells > 0 if show and is_valid_selection: # Use try in case selection is empty self_().add_mesh(picked, name='_cell_picking_selection', style=style, color=color, line_width=line_width, pickable=False, reset_camera=False, **kwargs) # render here prior to running the callback self_().render() elif not is_valid_selection: self.remove_actor('_cell_picking_selection') self_().picked_cells = None if callback is not None: try_callback(callback, self_().picked_cells) # TODO: Deactivate selection tool return def through_pick_call_back(picker, event_id): extract = vtk.vtkExtractGeometry() mesh.cell_arrays['orig_extract_id'] = np.arange(mesh.n_cells) extract.SetInputData(mesh) extract.SetImplicitFunction(picker.GetFrustum()) extract.Update() self_().picked_cells = pyvista.wrap(extract.GetOutput()) return end_pick_helper(picker, event_id) def visible_pick_call_back(picker, event_id): x0, y0, x1, y1 = renderer_().get_pick_position() selector = vtk.vtkOpenGLHardwareSelector() selector.SetFieldAssociation( vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS) selector.SetRenderer(renderer_()) selector.SetArea(x0, y0, x1, y1) selection = selector.Select() picked = pyvista.MultiBlock() for node in range(selection.GetNumberOfNodes()): selection_node = selection.GetNode(node) if selection_node is None: # No selection continue cids = pyvista.convert_array(selection_node.GetSelectionList()) actor = selection_node.GetProperties().Get( vtk.vtkSelectionNode.PROP()) if actor.GetProperty().GetRepresentation() != 2: # surface logging.warning( "Display representations other than `surface` will result in incorrect results." ) smesh = actor.GetMapper().GetInputAsDataSet() smesh = smesh.copy() smesh["original_cell_ids"] = np.arange(smesh.n_cells) tri_smesh = smesh.extract_surface().triangulate() cids_to_get = tri_smesh.extract_cells( cids)["original_cell_ids"] picked.append(smesh.extract_cells(cids_to_get)) if len(picked) == 1: self_().picked_cells = picked[0] else: self_().picked_cells = picked return end_pick_helper(picker, event_id) area_picker = vtk.vtkRenderedAreaPicker() if through: area_picker.AddObserver(vtk.vtkCommand.EndPickEvent, through_pick_call_back) else: # NOTE: there can be issues with non-triangulated meshes # Reference: # https://github.com/pyvista/pyvista/issues/277 # https://github.com/pyvista/pyvista/pull/281 # https://discourse.vtk.org/t/visible-cell-selection-hardwareselector-py-example-is-not-working-reliably/1262 area_picker.AddObserver(vtk.vtkCommand.EndPickEvent, visible_pick_call_back) self.enable_rubber_band_style() self.iren.SetPicker(area_picker) # Now add text about cell-selection if show_message: if show_message is True: show_message = "Press R to toggle selection tool" if not through: show_message += "\nPress P to pick a single cell under the mouse" self.add_text(str(show_message), font_size=font_size, name='_cell_picking_message') if start: self._style_class.StartSelect() return
def enable_cell_picking(self, mesh=None, callback=None, through=True, show=True, show_message=True, style='wireframe', line_width=5, color='pink', font_size=18, start=False, **kwargs): """Enable picking at cells. Press "r" to enable retangle based selection. Press "r" again to turn it off. Selection will be saved to ``self.picked_cells``. Also press "p" to pick a single cell under the mouse location. When using ``through=False``, and multiple meshes are being picked, the picked cells in ````self.picked_cells`` will be a :class:`MultiBlock` dataset for each mesh's selection. Uses last input mesh for input by default. Warning ------- Visible cell picking (``through=False``) is known to not perform well and produce incorrect selections on non-triangulated meshes if using any grpahics card other than NVIDIA. A warning will be thrown if the mesh is not purely triangles when using visible cell selection. Parameters ---------- mesh : pyvista.Common, optional Mesh to select cells from. When ``through`` is ``True``, uses last input mesh by default. When ``through`` is ``False``, all meshes in the scene are available for picking and this argument is ignored. If you would like to only pick a single mesh in the scene, use the ``pickable=False`` argument when adding the other meshes to the scene. callback : function, optional When input, calls this function after a selection is made. The picked_cells are input as the first parameter to this function. through : bool, optional When True (default) the picker will select all cells through the mesh. When False, the picker will select only visible cells on the mesh's surface. show : bool Show the selection interactively style : str Visualization style of the selection. One of the following: ``style='surface'``, ``style='wireframe'``, ``style='points'``. Defaults to ``'wireframe'``. line_width : float, optional Thickness of selected mesh edges. Default 5. color : str The color of the selected mesh is shown. show_message : bool, str Show the message about how to use the cell picking tool. If this is a string, that will be the message shown. font_size : int Sets the size of the message. start : bool Automatically start the cell selection tool. kwargs : optional All remaining keyword arguments are used to control how the selection is intereactively displayed. """ if hasattr(self, 'notebook') and self.notebook: raise AssertionError( 'Cell picking not available in notebook plotting') if mesh is None: if not hasattr(self, 'mesh'): raise Exception('Input a mesh into the Plotter class first or ' 'or set it in this function') mesh = self.mesh renderer = self.renderer # make sure to consistently use renderer def end_pick_helper(picker, event_id): if show: # Use try in case selection is empty if isinstance(self.picked_cells, pyvista.MultiBlock): picked = self.picked_cells.combine() else: picked = self.picked_cells try: self.add_mesh(picked, name='_cell_picking_selection', style=style, color=color, line_width=line_width, pickable=False, reset_camera=False, **kwargs) except RuntimeError: pass if callback is not None and self.picked_cells.n_cells > 0: try_callback(callback, self.picked_cells) # TODO: Deactivate selection tool return def through_pick_call_back(picker, event_id): extract = vtk.vtkExtractGeometry() mesh.cell_arrays['orig_extract_id'] = np.arange(mesh.n_cells) extract.SetInputData(mesh) extract.SetImplicitFunction(picker.GetFrustum()) extract.Update() self.picked_cells = pyvista.wrap(extract.GetOutput()) return end_pick_helper(picker, event_id) def visible_pick_call_back(picker, event_id): x0, y0, x1, y1 = renderer.get_pick_position() selector = vtk.vtkOpenGLHardwareSelector() selector.SetFieldAssociation( vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS) selector.SetRenderer(renderer) selector.SetArea(x0, y0, x1, y1) selection = selector.Select() picked = pyvista.MultiBlock() for node in range(selection.GetNumberOfNodes()): cellids = selection.GetNode(node) if cellids is None: # No selection continue smesh = cellids.GetProperties().Get(vtk.vtkSelectionNode.PROP( )).GetMapper().GetInputAsDataSet() selection_filter = vtk.vtkSelection() selection_filter.AddNode(cellids) extract = vtk.vtkExtractSelectedIds() extract.SetInputData(0, smesh) extract.SetInputData(1, selection_filter) extract.Update() picked.append(pyvista.wrap(extract.GetOutput())) if len(picked) == 1: self.picked_cells = picked[0] else: self.picked_cells = picked return end_pick_helper(picker, event_id) area_picker = vtk.vtkRenderedAreaPicker() if through: area_picker.AddObserver(vtk.vtkCommand.EndPickEvent, through_pick_call_back) else: # check if mesh is triangulated or not # Reference: # https://github.com/pyvista/pyvista/issues/277 # https://github.com/pyvista/pyvista/pull/281 message = "Surface picking non-triangulated meshes is known to "\ "not work properly with non-NVIDIA GPUs. Please "\ "consider triangulating your mesh:\n"\ "\t`.extract_geometry().triangulate()`" if not isinstance(mesh, pyvista.PolyData) or not mesh.is_all_triangles(): logging.warning(message) area_picker.AddObserver(vtk.vtkCommand.EndPickEvent, visible_pick_call_back) self.enable_rubber_band_style() self.iren.SetPicker(area_picker) # Now add text about cell-selection if show_message: if show_message is True: show_message = "Press R to toggle selection tool" if not through: show_message += "\nPress P to pick a single cell under the mouse" self.add_text(str(show_message), font_size=font_size, name='_cell_picking_message') if start: self._style.StartSelect() return