from collections.abc import Sequence
import numpy as np
from fury.lib import (
CellPicker,
DataObject,
HardwareSelector,
PointPicker,
PropPicker,
WorldPointPicker,
numpy_support,
)
[docs]
class PickingManager:
"""Picking Manager helps with picking 3D objects."""
[docs]
def __init__(self, vertices=True, faces=True, actors=True, world_coords=True):
"""Initialize Picking Manager.
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'] = PointPicker()
if faces:
self.pickers['faces'] = CellPicker()
if actors:
self.pickers['actors'] = PropPicker()
if world_coords:
self.pickers['world_coords'] = WorldPointPicker()
[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):
"""Return 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:
"""Selection Manager helps with picking many objects simultaneously."""
[docs]
def __init__(self, select='faces'):
"""Initialize Selection Manager.
Parameters
----------
select : 'faces'
Options are 'faces', 'vertices' or 'actors'.
Default 'faces'.
Methods
-------
select()
pick()
"""
self.hsel = HardwareSelector()
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(DataObject.FIELD_ASSOCIATION_CELLS)
elif select == 'points' or select == 'vertices':
self.hsel.SetFieldAssociation(DataObject.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):
"""Return 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()