class ManipulationManager(avango.script.Script): ### input fields sf_key_1 = avango.SFBool() sf_key_2 = avango.SFBool() sf_key_3 = avango.SFBool() ### internal fields sf_hand_mat = avango.gua.SFMatrix4() sf_dragging_trigger = avango.SFBool() # constructor def __init__(self): self.super(ManipulationManager).__init__() def my_constructor( self, PARENT_NODE=None, SCENE_ROOT=None, TARGET_LIST=[], ): ### external references ### self.SCENE_ROOT = SCENE_ROOT self.TARGET_LIST = TARGET_LIST ### variables ### self.dragging_technique = 0 self.dragged_objects_list = [] self.lf_hand_mat = avango.gua.make_identity_mat( ) # last frame hand matrix ## init hand geometry _loader = avango.gua.nodes.TriMeshLoader( ) # init trimesh loader to load external meshes self.hand_geometry = _loader.create_geometry_from_file( "hand_geometry", "data/objects/hand.obj", avango.gua.LoaderFlags.DEFAULTS) self.hand_geometry.Transform.value = \ avango.gua.make_rot_mat(45.0,1,0,0) * \ avango.gua.make_rot_mat(180.0,0,1,0) * \ avango.gua.make_scale_mat(0.06) self.hand_geometry.Material.value.set_uniform( "Color", avango.gua.Vec4(1.0, 0.86, 0.54, 1.0)) self.hand_geometry.Material.value.set_uniform("Emissivity", 0.9) self.hand_geometry.Material.value.set_uniform("Metalness", 0.1) self.hand_transform = avango.gua.nodes.TransformNode( Name="hand_transform") self.hand_transform.Children.value = [self.hand_geometry] PARENT_NODE.Children.value.append(self.hand_transform) self.hand_transform.Transform.connect_from(self.sf_hand_mat) ### init sub-classes ### self.mouseInput = MouseInput() self.mouseInput.my_constructor("gua-device-mouse") # init manipulation technique self.IPCManipulation = IsotonicPositionControlManipulation() self.IPCManipulation.my_constructor(self.mouseInput.mf_dof, self.mouseInput.mf_buttons) self.IPCManipulation.enable_manipulation(True) # init field connections self.sf_hand_mat.connect_from(self.IPCManipulation.sf_mat) self.sf_dragging_trigger.connect_from( self.IPCManipulation.sf_action_trigger) ## init keyboard sensor self.keyboard_sensor = avango.daemon.nodes.DeviceSensor( DeviceService=avango.daemon.DeviceService()) self.keyboard_sensor.Station.value = "gua-device-keyboard0" self.sf_key_1.connect_from(self.keyboard_sensor.Button16) # key 1 self.sf_key_2.connect_from(self.keyboard_sensor.Button17) # key 2 self.sf_key_3.connect_from(self.keyboard_sensor.Button18) # key 3 ### set initial states ### self.set_dragging_technique(1) # switch to 1st dragging variant ### functions ### def set_dragging_technique(self, INT): self.dragging_technique = INT print("Dragging Technique set to technique", self.dragging_technique) def start_dragging(self): _hand_mat = self.hand_transform.Transform.value for _node in self.TARGET_LIST: if self.is_highlight_material( _node.CurrentColor.value ) == True: # a monkey node in close proximity _node.CurrentColor.value = avango.gua.Vec4(1.0, 0.0, 0.0, 1.0) _node.Material.value.set_uniform( "Color", _node.CurrentColor.value) # switch to dragging material self.dragged_objects_list.append( _node) # add node for dragging ## TODO: Implement individual components of the different dragging strategies here ## if self.dragging_technique == 1: # change of node order in scenegraph _node.Parent.value.Children.value.remove(_node) self.hand_transform.Children.value.append(_node) _node.Transform.value = avango.gua.make_inverse_mat( self.hand_transform.WorldTransform.value ) * _node.Transform.value pass elif self.dragging_technique == 2: # absolute tool-hand offset to tool space _node.DraggingOffsetMatrix.value = avango.gua.make_inverse_mat( self.hand_transform.WorldTransform.value ) * _node.Transform.value pass elif self.dragging_technique == 3: # relative tool input to object space pass def update_dragging_candidates(self): #_hand_pos = self.hand_transform.Transform.value.get_translate() _hand_pos = self.hand_transform.WorldTransform.value.get_translate( ) #without WorldTransform when changing viewport the detection of correct monkey dist breaks for _node in self.TARGET_LIST: #_pos = _node.Transform.value.get_translate() # a monkey position _pos = _node.WorldTransform.value.get_translate( ) # a monkey position _dist = (_hand_pos - _pos).length() # hand-object distance _color = _node.CurrentColor.value ## toggle object highlight if _dist < 0.025 and self.is_default_material(_color) == True: _node.CurrentColor.value = avango.gua.Vec4(0.0, 1.0, 0.0, 1.0) _node.Material.value.set_uniform( "Color", _node.CurrentColor.value) # switch to highlight material elif _dist > 0.03 and self.is_highlight_material(_color) == True: _node.CurrentColor.value = avango.gua.Vec4(1.0, 1.0, 1.0, 1.0) _node.Material.value.set_uniform( "Color", _node.CurrentColor.value) # switch to default material def object_dragging(self): # apply hand movement to (all) dragged objects for _node in self.dragged_objects_list: ## TODO: Implement individual components of the different dragging strategies here ## if self.dragging_technique == 1: # change node order in scenegraph pass elif self.dragging_technique == 2: # absolute tool-hand offset to tool space _node.Transform.value = self.hand_transform.WorldTransform.value * _node.DraggingOffsetMatrix.value pass elif self.dragging_technique == 3: # relative tool input to object space self.diff_hand_mat = avango.gua.make_inverse_mat( self.lf_hand_mat ) * self.hand_transform.WorldTransform.value _node.Transform.value = self.diff_hand_mat * _node.Transform.value pass def stop_dragging(self): ## handle all dragged objects for _node in self.dragged_objects_list: _node.CurrentColor.value = avango.gua.Vec4(0.0, 1.0, 0.0, 1.0) _node.Material.value.set_uniform( "Color", _node.CurrentColor.value) # switch to highlight material ## TODO: Implement individual components of the different dragging strategies here ## if self.dragging_technique == 1: # change node order in scenegraph transform = _node.WorldTransform.value _node.Parent.value.Children.value.remove(_node) self.SCENE_ROOT.Children.value.append(_node) _node.Transform.value = transform pass elif self.dragging_technique == 2: # absolute tool-hand offset to tool space pass elif self.dragging_technique == 3: # relative tool input to object space pass self.dragged_objects_list = [] # clear list def is_default_material(self, VEC4): return VEC4.x == 1.0 and VEC4.y == 1.0 and VEC4.z == 1.0 and VEC4.w == 1.0 def is_highlight_material(self, VEC4): return VEC4.x == 0.0 and VEC4.y == 1.0 and VEC4.z == 0.0 and VEC4.w == 1.0 def is_dragging_material(self, VEC4): return VEC4.x == 1.0 and VEC4.y == 0.0 and VEC4.z == 0.0 and VEC4.w == 1.0 ### callback functions ### @field_has_changed(sf_key_1) def sf_key_1_changed(self): if self.sf_key_1.value == True: # key is pressed self.set_dragging_technique(1) # switch dragging technique @field_has_changed(sf_key_2) def sf_key_2_changed(self): if self.sf_key_2.value == True: # key is pressed self.set_dragging_technique(2) # switch dragging technique @field_has_changed(sf_key_3) def sf_key_3_changed(self): if self.sf_key_3.value == True: # key is pressed self.set_dragging_technique(3) # switch dragging technique @field_has_changed(sf_dragging_trigger) def sf_dragging_trigger_changed(self): if self.sf_dragging_trigger.value == True: self.start_dragging() else: self.stop_dragging() def evaluate( self ): # evaluated every frame if any input field has changed (incl. dependency evaluation) self.update_dragging_candidates() self.object_dragging() # possibly drag object with hand input self.lf_hand_mat = self.hand_transform.WorldTransform.value
class ManipulationManager(avango.script.Script): ### input fields sf_key_1 = avango.SFBool() sf_key_2 = avango.SFBool() sf_key_3 = avango.SFBool() sf_key_4 = avango.SFBool() sf_key_5 = avango.SFBool() sf_key_6 = avango.SFBool() sf_key_7 = avango.SFBool() sf_key_8 = avango.SFBool() sf_hand_mat = avango.gua.SFMatrix4() sf_dragging_trigger = avango.SFBool() # constructor def __init__(self): self.super(ManipulationManager).__init__() def my_constructor(self, PARENT_NODE = None, SCENE_ROOT = None, TARGET_LIST = [], ): ### external references ### self.SCENE_ROOT = SCENE_ROOT self.TARGET_LIST = TARGET_LIST ### variables ### self.dragged_objects_list = [] self.lf_hand_mat = avango.gua.make_identity_mat() # last frame hand matrix ## init hand geometry _loader = avango.gua.nodes.TriMeshLoader() # init trimesh loader to load external meshes self.hand_geometry = _loader.create_geometry_from_file("hand_geometry", "data/objects/hand.obj", avango.gua.LoaderFlags.DEFAULTS) self.hand_geometry.Transform.value = \ avango.gua.make_rot_mat(45.0,1,0,0) * \ avango.gua.make_rot_mat(180.0,0,1,0) * \ avango.gua.make_scale_mat(0.06) self.hand_geometry.Material.value.set_uniform("Color", avango.gua.Vec4(1.0, 0.86, 0.54, 1.0)) self.hand_geometry.Material.value.set_uniform("Emissivity", 0.9) self.hand_geometry.Material.value.set_uniform("Metalness", 0.1) self.hand_transform = avango.gua.nodes.TransformNode(Name = "hand_transform") self.hand_transform.Children.value = [self.hand_geometry] PARENT_NODE.Children.value.append(self.hand_transform) self.hand_transform.Transform.connect_from(self.sf_hand_mat) ### init sub-classes ### ## init inputs self.mouseInput = MouseInput() self.mouseInput.my_constructor("gua-device-mouse") if SPACEMOUSE_TYPE == "Spacemouse": self.spacemouseInput = SpacemouseInput() self.spacemouseInput.my_constructor("gua-device-spacemouse") elif SPACEMOUSE_TYPE == "Blue Spacemouse": self.spacemouseInput = NewSpacemouseInput() self.spacemouseInput.my_constructor("gua-device-spacemouse") ## init manipulation techniques self.IPCManipulation = IsotonicPositionControlManipulation() self.IPCManipulation.my_constructor(self.mouseInput.mf_dof, self.mouseInput.mf_buttons) self.EPCManipulation = ElasticPositionControlManipulation() self.EPCManipulation.my_constructor(self.spacemouseInput.mf_dof, self.spacemouseInput.mf_buttons) self.IRCManipulation = IsotonicRateControlManipulation() self.IRCManipulation.my_constructor(self.mouseInput.mf_dof, self.mouseInput.mf_buttons) self.ERCManipulation = ElasticRateControlManipulation() self.ERCManipulation.my_constructor(self.spacemouseInput.mf_dof, self.spacemouseInput.mf_buttons) self.IACManipulation = IsotonicAccelerationControlManipulation() self.IACManipulation.my_constructor(self.mouseInput.mf_dof, self.mouseInput.mf_buttons) self.EACManipulation = ElasticAccelerationControlManipulation() self.EACManipulation.my_constructor(self.spacemouseInput.mf_dof, self.spacemouseInput.mf_buttons) self.NIIPCManipulation = NonIsomorphicIsotonicPositionControlManipulation() self.NIIPCManipulation.my_constructor(self.mouseInput.mf_dof, self.mouseInput.mf_buttons) self.NIERCManipulation = NonIsomorphicElasticRateControlManipulation() self.NIERCManipulation.my_constructor(self.spacemouseInput.mf_dof, self.spacemouseInput.mf_buttons) ## init keyboard sensor for system control self.keyboard_sensor = avango.daemon.nodes.DeviceSensor(DeviceService = avango.daemon.DeviceService()) self.keyboard_sensor.Station.value = "gua-device-keyboard0" self.sf_key_1.connect_from(self.keyboard_sensor.Button16) # key 1 self.sf_key_2.connect_from(self.keyboard_sensor.Button17) # key 2 self.sf_key_3.connect_from(self.keyboard_sensor.Button18) # key 3 self.sf_key_4.connect_from(self.keyboard_sensor.Button19) # key 4 self.sf_key_5.connect_from(self.keyboard_sensor.Button20) # key 5 self.sf_key_6.connect_from(self.keyboard_sensor.Button21) # key 6 self.sf_key_7.connect_from(self.keyboard_sensor.Button22) # key 7 self.sf_key_8.connect_from(self.keyboard_sensor.Button23) # key 8 ### set initial states ### self.set_manipulation_technique(1) # switch to isotonic position control ### functions ### def set_manipulation_technique(self, INT): self.manipulation_technique = INT # disable prior manipulation technique self.IPCManipulation.enable_manipulation(False) self.EPCManipulation.enable_manipulation(False) self.IRCManipulation.enable_manipulation(False) self.ERCManipulation.enable_manipulation(False) self.IACManipulation.enable_manipulation(False) self.EACManipulation.enable_manipulation(False) self.NIIPCManipulation.enable_manipulation(False) self.NIERCManipulation.enable_manipulation(False) # remove existing field connections self.sf_hand_mat.disconnect() self.sf_dragging_trigger.disconnect() if self.manipulation_technique == 1: # isotonic position control self.IPCManipulation.enable_manipulation(True) # init field connections self.sf_hand_mat.connect_from(self.IPCManipulation.sf_mat) self.sf_dragging_trigger.connect_from(self.IPCManipulation.sf_action_trigger) elif self.manipulation_technique == 2: # elastic position control self.EPCManipulation.enable_manipulation(True) # init field connections self.sf_hand_mat.connect_from(self.EPCManipulation.sf_mat) self.sf_dragging_trigger.connect_from(self.EPCManipulation.sf_action_trigger) elif self.manipulation_technique == 3: # isotonic rate control self.IRCManipulation.enable_manipulation(True) # init field connections self.sf_hand_mat.connect_from(self.IRCManipulation.sf_mat) self.sf_dragging_trigger.connect_from(self.IRCManipulation.sf_action_trigger) elif self.manipulation_technique == 4: # elastic rate control self.ERCManipulation.enable_manipulation(True) # init field connections self.sf_hand_mat.connect_from(self.ERCManipulation.sf_mat) self.sf_dragging_trigger.connect_from(self.ERCManipulation.sf_action_trigger) elif self.manipulation_technique == 5: # isotonic acceleration control self.IACManipulation.enable_manipulation(True) # init field connections self.sf_hand_mat.connect_from(self.IACManipulation.sf_mat) self.sf_dragging_trigger.connect_from(self.IACManipulation.sf_action_trigger) elif self.manipulation_technique == 6: # elastic acceleration control self.EACManipulation.enable_manipulation(True) # init field connections self.sf_hand_mat.connect_from(self.EACManipulation.sf_mat) self.sf_dragging_trigger.connect_from(self.EACManipulation.sf_action_trigger) elif self.manipulation_technique == 7: self.NIIPCManipulation.enable_manipulation(True) # init field connections self.sf_hand_mat.connect_from(self.NIIPCManipulation.sf_mat) self.sf_dragging_trigger.connect_from(self.NIIPCManipulation.sf_action_trigger) elif self.manipulation_technique == 8: self.NIERCManipulation.enable_manipulation(True) # init field connections self.sf_hand_mat.connect_from(self.NIERCManipulation.sf_mat) self.sf_dragging_trigger.connect_from(self.NIERCManipulation.sf_action_trigger) def start_dragging(self): _hand_mat = self.hand_transform.WorldTransform.value for _node in self.TARGET_LIST: if self.is_highlight_material(_node.CurrentColor.value) == True: # a monkey node in close proximity _node.CurrentColor.value = avango.gua.Vec4(1.0, 0.0, 0.0, 1.0) _node.Material.value.set_uniform("Color", _node.CurrentColor.value) # switch to dragging material self.dragged_objects_list.append(_node) # add node for dragging ## dragging without snapping # clac tool-hand offset _dragging_offset_mat = avango.gua.make_inverse_mat(_hand_mat) * _node.Transform.value # object transformation in hand coordinate system _node.DraggingOffsetMatrix.value = _dragging_offset_mat # here you can store node dependent dragging transformations def update_dragging_candidates(self): _hand_pos = self.hand_transform.WorldTransform.value.get_translate() for _node in self.TARGET_LIST: _pos = _node.Transform.value.get_translate() # a monkey position _dist = (_hand_pos - _pos).length() # hand-object distance _color = _node.CurrentColor.value ## toggle object highlight if _dist < 0.025 and self.is_default_material(_color) == True: _node.CurrentColor.value = avango.gua.Vec4(0.0, 1.0, 0.0, 1.0) _node.Material.value.set_uniform("Color", _node.CurrentColor.value) # switch to highlight material elif _dist > 0.03 and self.is_highlight_material(_color) == True: _node.CurrentColor.value = avango.gua.Vec4(1.0, 1.0, 1.0, 1.0) _node.Material.value.set_uniform("Color", _node.CurrentColor.value) # switch to default material def object_dragging(self): # apply hand movement to (all) dragged objects for _node in self.dragged_objects_list: _node.Transform.value = self.hand_transform.WorldTransform.value * _node.DraggingOffsetMatrix.value # apply tool-hand offset to absolute hand transformation def stop_dragging(self): ## handle all dragged objects for _node in self.dragged_objects_list: _node.CurrentColor.value = avango.gua.Vec4(0.0, 1.0, 0.0, 1.0) _node.Material.value.set_uniform("Color", _node.CurrentColor.value) # switch to highlight material self.dragged_objects_list = [] # clear list def is_default_material(self, VEC4): return VEC4.x == 1.0 and VEC4.y == 1.0 and VEC4.z == 1.0 and VEC4.w == 1.0 def is_highlight_material(self, VEC4): return VEC4.x == 0.0 and VEC4.y == 1.0 and VEC4.z == 0.0 and VEC4.w == 1.0 def is_dragging_material(self, VEC4): return VEC4.x == 1.0 and VEC4.y == 0.0 and VEC4.z == 0.0 and VEC4.w == 1.0 ### callback functions ### @field_has_changed(sf_key_1) def sf_key_1_changed(self): if self.sf_key_1.value == True: # key is pressed self.set_manipulation_technique(1) # switch to isotonic position control @field_has_changed(sf_key_2) def sf_key_2_changed(self): if self.sf_key_2.value == True: # key is pressed self.set_manipulation_technique(2) # switch to elastic position control @field_has_changed(sf_key_3) def sf_key_3_changed(self): if self.sf_key_3.value == True: # key is pressed self.set_manipulation_technique(3) # switch to isotonic rate control @field_has_changed(sf_key_4) def sf_key_4_changed(self): if self.sf_key_4.value == True: # key is pressed self.set_manipulation_technique(4) # switch to elastic rate control @field_has_changed(sf_key_5) def sf_key_5_changed(self): if self.sf_key_5.value == True: # key is pressed self.set_manipulation_technique(5) # switch to isotonic acceleration control @field_has_changed(sf_key_6) def sf_key_6_changed(self): if self.sf_key_6.value == True: # key is pressed self.set_manipulation_technique(6) # switch to elastic acceleration control @field_has_changed(sf_key_7) def sf_key_7_changed(self): print("field_has_changed") if self.sf_key_7.value == True: # key is pressed self.set_manipulation_technique(7) # switch to elastic acceleration control @field_has_changed(sf_key_8) def sf_key_8_changed(self): if self.sf_key_8.value == True: # key is pressed self.set_manipulation_technique(8) # switch to elastic acceleration control @field_has_changed(sf_dragging_trigger) def sf_dragging_trigger_changed(self): if self.sf_dragging_trigger.value == True: self.start_dragging() else: self.stop_dragging() def evaluate(self): # evaluated every frame if any input field has changed (incl. dependency evaluation) self.update_dragging_candidates() self.object_dragging() # possibly drag object with hand input ## print covered distance and hand velocity as debug output _distance = (self.sf_hand_mat.value.get_translate() - self.lf_hand_mat.get_translate()).length() _velocity = _distance * 60.0 # application loop runs with 60Hz self.lf_hand_mat = self.sf_hand_mat.value