Help converting Picking cxx example to python

Hello, I am attempting to convert the CellPicking Cxx example to Python but it is not quite working. I think it is something simple yet I am missing it. Below is the python code that I have currently. It runs but clicking the mouse does not work as yet - nothing happens.

Cxx example: https://kitware.github.io/vtk-examples/site/Cxx/Picking/CellPicking/

#!/usr/bin/env python

import vtk
import math

# Catch mouse events
class MouseInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
    def __init__(self):
        self.Data = vtk.vtkPolyData()
        self.selectedMapper = vtk.vtkDataSetMapper()
        self.selectedActor = vtk.vtkActor()

    def OnLeftButtonDown(self, parent=None):
        colors = vtk.vtkNameColors

        # Get the location of the click (in window coordinates)
        pos = self.GetInteractor().GetEventPosition()

        picker = vtk.vtkCellPicker()
        picker.SetTolerance(0.0005)

        # Pick from this location.
        picker.Pick(pos[0], pos[1], 0, self.GetDefaultRenderer())

        worldPosition = picker.GetPickPosition()
        print(f"Cell id is: {picker.GetCellId()}")

        if picker.GetCellId() != -1:
            print(f"Pick position is: {worldPosition[0]}, {worldPosition[1]}, {worldPosition[2]}")

            ids = vtk.vtkIdTypeArray
            ids.SetNumberOfComponents(1)
            ids.InsertNextValue(picker.GetCellId())

            selectionNode = vtk.vtkSelectionNode()
            selectionNode.SetFieldType(vtk.vtkSelectionNode.CELL)
            selectionNode.SetContentType(vtk.vtkSelectionNode.INDICES)
            selectionNode.SetSelectionList(ids)

            selection = vtk.vtkSelection()
            selection.AddNode(selectionNode)

            extractSelection = vtk.vtkExtractSelection
            extractSelection.SetInputData(0, self.Data)
            extractSelection.SetInputData(1, selection)
            extractSelection.Update()

            # In selection
            selected = vtk.vtkUnstructuredGrid()
            selected.ShallowCopy(extractSelection.GetOutput())

            print(f"There are  {selected.GetNumberOfPoints()}  points in the selection.")
            print(f"There are  {selected.GetNumberOfCells()}  points in the selection.")

            self.selectedMapper.SetInputData(selected)
            self.selectedActor.SetMapper(self.selectedMapper)
            self.selectedActor.GetProperty().EdgeVisibilityOn()
            self.selectedActor.GetProperty().SetColor(colors.GetColor3d("Red"))

            self.selectedActor.GetProperty().SetLineWidth(3)

            self.Interactor.GetRenderWindow().GetRenderers().GetFirstRenderer().AddActor(self.selectedActor)

        # Forward events
        vtk.vtkInteractorStyleTrackballCamera.OnLeftButtonDown()

def main():
    colors = vtk.vtkNamedColors()

    planeSource = vtk.vtkPlaneSource()
    planeSource.Update()

    triangleFilter = vtk.vtkTriangleFilter()
    triangleFilter.SetInputConnection(planeSource.GetOutputPort())
    triangleFilter.Update()

    mapper = vtk.vtkPolyDataMapper()
    mapper.SetInputConnection(triangleFilter.GetOutputPort())

    actor = vtk.vtkActor()
    actor.GetProperty().SetColor(colors.GetColor3d("Green"))
    actor.SetMapper(mapper)

    renderer = vtk.vtkRenderer()
    renderWindow = vtk.vtkRenderWindow()
    renderWindow.AddRenderer(renderer)
    renderWindow.SetWindowName("CellPicking")

    renderWindowInteractor = vtk.vtkRenderWindowInteractor()
    renderWindowInteractor.SetRenderWindow(renderWindow)
    renderWindowInteractor.Initialize()

    # Set the custom stype to use for interaction.
    style = MouseInteractorStyle()
    style.SetDefaultRenderer(renderer)
    style.Data = triangleFilter.GetOutput()

    renderWindowInteractor.SetInteractorStyle(style)

    renderer.AddActor(actor)

    renderer.ResetCamera()

    renderer.SetBackground(colors.GetColor3d("Blue"))

    renderWindow.Render()
    renderWindowInteractor.Start()

