diff --git a/core/sockets.py b/core/sockets.py index e0192a76c5..42541633e3 100644 --- a/core/sockets.py +++ b/core/sockets.py @@ -666,6 +666,7 @@ class SvMatrixSocket(NodeSocket, SvSocketCommon): color = (0.2, 0.8, 0.8, 1.0) quick_link_to_node = 'SvMatrixInNodeMK4' + nesting_level: IntProperty(default=1) def do_flatten(self, data): return flatten_data(data, 1, data_types=(Matrix,)) @@ -814,7 +815,7 @@ class SvColorSocket(NodeSocket, SvSocketCommon): default_property: FloatVectorProperty(default=(0, 0, 0, 1), size=4, subtype='COLOR', min=0, max=1, update=process_from_socket) expanded: BoolProperty(default=False) # for minimizing showing socket property - + nesting_level: IntProperty(default=3) def draw_property(self, layout, prop_origin=None, prop_name='default_property'): if prop_origin is None: prop_origin = self @@ -837,6 +838,9 @@ def draw_group_property(self, layout, text, interface_socket): layout.prop(self, 'default_property', text=text) else: layout.label(text=text) + + def do_flat_topology(self, data): + return flatten_data(data, 3) class SvDummySocket(NodeSocket, SvSocketCommon): '''Dummy Socket for sockets awaiting assignment of type''' @@ -1234,7 +1238,7 @@ class SvLinkNewNodeInput(bpy.types.Operator): @classmethod def poll(cls, context): - return hasattr(context, 'socket') + return hasattr(context, 'socket') def execute(self, context): tree, node, socket = context.node.id_data, context.node, context.socket diff --git a/node_tree.py b/node_tree.py index e58af361e5..baa69632e8 100644 --- a/node_tree.py +++ b/node_tree.py @@ -184,7 +184,7 @@ def on_draft_mode_changed(self, context): sv_show_error_details : BoolProperty( name = "Show error details", description = "Display exception stack in the node view as well", - default = False, + default = False, update=lambda s, c: process_tree(s), options=set()) @@ -322,6 +322,11 @@ def init(self, context): sys.stderr.write('ERROR: %s\n' % str(err)) self.set_color() + def sv_new_input(self, socket_type, name, **attrib_dict): + socket = self.inputs.new(socket_type, name) + for att in attrib_dict: + setattr(socket, att, attrib_dict[att]) + def free(self): """ This method is not supposed to be overriden in specific nodes. @@ -603,7 +608,7 @@ def migrate_from(self, old_node): def get_and_set_gl_scale_info(self, origin=None): # todo, probably openGL viewers should have its own mixin class """ - This function is called in sv_init in nodes that draw GL instructions to the nodeview, + This function is called in sv_init in nodes that draw GL instructions to the nodeview, the nodeview scale and dpi differs between users and must be queried to get correct nodeview x,y and dpi scale info. """ diff --git a/nodes/matrix/matrix_out_mk2.py b/nodes/matrix/matrix_out_mk2.py index 33770ba093..43f81370a1 100644 --- a/nodes/matrix/matrix_out_mk2.py +++ b/nodes/matrix/matrix_out_mk2.py @@ -48,6 +48,11 @@ class SvMatrixOutNodeMK2(bpy.types.Node, SverchCustomTreeNode, SvAngleHelper, Sv bl_icon = 'OUTLINER_OB_EMPTY' sv_icon = 'SV_MATRIX_OUT' + flat_output: bpy.props.BoolProperty( + name="Flat Quaternions output", + description="Flatten Quaternions output by list-joining level 1", + default=True, update=updateNode) + def migrate_from(self, old_node): ''' Migration from old nodes (attributes mapping) ''' if old_node.bl_idname == "MatrixOutNode": @@ -80,7 +85,7 @@ def update_mode(self, context): items=mode_items, default="AXISANGLE", update=update_mode) def sv_init(self, context): - self.inputs.new('SvMatrixSocket', "Matrix").is_mandatory =True + self.sv_new_input('SvMatrixSocket', "Matrix", is_mandatory=True, nesting_level=2) # translation and scale outputs self.outputs.new('SvVerticesSocket', "Location") self.outputs.new('SvVerticesSocket', "Scale") @@ -105,40 +110,52 @@ def draw_buttons(self, context, layout): def draw_buttons_ext(self, context, layout): if self.mode in {"EULER", "AXISANGLE"}: self.draw_angle_units_buttons(context, layout) - + elif self.mode == 'QUATERNION': + layout.prop(self, 'flat_output') + def process_data(self, params): input_M = params[0] outputs = self.outputs # decompose matrices into: Translation, Rotation (quaternion) and Scale - location_list = [] - quaternion_list = [] # rotations (as quaternions) - scale_list = [] - angles = [[], [], []] - axis_list, angle_list = [], [] - for m in input_M: - T, R, S = m.decompose() - location_list.append([list(T)]) - quaternion_list.append(R) - scale_list.append([list(S)]) + result = [] + for mat_list in input_M: + location_list = [] + quaternion_list = [] # rotations (as quaternions) + scale_list = [] + angles = [[], [], []] + axis_list, angle_list = [], [] + for m in mat_list: + T, R, S = m.decompose() + location_list.append(list(T)) + quaternion_list.append(R) + scale_list.append(list(S)) + + if self.mode == "EULER": + # conversion factor from radians to the current angle units + au = self.angle_conversion_factor(AngleUnits.RADIANS, self.angle_units) - if self.mode == "EULER": - # conversion factor from radians to the current angle units - au = self.angle_conversion_factor(AngleUnits.RADIANS, self.angle_units) + for i, name in enumerate("XYZ"): + if outputs["Angle " + name].is_linked: + angles[i] = [q.to_euler(self.euler_order)[i] * au for q in quaternion_list] + elif self.mode == "AXISANGLE": + if outputs['Axis'].is_linked: + axis_list = [tuple(q.axis) for q in quaternion_list] - for i, name in enumerate("XYZ"): - if outputs["Angle " + name].is_linked: - angles[i] = [[q.to_euler(self.euler_order)[i] * au] for q in quaternion_list] - elif self.mode == "AXISANGLE": - if outputs['Axis'].is_linked: - axis_list = [[tuple(q.axis)] for q in quaternion_list] + if outputs['Angle'].is_linked: + # conversion factor from radians to the current angle units + au = self.angle_conversion_factor(AngleUnits.RADIANS, self.angle_units) + angle_list = [q.angle * au for q in quaternion_list] + result.append([location_list, scale_list, quaternion_list, *angles, axis_list, angle_list]) - if outputs['Angle'].is_linked: - # conversion factor from radians to the current angle units - au = self.angle_conversion_factor(AngleUnits.RADIANS, self.angle_units) - angle_list = [[q.angle * au] for q in quaternion_list] + if self.mode == 'QUATERNION': + output_data = list(zip(*result)) + if len(output_data[2]) == 1 and self.flat_output: + output_data[2] = output_data[2][0] + return output_data + + return list(zip(*result)) - return (location_list, scale_list, quaternion_list, *angles, axis_list, angle_list)