"""Custom Interactor Style."""importnumpyasnpimportvtkclassEvent(object):"""Event class."""def__init__(self):self.position=Noneself.name=Noneself.key=Noneself.alt_key=Noneself.shift_key=Noneself.ctrl_key=Noneself._abort_flag=None@propertydefabort_flag(self):"""Abort."""returnself._abort_flagdefupdate(self,event_name,interactor):"""Update current event information."""self.name=event_nameself.position=np.asarray(interactor.GetEventPosition())self.key=interactor.GetKeySym()self.alt_key=bool(interactor.GetAltKey())self.shift_key=bool(interactor.GetShiftKey())self.ctrl_key=bool(interactor.GetControlKey())self._abort_flag=False# Reset abort flagdefabort(self):"""Abort the event i.e. do not propagate it any further."""self._abort_flag=Truedefreset(self):"""Done with the current event. Reset the attributes."""self.position=Noneself.name=Noneself.key=Noneself._abort_flag=False
[docs]classCustomInteractorStyle(vtk.vtkInteractorStyleUser):"""Manipulate the camera and interact with objects in the scene. This interactor style allows the user to interactively manipulate (pan, rotate and zoom) the camera. It also allows the user to interact (click, scroll, etc.) with objects in the scene. Several events handling methods from :class:`vtkInteractorStyleUser` have been overloaded to allow the propagation of the events to the objects the user is interacting with. In summary, while interacting with the scene, the mouse events are as follows:: - Left mouse button: rotates the camera - Right mouse button: dollys the camera - Mouse wheel: dollys the camera - Middle mouse button: pans the camera """
[docs]def__init__(self):"""Init."""# Interactor responsible for moving the camera.self.trackball_camera=vtk.vtkInteractorStyleTrackballCamera()# Interactor responsible for moving/rotating a selected actor.self.trackball_actor=vtk.vtkInteractorStyleTrackballActor()# Interactor responsible for panning/zooming the camera.self.image=vtk.vtkInteractorStyleImage()# The picker allows us to know which object/actor is under the mouse.self.picker=vtk.vtkPropPicker()self.chosen_element=Noneself.event=Event()# Define some interaction statesself.left_button_down=Falseself.right_button_down=Falseself.middle_button_down=Falseself.active_props=set()self.selected_props={"left_button":set(),"right_button":set(),"middle_button":set()}
[docs]defget_prop_at_event_position(self):"""Return the prop that lays at the event position."""# TODO: return a list of items (i.e. each level of the assembly path).event_pos=self.GetInteractor().GetEventPosition()self.picker.Pick(event_pos[0],event_pos[1],0,self.GetCurrentRenderer())path=self.picker.GetPath()ifpathisNone:returnNonenode=path.GetLastNode()prop=node.GetViewProp()returnprop
[docs]defpropagate_event(self,evt,*props):forpropinprops:# Propagate event to the prop.prop.InvokeEvent(evt)ifself.event.abort_flag:return
[docs]defon_mouse_move(self,_obj,evt):"""On mouse move."""# Only propagate events to active or selected props.self.propagate_event(evt,*(self.active_props|self.selected_props["left_button"]|self.selected_props["right_button"]|self.selected_props["middle_button"]))self.trackball_camera.OnMouseMove()
[docs]defon_mouse_wheel_forward(self,_obj,evt):"""On mouse wheel forward."""# First, propagate mouse wheel event to underneath prop.prop=self.get_prop_at_event_position()ifpropisnotNone:self.propagate_event(evt,prop)# Then, to the active props.ifnotself.event.abort_flag:self.propagate_event(evt,*self.active_props)# Finally, to the default interactor.ifnotself.event.abort_flag:self.trackball_camera.OnMouseWheelForward()
[docs]defon_mouse_wheel_backward(self,_obj,evt):"""On mouse wheel backward."""# First, propagate mouse wheel event to underneath prop.prop=self.get_prop_at_event_position()ifpropisnotNone:self.propagate_event(evt,prop)# Then, to the active props.ifnotself.event.abort_flag:self.propagate_event(evt,*self.active_props)# Finally, to the default interactor.ifnotself.event.abort_flag:self.trackball_camera.OnMouseWheelBackward()
[docs]defSetInteractor(self,interactor):"""Define new interactor."""# Internally, `InteractorStyle` objects need a handle to a# `vtkWindowInteractor` object and this is done via `SetInteractor`.# However, this has the side effect of adding directly all their# observers to the `interactor`!self.trackball_actor.SetInteractor(interactor)self.image.SetInteractor(interactor)self.trackball_camera.SetInteractor(interactor)# Remove all observers *most likely* (cannot guarantee that the# interactor did not already have these observers) added by# `vtkInteractorStyleTrackballCamera`, i.e. our `trackball_camera`.## Note: Be sure that no observer has been manually added to the# `interactor` before setting the InteractorStyle.interactor.RemoveObservers("TimerEvent")interactor.RemoveObservers("EnterEvent")interactor.RemoveObservers("LeaveEvent")interactor.RemoveObservers("ExposeEvent")interactor.RemoveObservers("ConfigureEvent")interactor.RemoveObservers("CharEvent")interactor.RemoveObservers("KeyPressEvent")interactor.RemoveObservers("KeyReleaseEvent")interactor.RemoveObservers("MouseMoveEvent")interactor.RemoveObservers("LeftButtonPressEvent")interactor.RemoveObservers("RightButtonPressEvent")interactor.RemoveObservers("MiddleButtonPressEvent")interactor.RemoveObservers("LeftButtonReleaseEvent")interactor.RemoveObservers("RightButtonReleaseEvent")interactor.RemoveObservers("MiddleButtonReleaseEvent")interactor.RemoveObservers("MouseWheelForwardEvent")interactor.RemoveObservers("MouseWheelBackwardEvent")# This class is a `vtkClass` (instead of `object`), so `super()`# cannot be used. Also the method `SetInteractor` is not overridden in# `vtkInteractorStyleUser` so we have to call directly the one from# `vtkInteractorStyle`. In addition to setting the interactor, the# following line adds the necessary hooks to listen to this# observers instances.vtk.vtkInteractorStyle.SetInteractor(self,interactor)# Keyboard events.self.AddObserver("CharEvent",self._process_event)self.AddObserver("KeyPressEvent",self._process_event)self.AddObserver("KeyReleaseEvent",self._process_event)# Mouse events.self.AddObserver("MouseMoveEvent",self._process_event)self.AddObserver("LeftButtonPressEvent",self._process_event)self.AddObserver("LeftButtonReleaseEvent",self._process_event)self.AddObserver("RightButtonPressEvent",self._process_event)self.AddObserver("RightButtonReleaseEvent",self._process_event)self.AddObserver("MiddleButtonPressEvent",self._process_event)self.AddObserver("MiddleButtonReleaseEvent",self._process_event)# Windows and special events.# TODO: we ever find them useful we could support them.# self.AddObserver("TimerEvent", self._process_event)# self.AddObserver("EnterEvent", self._process_event)# self.AddObserver("LeaveEvent", self._process_event)# self.AddObserver("ExposeEvent", self._process_event)# self.AddObserver("ConfigureEvent", self._process_event)# These observers need to be added directly to the interactor because# `vtkInteractorStyleUser` does not support wheel events prior 7.1. See# https://github.com/Kitware/VTK/commit/373258ed21f0915c425eddb996ce6ac13404be28interactor.AddObserver("MouseWheelForwardEvent",self._process_event)interactor.AddObserver("MouseWheelBackwardEvent",self._process_event)
[docs]defforce_render(self):"""Causes the scene to refresh."""self.GetInteractor().GetRenderWindow().Render()
[docs]defadd_callback(self,prop,event_type,callback,priority=0,args=[]):"""Add a callback associated to a specific event for a VTK prop. Parameters ---------- prop : vtkProp event_type : event code callback : function priority : int """def_callback(_obj,event_name):# Update event information.interactor_=self.GetInteractor()ifinteractor_isnotNone:self.event.update(event_name,interactor_)callback(self,prop,*args)else:print('interactor is none')print('event name is',event_name)prop.AddObserver(event_type,_callback,priority)