vtkCellPicker can not pick vtk.vtkActor

There is vtk.vtkImageActor and vtk.vtkActor in the vtkRenderer. I want to pick the actor in the mouse move event with vtkCellPicker. I can pick vtkImageActor, but it is failed to pick vtkActor. The completed code is:

import vtk
from vtk.util.numpy_support import vtk_to_numpy, numpy_to_vtk
import numpy as np

def numpyToVTK(data):
    if len(data.shape) == 2:
        data = data[:, :, np.newaxis]
    flat_data_array = data.transpose(2,1,0).flatten()
    vtk_data = numpy_to_vtk(num_array=flat_data_array, deep=True, array_type=vtk.VTK_FLOAT)
    shape = data.shape

    img = vtk.vtkImageData()
    img.GetPointData().SetScalars(vtk_data)
    img.SetDimensions(shape[0], shape[1], shape[2])
    return img

img = np.zeros(shape=[512, 512])

img[0:256, 0:256] = 0
img[0:256, 256:] = 64
img[256:, 0:256] = 128
img[256:, 256:] = 255

img = numpyToVTK(img)

imgActor = vtk.vtkImageActor()
imgActor.SetInputData(img)


lineSource = vtk.vtkLineSource()
lineSource.SetPoint1(0, 0, 0)
lineSource.SetPoint2(512, 512, 0)
lineSource.Update()
lineMapper = vtk.vtkPolyDataMapper()
lineMapper.SetInputData(lineSource.GetOutput())
lineActor = vtk.vtkActor()
lineActor.SetMapper(lineMapper)
lineActor.GetProperty().SetColor(255, 0, 0)
lineActor.GetProperty().SetLineWidth(5)
# lineActor.GetProperty().EdgeVisibilityOn()     ############################ it make difference

renderer = vtk.vtkRenderer()
renderer.AddActor(imgActor)
renderer.AddActor(lineActor)
renderer.SetBackground(0.4, 0.5, 0.6)

renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindow.Render()

def mousemove(iren, even):
    pos = iren.GetEventPosition()
    picker = vtk.vtkCellPicker()
    picker.Pick(pos[0], pos[1], 0, renderer)
    actor = picker.GetProp3D()
    # print(pos)
    if isinstance(actor, vtk.vtkImageActor):
        print('Picture actor')
    elif isinstance(actor, vtk.vtkActor):
        print("line actor")
    else:
        print('none actor')

renderWindowInteractor = vtk.vtkRenderWindowInteractor()
renderWindowInteractor.AddObserver("MouseMoveEvent", mousemove)

style = vtk.vtkInteractorStyleImage()
renderWindowInteractor.SetInteractorStyle(style)
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.Initialize()
renderWindowInteractor.Start()

In thte mousemove function, I print the picked actor. But it only print Picture actor. Is there anything wrong with vtkCellPicker?


def mousemove(iren, even):
    pos = iren.GetEventPosition()
    picker = vtk.vtkCellPicker()
    picker.Pick(pos[0], pos[1], 0, renderer)
    actor = picker.GetProp3D()
    # print(pos)
    if isinstance(actor, vtk.vtkImageActor):
        print('Picture actor')
    elif isinstance(actor, vtk.vtkActor):
        print("line actor")
    else:
        print('none actor')

Hello, Zhang,

I guess you need a vtkPropPicker instead: https://vtk.org/doc/nightly/html/classvtkPropPicker.html.

regards,

Paulo

@Paulo_Carvalho , Thank you very much for the suggestion, and vtkPropPicker works.

But, why vtkCellPicker.GetProp3D do not return the correct result? If vtkCellPicker.GetProp3D do not return the picked prop, what is the output of vtkCellPicker.GetProp3D?

From here: VTK: vtkCellPicker Class Reference

If it is On, then the clipping planes become pickable objects, even though they are usually invisible. This means that if the pick ray intersects a clipping plane before it hits anything else, the pick will stop at that clipping plane. The GetProp3D() and GetMapper() methods will return the Prop3D and Mapper that the clipping plane belongs to. The GetClippingPlaneId() method will return the index of the clipping plane so that you can retrieve it from the mapper, or -1 if no clipping plane was picked.

(emphasis added)

This implies that no actor will be returned if there are no clipping planes.

1 Like

In my understanding, it means:

    if PickClippingPlanes = True
        if there are clipping planes
            the pick ray will stop at the clipping plane (belong to a prop) , and vtkCellPicker would return this prop
       if there is no clipping planes
            the pick ray will stop at a prop, and vtkCellPicker would return this prop
    if PickClippingPlanes = False
        the pick ray will stop at a prop, and vtkCellPicker would return this prop

In the source code of vtkCellPicker (Line 287~310):

  double tMin = VTK_DOUBLE_MAX;
  double t1 = 0.0;
  double t2 = 1.0;

  // Clip the ray with the mapper's ClippingPlanes and adjust t1, t2.
  // This limits the pick search to the inside of the clipped region.
  int clippingPlaneId = -1;
  if (m &&
    !this->ClipLineWithPlanes(m, this->Transform->GetMatrix(), p1, p2, t1, t2, clippingPlaneId))
  {
    return VTK_DOUBLE_MAX;
  }

  // Initialize the pick position to the frontmost clipping plane
  if (this->PickClippingPlanes && clippingPlaneId >= 0)
  {
    tMin = t1;
  }

  // HyperTreeGrid
  else if ((htgMapper = vtkAbstractHyperTreeGridMapper::SafeDownCast(m)))
  {
    tMin = this->IntersectHyperTreeGridWithLine(p1, p2, t1, t2, htgMapper);
  }
  ...

Code 1. The following code only calculate the position of ClippingPlanes.

  if (m &&
    !this->ClipLineWithPlanes(m, this->Transform->GetMatrix(), p1, p2, t1, t2, clippingPlaneId))
  {
    return VTK_DOUBLE_MAX;
  }

Code 2. The following code only initialize the pick position.

  // Initialize the pick position to the frontmost clipping plane
  if (this->PickClippingPlanes && clippingPlaneId >= 0)
  {
    tMin = t1;
  }

If there is no clipping planes, this->ClipLineWithPlanes would return 1, then Code 2 is executed.
In Code 2:

if this->PickClippingPlanes = False, the code would be continue executed.
if this->PickClippingPlanes = True, only tMin is updated and the code would be continue executed. 

Thus, I think that no clipping plane may not result in the wrong result of vtkCellPicker. Is that correct?

Moreover, if I want to use vtkCellPicker to pick correct actor (because I want to use the SetTolerance method), how should I modify my code? I use PickClippingPlanesOff or PickClippingPlanesOn in my code, but it don’t make any change:

def mousemove(iren, even):
    pos = iren.GetEventPosition()
    picker = vtk.vtkCellPicker()
    picker.PickClippingPlanesOff()  ################################### change 
    picker.Pick(pos[0], pos[1], 0, renderer)
    actor = picker.GetProp3D()
    # print(pos)
    if isinstance(actor, vtk.vtkImageActor):
        print('Picture actor')
    elif isinstance(actor, vtk.vtkActor):
        print("line actor")
    else:
        print('none actor')

Any suggestion is appreciated~~~

Hello,

I think your question has already been answered. Please, mark the answer as solution so others can benefit from it. If you have further questions, please, start new ones.

thanks,

Paulo

Actually, my question is “vtkCellPicker can not pick vtk.vtkActor”. Even vtkPropPicker solve my problem, I still feel confuzed why vtkCellPicker can not correctly pick vtk.vtkActor.