Pick and highlight glyphs.

Firstly, I’m still fairly new at VTK, I’m doing the best I can :slight_smile:

I have a scene illustrating points as glyphs. I want to be able to pick and highlight each glyph individually.
I have implemented the interactor style highlighting actors, which works perfectly. However, this will select all glyphs at once.

I’m showing the points as glyphs since I normally have more than 10,000 points. And creating an individual actor for each point makes interaction impossible (simple operates to slow).

I looked into a vtkCellPicker, and I’m getting something, but it is definitely not correct, and I was hoping someone could assist me.

What I have:

import vtk
import numpy as np  


class InteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
    def __init__(self, glyphs, renderer):
        self.glyphs = glyphs
        self.renderer = renderer
        self.AddObserver("LeftButtonPressEvent", self._left_button_press_event)

    def _left_button_press_event(self, obj, event):
        click_pos = self.GetInteractor().GetEventPosition()

        cell_picker = vtk.vtkCellPicker()
        cell_picker.Pick(click_pos[0], click_pos[1], 0, self.GetDefaultRenderer())

        input_ids = self.glyphs.GetOutput().GetPointData().GetArray("InputPointIds")
        if input_ids:
            cell = self.glyphs.GetOutput().GetCell(cell_picker.GetCellId())
            if cell and cell.GetNumberOfPoints() > 0:
                input_id = cell.GetPointId(0)
                selected_id = input_ids.GetTuple1(input_id)
                if selected_id >= 0:
                    highlight_sphere = vtk.vtkSphereSource() 
                    highlight_sphere.SetRadius(2)
                    highlight_sphere.SetThetaResolution(8)
                    highlight_sphere.SetPhiResolution(8)
                    highlight_sphere.SetCenter(self.glyphs.GetOutput().GetPoint(int(selected_id)))
                    mapper = vtk.vtkPolyDataMapper()
                    mapper.SetInputConnection(highlight_sphere.GetOutputPort())

                    highlight_actor = vtk.vtkActor()
                    highlight_actor.SetMapper(mapper)
                    self.renderer.AddActor(highlight_actor)
                    print("Pick!")
        self.OnLeftButtonDown()
        return


renderer = vtk.vtkRenderer()
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)

sphere = vtk.vtkSphereSource()
sphere.SetRadius(1)
sphere.SetThetaResolution(8)
sphere.SetPhiResolution(8)

points = vtk.vtkPoints()
p_data = vtk.vtkPolyData()
for i in range(20):
    points.InsertNextPoint(20 * np.random.random(3))

p_data.SetPoints(points)

glyph = vtk.vtkGlyph3D()
glyph.GeneratePointIdsOn()
glyph.SetInputData(p_data)
glyph.SetSourceConnection(sphere.GetOutputPort())
glyph.Update()

mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(glyph.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer.AddActor(actor)
style = InteractorStyle(glyph, renderer)
style.SetDefaultRenderer(renderer)
interactor.SetInteractorStyle(style)

render_window.Render()
interactor.Start()

I add a sphere when something is clicked, at the found coordinates. This shows that the returned coordinates are not those I expected.

So, is this the wrong way to go about this issue?
If the CellPicker is the correct way, how can I extract the glyph and recolor it?

Hi
just change

highlight_sphere.SetCenter(self.glyphs.GetOutput().GetPoint(int(selected_id)))

to

highlight_sphere.SetCenter(self.glyphs.GetInput().GetPoint(int(selected_id)))

I would like to reply an answer myself, for possible future readers.

I succeeded in picking and highlighting specific glyphs.

It still very basic, and needs refinement, but assuming the glyphs are colored by a scalar, from an array called ‘col’

class InteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
    def __init__(self, glyphs, renderer):
        self.glyphs = glyphs
        self.renderer = renderer
        self.AddObserver("LeftButtonPressEvent", self._left_button_press_event)
        self._new_glyph_index = None
        self._old_glyph_index = None
        self._new_glyph_value = None    
        self._old_glyph_value = None

    def _left_button_press_event(self, obj, event):
        click_pos = self.GetInteractor().GetEventPosition()

        cell_picker = vtk.vtkCellPicker()
        cell_picker.Pick(click_pos[0], click_pos[1], 0, self.GetDefaultRenderer())
        if self._new_glyph_value:
            if self._old_glyph_value:
                self.data.GetPointData().GetArray('col').SetValue(self._old_glyph_index, self._old_glyph_value)
        self._new_glyph_index = self.glyph_data.GetOutput().GetPointData().GetArray("InputPointIds").GetValue(cell_picker.GetPointId())
        self._new_glyph_value = self.data.GetPointData().GetArray('col').GetTuple1(self._new_glyph_index)
        self.data.GetPointData().GetArray('col').SetValue(self._new_glyph_index, **number**) 
        self._old_glyph_index = self._new_glyph_index
        self._old_glyph_value = self._new_glyph_value

        self.data.Modified()

This interactor style did what I needed, The number needs to be replaced by a scalar value providing the desired color.

2 Likes

It worked, but I found a different approach instead. Thanks for the answer though!

Hi Martin, can you tell me how were your another approach ? I have to make the same task, but I didn’t succeeded, and I intend to try in another way. Thank you.

I apologize for the confusion. The “other” approach is the one marked with the solution. It is a different approach than the one suggested by Marcomusy.