177 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from lnx.logicnode.lnx_nodes import *
 | |
| 
 | |
| class AddPhysicsConstraintNode(LnxLogicTreeNode):
 | |
|     """
 | |
|     Add a physics constraint to constrain two rigid bodies if not already present.
 | |
| 
 | |
|     @option Fixed: No fredom of movement. Relative positions and rotations of rigid bodies are fixed
 | |
| 
 | |
|     @option Point: Both rigid bodies are constrained at the pivot object.
 | |
| 
 | |
|     @option Hinge: Constrained objects can move only along angular Z axis of the pivot object.
 | |
| 
 | |
|     @option Slider: Constrained objects can move only along linear X axis of the pivot object.
 | |
| 
 | |
|     @option Piston: Constrained objects can move only and rotate along X axis of the pivot object.
 | |
| 
 | |
|     @option GenericSpring: Fully custimizable generic 6 degree of freedom constraint with optional springs. All liner and angular axes can be constrained
 | |
|     along with spring options. Use `Physics Constraint Node` to set a combination of constraints and springs.
 | |
| 
 | |
|     @seeNode Physics Constraint
 | |
| 
 | |
|     @input Pivot object: The object to which the physics constraint traint is applied. This object will not be affected by the constraint
 | |
|     but is necessary to specify the constraint axes and location. Hence, the pivot object need not be a rigid body. Typically an `Empty`
 | |
|     object may be used. Each pivot object can have only one constraint trait applied. Moving/rotating/parenting the pivot object after the constraint
 | |
|     is applied has no effect. However, removig the pivot object removes the constraint and `RB 1` and `RB 2` are no longer constrained.
 | |
| 
 | |
|     @input RB 1: The first rigid body to be constrained. Must be a rigid body. This object can be constrained by more than one constraint.
 | |
| 
 | |
|     @input RB 2: The second rigid body to be constrained. Must be a rigid body. This object can be constrained by more than one constraint.
 | |
| 
 | |
|     @input Disable Collisions: Disable collisions between `RB 1` and `RB 2`
 | |
| 
 | |
|     @input Breakable: Constraint can break if stress on the constraint is more than the set threshold. Disable this option to disable breaking.
 | |
| 
 | |
|     @input Breaking threshold: Stress on the constraint above which the constraint breaks. Depends on the mass, velocity of rigid bodies and type of constraint.
 | |
| 
 | |
|     @input Limit Lower: Lower limit of the consraint in that particular axis
 | |
| 
 | |
|     @input Limit Upper: Upper limit of the constraint in that particular axis. (`lower limit` = `upper limit`) --> Fully constrained. (`lower limit` < `upper limit`) --> Partially constrained
 | |
|     (`lower limit` > `upper limit`) --> Full freedom.
 | |
| 
 | |
|     @input Angular limits: Limits to constarin rotation. Specified in degrees. Range (-360 to +360)
 | |
| 
 | |
|     @input Add Constarint: Option to add custom constraint to `Generic Spring` type.
 | |
|     """
 | |
| 
 | |
| 
 | |
|     bl_idname = 'LNAddPhysicsConstraintNode'
 | |
|     bl_label = 'Add Physics Constraint'
 | |
|     lnx_section = 'add'
 | |
|     lnx_version = 1
 | |
| 
 | |
|     @staticmethod
 | |
|     def get_enum_id_value(obj, prop_name, value):
 | |
|         return obj.bl_rna.properties[prop_name].enum_items[value].identifier
 | |
| 
 | |
|     @staticmethod
 | |
|     def get_count_in(type_name):
 | |
|         return {
 | |
|             'Fixed': 0,
 | |
|             'Point': 1,
 | |
|             'Hinge': 2,
 | |
|             'Slider': 3,
 | |
|             'Piston': 4,
 | |
|             'Generic Spring': 5
 | |
|         }.get(type_name, 0)
 | |
| 
 | |
|     def get_enum(self):
 | |
|         return self.get('property0', 0)
 | |
| 
 | |
|     def set_enum(self, value):
 | |
|         # Checking the selection of another type
 | |
|         select_current = self.get_enum_id_value(self, 'property0', value)
 | |
|         select_prev = self.property0
 | |
| 
 | |
|         #Check if a different type is selected
 | |
|         if select_prev != select_current:
 | |
|             print('New value selected')
 | |
|             # Arguements for type Fixed
 | |
|             if (self.get_count_in(select_current) == 0):
 | |
|                 while (len(self.inputs) > 7):
 | |
|                     self.inputs.remove(self.inputs.values()[-1])
 | |
| 
 | |
|             # Arguements for type Point
 | |
|             if (self.get_count_in(select_current) == 1):
 | |
|                 while (len(self.inputs) > 7):
 | |
|                     self.inputs.remove(self.inputs.values()[-1])
 | |
| 
 | |
|             #Arguements for type Hinge
 | |
|             if (self.get_count_in(select_current) == 2):
 | |
|                 while (len(self.inputs) > 7):
 | |
|                     self.inputs.remove(self.inputs.values()[-1])
 | |