if __name__ == '__main__':
    main()

Hi,

Here’s a Python example that came up in Google: https://python.hotexamples.com/examples/vtk/-/vtkCellPicker/python-vtkcellpicker-function-examples.html I assume this is a working example. Here’s another one: https://programtalk.com/python-examples/vtk.vtkCellPicker/

regards,

Paulo

You’re nearly there your class has lots of errors, here is the fixed up class:

# Catch mouse events.
class MouseInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
    def __init__(self, data):
        self.AddObserver("LeftButtonPressEvent", self.leftButtonPressEvent)
        self.Data = data
        self.selectedMapper = vtk.vtkDataSetMapper()
        self.selectedActor = vtk.vtkActor()

    def leftButtonPressEvent(self, obj, event):
        colors = vtk.vtkNamedColors()

        # Get the location of the click (in window coordinates)
        pos = self.GetInteractor().GetEventPosition()

        picker = vtk.vtkCellPicker()
        picker.SetTolerance(0.0005)

        # Pick from this location.
        picker.Pick(pos[0], pos[1], 0, self.GetDefaultRenderer())

        worldPosition = picker.GetPickPosition()
        print(f"Cell id is: {picker.GetCellId()}")

        if picker.GetCellId() != -1:
            print(f"Pick position is: {worldPosition[0]}, {worldPosition[1]}, {worldPosition[2]}")

            ids = vtk.vtkIdTypeArray()
            ids.SetNumberOfComponents(1)
            ids.InsertNextValue(picker.GetCellId())

            selectionNode = vtk.vtkSelectionNode()
            selectionNode.SetFieldType(vtk.vtkSelectionNode.CELL)
            selectionNode.SetContentType(vtk.vtkSelectionNode.INDICES)
            selectionNode.SetSelectionList(ids)

            selection = vtk.vtkSelection()
            selection.AddNode(selectionNode)

            extractSelection = vtk.vtkExtractSelection()
            extractSelection.SetInputData(0, self.Data)
            extractSelection.SetInputData(1, selection)
            extractSelection.Update()

            # In selection
            # selected = vtk.vtkPolyData()
            # selected.ShallowCopy(extractSelection.GetOutput())

            print(f"There are  {extractSelection.GetOutput().GetNumberOfPoints()}  points in the selection.")
            print(f"There are  {extractSelection.GetOutput().GetNumberOfCells()}  cells in the selection.")

            self.selectedMapper.SetInputData(extractSelection.GetOutput())
            self.selectedActor.SetMapper(self.selectedMapper)
            self.selectedActor.GetProperty().EdgeVisibilityOn()
            self.selectedActor.GetProperty().SetColor(colors.GetColor3d("Red"))

            self.selectedActor.GetProperty().SetLineWidth(3)

            self.GetInteractor().GetRenderWindow().GetRenderers().GetFirstRenderer().AddActor(self.selectedActor)

        # Forward events
        self.OnLeftButtonDown()

ten in main():

    # Add the custom style.
    style = MouseInteractorStyle(triangleFilter.GetOutput())
    style.SetDefaultRenderer(renderer)
    renderWindowInteractor.SetInteractorStyle(style)

I’m happy to add this with a few more modifications to the VTK Examples.

Thanks for your help. Sorry about the obvious errors in my OnLeftButtonDown method… I should have checked that much closer. I prefer the style that you used in creating a new method rather than redefining OnLeftButtonDown as in the C++ example. It then makes it clearer that you need to add the method with AddObserver. I am assuming that the reason that overriding the OnLeftButtonDown method in Python does not work is because of the way that Python handles references or more importantly when if does not use references and the way that vtk store its information about added observers.

I think that it would be great to have more Python examples. Much appreciated.

P.S. I do find this example a little odd in that it seems to be adding layers of actors onto the scene and if you pick each side of the square a few times the coloring of the layering becomes odd (i.e. you being to see green from the original cell below).

The Cxx version has been updated (mainly less garish colours) and there is now a Python version.

It is a little odd, not sure why this was done, it is a very old example.

This happens when the orientation of the object changes. Not sure why.