| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  | 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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-06 10:01:08 +00:00
										 |  |  |     def __init__(self, *args, **kwargs): | 
					
						
							|  |  |  |         super(AddPhysicsConstraintNode, self).__init__(*args, **kwargs) | 
					
						
							| 
									
										
										
										
											2025-01-22 16:18:30 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 | 
					
						
							|  |  |  | 
 |