|                 #Z ang limits
 | |
|                 self.add_input('LnxBoolSocket', 'Z angle')
 | |
|                 self.add_input('LnxFloatSocket', 'Z ang lower', -45.0)
 | |
|                 self.add_input('LnxFloatSocket', 'Z ang upper', 45.0)
 | |
| 
 | |
|             #Arguements for type Slider
 | |
|             if (self.get_count_in(select_current) == 3):
 | |
|                 while (len(self.inputs) > 7):
 | |
|                     self.inputs.remove(self.inputs.values()[-1])
 | |
|                 #X lin limits
 | |
|                 self.add_input('LnxBoolSocket', 'X linear')
 | |
|                 self.add_input('LnxFloatSocket', 'X lin lower')
 | |
|                 self.add_input('LnxFloatSocket', 'X lin upper')
 | |
| 
 | |
|             #Arguements for type Piston
 | |
|             if (self.get_count_in(select_current) == 4):
 | |
|                 while (len(self.inputs) > 7):
 | |
|                     self.inputs.remove(self.inputs.values()[-1])
 | |
|                 #X lin limits
 | |
|                 self.add_input('LnxBoolSocket', 'X linear')
 | |
|                 self.add_input('LnxFloatSocket', 'X lin lower')
 | |
|                 self.add_input('LnxFloatSocket', 'X lin upper')
 | |
|                 #X ang limits
 | |
|                 self.add_input('LnxBoolSocket', 'X angle')
 | |
|                 self.add_input('LnxFloatSocket', 'X ang lower', -45.0)
 | |
|                 self.add_input('LnxFloatSocket', 'X ang upper', 45.0)
 | |
| 
 | |
|             #Arguements for type GenericSpring
 | |
|             if (self.get_count_in(select_current) == 5):
 | |
|                 while (len(self.inputs) > 7):
 | |
|                     self.inputs.remove(self.inputs.values()[-1])
 | |
| 
 | |
|         self['property0'] = value
 | |
| 
 | |
|     property0: HaxeEnumProperty(
 | |
|         'property0',
 | |
|         items = [('Fixed', 'Fixed', 'Fixed'),
 | |
|                  ('Point', 'Point', 'Point'),
 | |
|                  ('Hinge', 'Hinge', 'Hinge'),
 | |
|                  ('Slider', 'Slider', 'Slider'),
 | |
|                  ('Piston', 'Piston', 'Piston'),
 | |
|                  ('Generic Spring', 'Generic Spring', 'Generic Spring')],
 | |
|         name='Type', default='Fixed', set=set_enum, get=get_enum)
 | |
| 
 | |
|     def __init__(self, *args, **kwargs):
 | |
|         super(AddPhysicsConstraintNode, self).__init__(*args, **kwargs)
 | |
| 
 | |
|     def lnx_init(self, context):
 | |
|         self.add_input('LnxNodeSocketAction', 'In')
 | |
|         self.add_input('LnxNodeSocketObject', 'Pivot Object')
 | |
|         self.add_input('LnxNodeSocketObject', 'RB 1')
 | |
|         self.add_input('LnxNodeSocketObject', 'RB 2')
 | |
|         self.add_input('LnxBoolSocket', 'Disable Collissions')
 | |
|         self.add_input('LnxBoolSocket', 'Breakable')
 | |
|         self.add_input('LnxFloatSocket', 'Breaking Threshold')
 | |
|         self.add_output('LnxNodeSocketAction', 'Out')
 | |
| 
 | |
|     def draw_buttons(self, context, layout):
 | |
|         layout.prop(self, 'property0')
 | |
| 
 | |
|         #GenericSpring:
 | |
|         if (self.get_count_in(self.property0) == 5):
 | |
|             grid0 = layout.grid_flow(row_major=True, columns=1, align=True)
 | |
|             grid0.label(text="Possible Constraints:")
 | |
|             grid0.label(text="Linear [X, Y, Z]")
 | |
|             grid0.label(text="Angular [X, Y, Z]")
 | |
|             grid0.label(text="Spring Linear [X, Y, Z]")
 | |
|             grid0.label(text="Spring Angular [X, Y, Z]")
 | |
|             row = layout.row(align=True)
 | |
|             column = row.column(align=True)
 | |
|             op = column.operator('lnx.node_add_input', text='Add Constraint', icon='PLUS', emboss=True)
 | |
|             op.node_index = str(id(self))
 | |
|             op.socket_type = 'LnxDynamicSocket'
 | |
|             op.name_format = 'Constraint {0}'.format(len(self.inputs) - 6)
 | |
|             column1 = row.column(align=True)
 | |
|             op = column1.operator('lnx.node_remove_input', text='', icon='X', emboss=True)
 | |
|             op.node_index = str(id(self))
 | |
|             #Static inputs
 | |
|             if len(self.inputs) < 8:
 | |
|                 column1.enabled = False
 | |
|             #Max Possible inputs
 | |
|             if len(self.inputs) > 18:
 | |
|                 column.enabled = False
 | |
| 
 |