Exemple #1
0
    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)
Exemple #2
0
 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)
Exemple #3
0
    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)
Exemple #4
0
    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
Exemple #5
0
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()
Exemple #6
0
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()
Exemple #7
0
    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
Exemple #8
0
    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