Pick vtkActor from vtkPropAssembly

Hello everyone,

I’m trying to pick an actor from an assembly, but I’m always getting the first actor in the assembly as the picked actor. My understanding is that that I should get the picked actor from the path returned by the picker (vtkPropPicker to be more precise). This path should contain 2 nodes: the assembly would be in the first node and the picked actor would be the in second node (a call to GetViewProp() is needed to get the actual actor). Did I understood it correctly?

I’ve modified HighlightWithSilhouette example to test this with no luck:

# !/usr/bin/env python

import vtk


def get_program_parameters():
    import argparse
    description = 'Highlighting a selected object with a silhouette.'
    epilogue = '''
Click on the object to highlight it.
The selected object is highlighted with a silhouette.
    '''
    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
                                     formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument('numberOfSpheres', nargs='?', type=int, default=10,
                        help='The number of spheres, default is 10.')
    args = parser.parse_args()
    return args.numberOfSpheres


class MouseInteractorHighLightActor(vtk.vtkInteractorStyleTrackballCamera):

    def __init__(self, silhouette=None, silhouetteActor=None):
        self.AddObserver("LeftButtonPressEvent", self.onLeftButtonDown)
        self.LastPickedActor = None
        self.Silhouette = silhouette
        self.SilhouetteActor = silhouetteActor

    def onLeftButtonDown(self, obj, event):
        clickPos = self.GetInteractor().GetEventPosition()

        #  Pick from this location.
        picker = vtk.vtkPropPicker()
        picker.Pick(clickPos[0], clickPos[1], 0, self.GetDefaultRenderer())

        print("---------- New picking ------------------")
        print("Path: %s", picker.GetPath())
        print("Path 1: %s", picker.GetPath().GetItemAsObject(1).GetViewProp())
        print("-----------------------------------------")

        self.LastPickedActor = picker.GetPath().GetItemAsObject(1).GetViewProp() #picker.GetActor()

        # If we picked something before, remove the silhouette actor and
        # generate a new one.
        if self.LastPickedActor:
            self.GetDefaultRenderer().RemoveActor(self.SilhouetteActor)

            # Highlight the picked actor by generating a silhouette
            self.Silhouette.SetInputData(self.LastPickedActor.GetMapper().GetInput())
            self.GetDefaultRenderer().AddActor(self.SilhouetteActor)

        #  Forward events
        self.OnLeftButtonDown()
        return

    def SetSilhouette(self, silhouette):
        self.Silhouette = silhouette

    def SetSilhouetteActor(self, silhouetteActor):
        self.SilhouetteActor = silhouetteActor


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

    # A renderer and render window
    renderer = vtk.vtkRenderer()
    renderer.SetBackground(colors.GetColor3d('SteelBlue'))

    renderWindow = vtk.vtkRenderWindow()
    renderWindow.SetSize(640, 480)
    renderWindow.AddRenderer(renderer)

    # An interactor
    interactor = vtk.vtkRenderWindowInteractor()
    interactor.SetRenderWindow(renderWindow)

    # Assembly
    assembly = vtk.vtkPropAssembly()

    # Add spheres to play with
    for i in range(numberOfSpheres):
        source = vtk.vtkSphereSource()

        # random position and radius
        x = vtk.vtkMath.Random(-5, 5)
        y = vtk.vtkMath.Random(-5, 5)
        z = vtk.vtkMath.Random(-5, 5)
        radius = vtk.vtkMath.Random(.5, 1.0)

        source.SetRadius(radius)
        source.SetCenter(x, y, z)
        source.SetPhiResolution(11)
        source.SetThetaResolution(21)

        mapper = vtk.vtkPolyDataMapper()
        mapper.SetInputConnection(source.GetOutputPort())
        actor = vtk.vtkActor()
        actor.SetMapper(mapper)

        r = vtk.vtkMath.Random(.4, 1.0)
        g = vtk.vtkMath.Random(.4, 1.0)
        b = vtk.vtkMath.Random(.4, 1.0)
        actor.GetProperty().SetDiffuseColor(r, g, b)
        actor.GetProperty().SetDiffuse(.8)
        actor.GetProperty().SetSpecular(.5)
        actor.GetProperty().SetSpecularColor(colors.GetColor3d('White'))
        actor.GetProperty().SetSpecularPower(30.0)

        assembly.AddPart(actor)


    # Add assembly to renderer
    renderer.AddActor(assembly)

    # Render and interact
    renderWindow.Render()

    # Create the silhouette pipeline, the input data will be set in the
    # interactor
    silhouette = vtk.vtkPolyDataSilhouette()
    silhouette.SetCamera(renderer.GetActiveCamera())

    # Create mapper and actor for silhouette
    silhouetteMapper = vtk.vtkPolyDataMapper()
    silhouetteMapper.SetInputConnection(silhouette.GetOutputPort())

    silhouetteActor = vtk.vtkActor()
    silhouetteActor.SetMapper(silhouetteMapper)
    silhouetteActor.GetProperty().SetColor(colors.GetColor3d("Tomato"))
    silhouetteActor.GetProperty().SetLineWidth(5)

    # Set the custom type to use for interaction.
    style = MouseInteractorHighLightActor(silhouette, silhouetteActor)
    style.SetDefaultRenderer(renderer)

    # Start
    interactor.Initialize()
    interactor.SetInteractorStyle(style)
    renderWindow.SetWindowName('HighlightWithSilhouette')
    renderWindow.Render()

    interactor.Start()


if __name__ == "__main__":
    main()

As you can see in the above code, I add the actors to the assembly. And then add the assembly to the renderer. In the picking part, I assign the actor in last node of the path to LastPickedActor (to highligh it). I also print the path and the actor of the last element of the path, so I can see that the path has 2 elements and the memory position of the picked actor (I always get the same actor with the same memory position).

Any help will be apreciated :slight_smile:

Thanks!

T,

hey,

have you find any answer on this i also need this.