from collections.abc import Sequence
import vtk
import numpy as np
from fury.utils import numpy_support
[docs]class PickingManager:
[docs] def __init__(self, vertices=True, faces=True, actors=True,
world_coords=True):
""" Picking Manager helps with picking 3D objects
Parameters
-----------
vertices : bool
If True allows to pick vertex indices.
faces : bool
If True allows to pick face indices.
actors : bool
If True allows to pick actor indices.
world_coords : bool
If True allows to pick xyz position in world coordinates.
"""
self.pickers = {}
if vertices:
self.pickers['vertices'] = vtk.vtkPointPicker()
if faces:
self.pickers['faces'] = vtk.vtkCellPicker()
if actors:
self.pickers['actors'] = vtk.vtkPropPicker()
if world_coords:
self.pickers['world_coords'] = vtk.vtkWorldPointPicker()
[docs] def pick(self, disp_xy, sc):
""" Pick on display coordinates
Parameters
----------
disp_xy : tuple
Display coordinates x, y.
sc : Scene
"""
x, y = disp_xy
z = 0
info = {'vertex': None, 'face': None, 'actor': None, 'xyz': None}
keys = self.pickers.keys()
if 'vertices' in keys:
self.pickers['vertices'].Pick(x, y, z, sc)
info['vertex'] = self.pickers['vertices'].GetPointId()
if 'faces' in keys:
self.pickers['faces'].Pick(x, y, z, sc)
info['vertex'] = self.pickers['faces'].GetPointId()
info['face'] = self.pickers['faces'].GetCellId()
if 'actors' in keys:
self.pickers['actors'].Pick(x, y, z, sc)
info['actor'] = self.pickers['actors'].GetViewProp()
if 'world_coords' in keys:
self.pickers['world_coords'].Pick(x, y, z, sc)
info['xyz'] = self.pickers['world_coords'].GetPickPosition()
return info
[docs] def event_position(self, iren):
""" Returns event display position from interactor
Parameters
----------
iren : interactor
The interactor object can be retrieved for example
using providing ShowManager's iren attribute.
"""
return iren.GetEventPosition()
[docs] def pickable_on(self, actors):
""" Choose which actors can be picked
Parameters
----------
actors : actor or sequence of actors
"""
if isinstance(actors, Sequence):
for a in actors:
a.PickableOn()
else:
actors.PickableOn()
[docs] def pickable_off(self, actors):
""" Choose which actors cannot be picked
Parameters
----------
actors : actor or sequence of actors
"""
if isinstance(actors, Sequence):
for a in actors:
a.PickableOff()
else:
actors.PickableOff()
[docs]class SelectionManager:
[docs] def __init__(self, select='faces'):
""" Selection Manager helps with picking many
objects simultaneously
Parameters
-----------
select : 'faces'
Options are 'faces', 'vertices' or 'actors'.
Default 'faces'.
Methods
-------
select()
pick()
"""
self.hsel = vtk.vtkHardwareSelector()
self.update_selection_type(select)
[docs] def update_selection_type(self, select):
""" Update selection type
Parameters
-----------
select : 'faces'
Options are 'faces', 'vertices' or 'actors'.
Default 'faces'.
"""
self.selected_type = select.lower()
if select == 'faces' or select == 'edges':
self.hsel.SetFieldAssociation(
vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS)
elif select == 'points' or select == 'vertices':
self.hsel.SetFieldAssociation(
vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS)
elif select == 'actors':
self.hsel.SetActorPassOnly(True)
else:
raise ValueError('Unkown parameter select')
[docs] def pick(self, disp_xy, sc):
""" Pick on display coordinates returns a single object
Parameters
----------
disp_xy : tuple
Display coordinates x, y.
sc : Scene
"""
return self.select(disp_xy, sc, area=0)[0]
[docs] def select(self, disp_xy, sc, area=0):
""" Select multiple objects using display coordinates
Parameters
----------
disp_xy : tuple
Display coordinates x, y.
sc : Scene
area : int or 2d tuple of ints
Selection area around x, y coords.
"""
info_plus = {}
self.hsel.SetRenderer(sc)
if isinstance(area, int):
picking_area = area, area
else:
picking_area = area
try:
self.hsel.SetArea(disp_xy[0] - picking_area[0],
disp_xy[1] - picking_area[1],
disp_xy[0] + picking_area[0],
disp_xy[1] + picking_area[1])
res = self.hsel.Select()
except OverflowError:
return {0: {'node': None, 'vertex': None,
'face': None, 'actor': None}}
num_nodes = res.GetNumberOfNodes()
if num_nodes < 1:
sel_node = None
return {0: {'node': None, 'vertex': None,
'face': None, 'actor': None}}
else:
for i in range(num_nodes):
sel_node = res.GetNode(i)
info = {'node': None, 'vertex': None,
'face': None, 'actor': None}
if sel_node is not None:
selected_nodes = set(
np.floor(numpy_support.vtk_to_numpy(
sel_node.GetSelectionList())).astype(int))
info['node'] = sel_node
info['actor'] = \
sel_node.GetProperties().Get(sel_node.PROP())
if self.selected_type == 'faces':
info['face'] = list(selected_nodes)
if self.selected_type == 'vertex':
info['vertex'] = list(selected_nodes)
info_plus[i] = info
return info_plus
[docs] def event_position(self, iren):
""" Returns event display position from interactor
Parameters
----------
iren : interactor
The interactor object can be retrieved for example
using ShowManager's iren attribute.
"""
return iren.GetEventPosition()
[docs] def selectable_on(self, actors):
""" Choose which actors can be selected
Parameters
----------
actors : actor or sequence of actors
"""
if isinstance(actors, Sequence):
for a in actors:
a.PickableOn()
else:
actors.PickableOn()
[docs] def selectable_off(self, actors):
""" Choose which actors cannot be selected
Parameters
----------
actors : actor or sequence of actors
"""
if isinstance(actors, Sequence):
for a in actors:
a.PickableOff()
else:
actors.PickableOff()