class SvMatrixNormalNode(bpy.types.Node, SverchCustomTreeNode):
    ''' Construct a Matirx from Normal '''
    bl_idname = 'SvMatrixNormalNode'
    bl_label = 'Matrix normal'
    bl_icon = 'OUTLINER_OB_EMPTY'

    F = ['X', 'Y', 'Z', '-X', '-Y', '-Z']
    S = ['X', 'Y', 'Z']
    track = EnumProperty(name="track", default=F[4], items=e(F), update=updateNode)
    up = EnumProperty(name="up", default=S[2], items=e(S), update=updateNode)

    def sv_init(self, context):
        self.inputs.new('VerticesSocket', "Location").use_prop = True
        self.inputs.new('VerticesSocket', "Normal").use_prop = True
        self.outputs.new('MatrixSocket', "Matrix")

    def draw_buttons(self, context, layout):
        layout.prop(self, "track", "track")
        layout.prop(self, "up", "up")

    def process(self):
        Ma = self.outputs[0]
        if not Ma.is_linked:
            return
        L, N = self.inputs
        out = []
        loc = L.sv_get()[0]
        nor = [Vector(i) for i in N.sv_get()[0]]
        nor = safc(loc, nor)
        T, U = self.track, self.up
        for V, N in zip(loc, nor):
            n = N.to_track_quat(T, U)
            m = Matrix.Translation(V) * n.to_matrix().to_4x4()
            out.append([i[:] for i in m])
        Ma.sv_set(out)
示例#2
0
class SvGetDataObjectNode(bpy.types.Node, SverchCustomTreeNode):
    ''' Get Object Props '''
    bl_idname = 'SvGetDataObjectNode'
    bl_label = 'Object ID Get'
    bl_icon = 'OUTLINER_OB_EMPTY'

    M = ['actions','brushes','filepath','grease_pencil','groups',
         'images','libraries','linestyles','masks','materials',
         'movieclips','node_groups','particles','scenes','screens','shape_keys',
         'sounds','speakers','texts','textures','worlds','objects']
    T = ['MESH','CURVE','SURFACE','META','FONT','ARMATURE','LATTICE','EMPTY','CAMERA','LAMP','SPEAKER']

    Modes = EnumProperty(name="getmodes", default="objects", items=e(M), update=updateNode)
    Types = EnumProperty(name="getmodes", default="MESH", items=e(T), update=updateNode)

    def draw_buttons(self, context, layout):
        row = layout.row(align=True)
        layout.prop(self, "Modes", "mode")
        if self.Modes == 'objects':
            layout.prop(self, "Types", "type")

    def sv_init(self, context):
        self.outputs.new('StringsSocket', "Objects")

    def process(self):
        sob = self.outputs['Objects']
        if not sob.is_linked:
            return
        L = getattr(bpy.data,self.Modes)
        if self.Modes != 'objects':
            sob.sv_set(L[:])
        else:
            sob.sv_set([i for i in L if i.type == self.Types])
示例#3
0
class SvMatrixNormalNode(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: M. from Loc & Normal
    Tooltip:  Construct a Matirx from  Location and Normal vectors

    """

    bl_idname = 'SvMatrixNormalNode'
    bl_label = 'Matrix normal'
    bl_icon = 'OUTLINER_OB_EMPTY'
    sv_icon = 'SV_MATRIX_NORMAL'

    F = ['X', 'Y', 'Z', '-X', '-Y', '-Z']
    S = ['X', 'Y', 'Z']

    track: EnumProperty(name="track", default=F[4], items=e(F), update=updateNode)
    up: EnumProperty(name="up", default=S[2], items=e(S), update=updateNode)
    flat_output: BoolProperty(
        name="Flat output",
        description="Flatten output by list-joining level 1",
        default=True,
        update=updateNode)

    def sv_init(self, context):
        self.inputs.new('SvVerticesSocket', "Location").use_prop = True
        self.inputs.new('SvVerticesSocket', "Normal").use_prop = True
        self.outputs.new('SvMatrixSocket', "Matrix")

    def draw_buttons(self, context, layout):
        layout.prop(self, "track", text="track")
        layout.prop(self, "up", text="up")

    def draw_buttons_ext(self, context, layout):
        layout.prop(self, "track", text="track")
        layout.prop(self, "up", text="up")
        self.draw_buttons(context, layout)
        layout.prop(self, "flat_output", text="Flat Output", expand=False)

    def rclick_menu(self, context, layout):
        layout.prop_menu_enum(self, "track", text="Track:")
        layout.prop_menu_enum(self, "up", text="Up:")
        layout.prop(self, "flat_output", text="Flat Output", expand=False)

    def process(self):
        Ma = self.outputs[0]
        if not Ma.is_linked:
            return
        L, N = self.inputs
        T, U = self.track, self.up
        loc = L.sv_get()
        nor = Vector_generate(N.sv_get())
        out = []
        m_add = out.extend if  self.flat_output else out.append
        params = match_long_repeat([loc, nor])

        for par in zip(*params):
            matrixes = matrix_normal(par, T, U)
            m_add(matrixes)
        Ma.sv_set(out)
示例#4
0
class SvBMVertsNode(bpy.types.Node, SverchCustomTreeNode):
    ''' BMesh Verts '''
    bl_idname = 'SvBMVertsNode'
    bl_label = 'BMesh props'
    bl_icon = 'OUTLINER_OB_EMPTY'

    Modes = ['verts', 'faces', 'edges']
    Mod = EnumProperty(name="getmodes",
                       default="verts",
                       items=e(Modes),
                       update=updateNode)
    a = ['hide', 'select']
    PV = a + [
        'is_manifold', 'is_wire', 'is_boundary', 'calc_shell_factor()',
        'calc_edge_angle(-1)'
    ]
    PF = a + ['calc_area()', 'calc_perimeter()', 'material_index', 'smooth']
    PE = a + [
        'calc_face_angle(0)', 'calc_face_angle_signed(0)', 'calc_length()',
        'is_boundary', 'is_contiguous', 'is_convex', 'is_manifold', 'is_wire',
        'seam'
    ]
    verts = EnumProperty(name="Vprop",
                         default="is_manifold",
                         items=e(PV),
                         update=updateNode)
    faces = EnumProperty(name="Fprop",
                         default="select",
                         items=e(PF),
                         update=updateNode)
    edges = EnumProperty(name="Eprop",
                         default="select",
                         items=e(PE),
                         update=updateNode)

    def sv_init(self, context):
        self.inputs.new('StringsSocket', 'bmesh_list')
        self.outputs.new('StringsSocket', 'Value')

    def draw_buttons(self, context, layout):
        layout.prop(self, "Mod", "Get")
        layout.prop(self, self.Mod, "")

    def process(self):
        V = []
        bm = self.inputs['bmesh_list'].sv_get()
        elem = getattr(self, self.Mod)
        exec("for b in bm:\n    bv = getattr(b, self.Mod)\n    V.append([i." +
             elem + " for i in bv])")
        self.outputs['Value'].sv_set(V)

    def update_socket(self, context):
        self.update()
示例#5
0
class SvBVHtreeNode(bpy.types.Node, SverchCustomTreeNode):
    ''' BVH Tree '''
    bl_idname = 'SvBVHtreeNode'
    bl_label = 'BVH Tree In'
    bl_icon = 'OUTLINER_OB_EMPTY'

    def mode_change(self, context):
        inputs = self.inputs
        while len(inputs) > 1:
            inputs.remove(inputs[-1])
        if self.Mod == "FromObject":
            inputs[0].name = "Objects"
            inputs[0].hide = 0
        elif self.Mod == "FromBMesh":
            inputs[0].name = "bmesh_list"
            inputs[0].hide = 0
        else:
            inputs[0].hide = 1
            inputs.new('VerticesSocket', 'Verts')
            inputs.new('StringsSocket', 'Polys')

    Modes = ['FromObject', 'FromBMesh', 'FromSVdata']
    Mod: EnumProperty(name="getmodes",
                      default=Modes[0],
                      items=e(Modes),
                      update=mode_change)

    def sv_init(self, context):
        self.inputs.new('StringsSocket', 'Objects')
        self.outputs.new('StringsSocket', 'BVHtree_list')

    def draw_buttons(self, context, layout):
        layout.prop(self, "Mod", "Get")

    def process(self):
        bvh = []
        if self.Mod == "FromObject":
            for i in self.inputs[0].sv_get():
                bvh.append(
                    BVHTree.FromObject(i,
                                       bpy.context.scene,
                                       deform=True,
                                       render=False,
                                       cage=False,
                                       epsilon=0.0))
        elif self.Mod == "FromBMesh":
            for i in self.inputs[0].sv_get():
                bvh.append(BVHTree.FromBMesh(i))
        else:
            for i, i2 in zip(self.inputs[1].sv_get(), self.inputs[2].sv_get()):
                bvh.append(
                    BVHTree.FromPolygons(i,
                                         i2,
                                         all_triangles=False,
                                         epsilon=0.0))
        self.outputs[0].sv_set(bvh)

    def update_socket(self, context):
        self.update()
示例#6
0
class SvNumpyArrayNode(bpy.types.Node, SverchCustomTreeNode):
    ''' Numpy Props '''
    bl_idname = 'SvNumpyArrayNode'
    bl_label = 'Numpy Array'
    bl_icon = 'OUTLINER_OB_EMPTY'

    Modes = [
        'x.tolist()', 'x.conj()', 'x.flatten()', 'np.add(x,y)',
        'np.subtract(x,y)', 'x.resize()', 'x.transpose()', 'np.trunc(x)',
        'x.squeeze()', 'np.ones_like(x)', 'np.minimum(x,y)', 'x.round()',
        'np.maximum(x,y)', 'np.sin(x)', 'x.ptp()', 'x.all()', 'x.any()',
        'np.remainder(x,y)', 'np.unique(x)', 'x.sum()', 'x.cumsum()',
        'x.mean()', 'x.var()', 'x.std()', 'x.prod()', 'x.cumprod()',
        'np.array(x)', 'np.array_equal(x,y)', 'np.invert(x)', 'np.rot90(x,1)',
        'x[y]', 'x+y', 'x*y', 'Custom'
    ]

    Mod: EnumProperty(name="getmodes",
                      default="np.array(x)",
                      items=e(Modes),
                      update=updateNode)
    Cust: StringProperty(default='x[y.argsort()]', update=updateNode)

    def sv_init(self, context):
        self.inputs.new('StringsSocket', 'x')
        self.inputs.new('StringsSocket', 'y')
        self.outputs.new('StringsSocket', 'Value')

    def draw_buttons(self, context, layout):
        layout.prop(self, "Mod", text="Get")
        if self.Mod == 'Custom':
            layout.prop(self, "Cust", text="")

    def process(self):
        out = self.outputs[0]
        if out.is_linked:
            X, Y = self.inputs
            Mod = self.Mod
            string = self.Cust if Mod == 'Custom' else Mod
            if X.is_linked and Y.is_linked:
                out.sv_set(
                    eval("[" + string +
                         " for x,y in zip(X.sv_get(),Y.sv_get())]"))
            elif X.is_linked:
                out.sv_set(eval("[" + string + " for x in X.sv_get()]"))
            else:
                out.sv_set([eval(string)])

    def update_socket(self, context):
        self.update()
示例#7
0
class SvGetAssetProperties(bpy.types.Node, SverchCustomTreeNode,
                           SvAnimatableNode):
    ''' Get Asset Props '''
    bl_idname = 'SvGetAssetProperties'
    bl_label = 'Object ID Selector'
    bl_icon = 'SELECT_SET'
    sv_icon = 'SV_OBJECT_ID_SELECTOR'

    def pre_updateNode(self, context):
        ''' must rebuild for each update'''
        self.type_collection_name.clear()
        for o in bpy.data.objects:
            if o.type == self.Type:
                self.type_collection_name.add().name = o.name

        # updateNode(self, context)
        self.process()

    def frame_updateNode(self, context):
        ''' must rebuild for each update'''
        self.frame_collection_name.clear()
        gp_layer = bpy.data.grease_pencils[self.gp_name].layers[self.gp_layer]
        for idx, f in enumerate(gp_layer.frames):
            self.frame_collection_name.add().name = str(idx) + ' | ' + str(
                f.frame_number)

        # updateNode(self, context)
        if self.gp_selected_frame_mode == 'active_frame':
            if len(self.inputs) == 0:
                self.inputs.new("SvStringsSocket", 'frame#')
        else:
            if len(self.inputs) > 0:
                self.inputs.remove(self.inputs[-1])

        self.process()

    type_collection_name: bpy.props.CollectionProperty(
        type=bpy.types.PropertyGroup)
    frame_collection_name: bpy.props.CollectionProperty(
        type=bpy.types.PropertyGroup)

    M = [
        'actions', 'brushes', 'filepath', 'grease_pencils', 'groups', 'images',
        'libraries', 'linestyles', 'masks', 'materials', 'movieclips',
        'node_groups', 'particles', 'scenes', 'screens', 'shape_keys',
        'sounds', 'speakers', 'texts', 'textures', 'worlds', 'objects'
    ]
    T = [
        'MESH', 'CURVE', 'SURFACE', 'META', 'FONT', 'ARMATURE', 'GPENCIL',
        'LATTICE', 'EMPTY', 'CAMERA', 'LIGHT', 'SPEAKER'
    ]

    Mode: EnumProperty(name="getmodes",
                       default="objects",
                       items=e(M),
                       update=updateNode)
    Type: EnumProperty(name="getmodes",
                       default="MESH",
                       items=e(T),
                       update=pre_updateNode)
    text_name: bpy.props.StringProperty(update=updateNode)
    object_name: bpy.props.StringProperty(update=updateNode)
    image_name: bpy.props.StringProperty(update=updateNode)
    pass_pixels: bpy.props.BoolProperty(update=updateNode)

    # GP props
    gp_name: bpy.props.StringProperty(update=updateNode)
    gp_layer: bpy.props.StringProperty(update=updateNode)
    gp_frame_current: bpy.props.BoolProperty(default=True, update=updateNode)
    gp_frame_override: bpy.props.IntProperty(default=1, update=updateNode)
    gp_stroke_idx: bpy.props.IntProperty(update=updateNode)

    gp_frame_mode_options = [
        (no_space(k), k, '', i)
        for i, k in enumerate(["pick frame", "active frame"])
    ]
    gp_selected_frame_mode: bpy.props.EnumProperty(
        items=gp_frame_mode_options,
        description="offers choice between current frame or available frames",
        default="pick_frame",
        update=frame_updateNode)
    gp_frame_pick: bpy.props.StringProperty(update=frame_updateNode)
    gp_pass_points: bpy.props.BoolProperty(default=True, update=updateNode)

    def draw_gp_options(self, context, layout):
        # -- points  [p.co for p in points]
        # -- color
        #     -- color.color (stroke_color)
        #     -- color.fill_color
        #     -- color.file_alpha
        # -- line_width
        # -- draw_cyclic
        #  --- / triangles (only set is useful...)

        layout.prop_search(self,
                           'gp_name',
                           bpy.data,
                           'grease_pencils',
                           text='name')
        if not self.gp_name:
            return

        layout.prop_search(self,
                           'gp_layer',
                           bpy.data.grease_pencils[self.gp_name],
                           'layers',
                           text='layer')
        if not self.gp_layer:
            return

        layout.prop(self, 'gp_selected_frame_mode', expand=True)
        gp_layer = bpy.data.grease_pencils[self.gp_name].layers[self.gp_layer]
        frame_data = None
        if self.gp_selected_frame_mode == 'active_frame':
            frame_data = gp_layer.active_frame
        else:
            # maybe display uilist with frame_index and frame_nmber.
            layout.prop_search(self, 'gp_frame_pick', self,
                               'frame_collection_name')
        layout.prop(self, 'gp_pass_points', text='pass points')

    def draw_buttons(self, context, layout):
        # layout.operator('node.'   ,text='refresh from scene')
        self.draw_animatable_buttons(layout, icon_only=True)
        layout.row().prop(self, "Mode", text="data")

        if self.Mode == 'objects':
            layout.prop(self, "Type", text="type")
            layout.prop_search(self,
                               'object_name',
                               self,
                               'type_collection_name',
                               text='name',
                               icon='OBJECT_DATA')
        elif self.Mode == 'texts':
            layout.prop_search(self,
                               'text_name',
                               bpy.data,
                               'texts',
                               text='name')
        elif self.Mode == 'images':
            layout.prop_search(self,
                               'image_name',
                               bpy.data,
                               'images',
                               text='name')
            if self.image_name:
                layout.prop(self, 'pass_pixels', text='pixels')
                # size ?  new socket outputting [w/h]
        elif self.Mode == 'grease_pencils':
            self.draw_gp_options(context, layout)

    def sv_init(self, context):
        self.outputs.new('SvStringsSocket', "Objects")
        self.width = 210
        self.Type = 'MESH'  # helps init the custom object prop_search

    def process(self):
        output_socket = self.outputs['Objects']
        if not output_socket.is_linked:
            return

        data_list = getattr(bpy.data, self.Mode)

        if self.Mode == 'objects':
            if self.object_name:
                output_socket.sv_set([data_list[self.object_name]])
            else:
                output_socket.sv_set(
                    [i for i in data_list if i.type == self.Type])

        elif self.Mode == 'texts':
            if self.text_name:
                # print(repr(data_list[self.text_name].as_string()))
                output_socket.sv_set([[data_list[self.text_name].as_string()]])
            else:
                output_socket.sv_set(data_list[:])

        elif self.Mode == 'images':
            if self.image_name:
                img = data_list[self.image_name]
                if self.pass_pixels:
                    output_socket.sv_set([[img.pixels[:]]])
                else:
                    output_socket.sv_set([img])
            else:
                output_socket.sv_set(data_list[:])

        elif self.Mode == 'grease_pencils':
            # candidate for refactor
            if self.gp_name and self.gp_layer:
                GP_and_layer = data_list[self.gp_name].layers[self.gp_layer]
                if self.gp_selected_frame_mode == 'active_frame':
                    if len(self.inputs) > 0 and self.inputs[0].is_linked:

                        frame_number = self.inputs[0].sv_get()[0][0]
                        key = frame_from_available2(frame_number, GP_and_layer)
                        strokes = GP_and_layer.frames[key].strokes
                    else:
                        strokes = GP_and_layer.active_frame.strokes

                    if not strokes:
                        return

                    if self.gp_pass_points:
                        output_socket.sv_set([[p.co[:] for p in s.points]
                                              for s in strokes])
                    else:
                        output_socket.sv_set(strokes)
                else:
                    if self.gp_frame_pick:
                        idx_from_frame_pick = int(
                            self.gp_frame_pick.split(' | ')[0])
                        frame_data = GP_and_layer.frames[idx_from_frame_pick]
                        if frame_data:
                            if self.gp_pass_points:
                                output_socket.sv_set(
                                    [[p.co[:] for p in s.points]
                                     for s in frame_data.strokes])
                            else:
                                output_socket.sv_set(strokes)

        else:
            output_socket.sv_set(data_list[:])
示例#8
0
class SvMatrixTrackToNode(bpy.types.Node, SverchCustomTreeNode):
    ''' Construct a Matrix from arbitrary Track and Up vectors '''
    bl_idname = 'SvMatrixTrackToNode'
    bl_label = 'Matrix Track To'
    bl_icon = 'OUTLINER_OB_EMPTY'

    TUA = ["X Y", "X Z", "Y X", "Y Z", "Z X", "Z Y"]
    tu_axes: EnumProperty(
        name="Track/Up Axes",
        description=
        "Select which two of the XYZ axes to be the Track and Up axes",
        items=e(TUA),
        default=TUA[0],
        update=updateNode)

    normalize: BoolProperty(name="Normalize Vectors",
                            description="Normalize the output X,Y,Z vectors",
                            default=True,
                            update=updateNode)

    origin: FloatVectorProperty(
        name='Location',
        description="The location component of the output matrix",
        default=(0, 0, 0),
        update=updateNode)

    scale: FloatVectorProperty(
        name='Scale',
        description="The scale component of the output matrix",
        default=(1, 1, 1),
        update=updateNode)

    vA: FloatVectorProperty(name='A',
                            description="A direction",
                            default=(1, 0, 0),
                            update=updateNode)

    vB: FloatVectorProperty(name='B',
                            description='B direction',
                            default=(0, 1, 0),
                            update=updateNode)

    TUM = ["A B", "A -B", "-A B", "-A -B", "B A", "B -A", "-B A", "-B -A"]
    tu_mapping: EnumProperty(
        name="Track/Up Mapping",
        description=
        "Map the Track and Up vectors to one of the two inputs or their negatives",
        items=e(TUM),
        default=TUM[0],
        update=updateNode)

    def sv_init(self, context):
        self.inputs.new('VerticesSocket', "Location").prop_name = "origin"  # L
        self.inputs.new('VerticesSocket', "Scale").prop_name = "scale"  # S
        self.inputs.new('VerticesSocket', "A").prop_name = "vA"  # A
        self.inputs.new('VerticesSocket', "B").prop_name = "vB"  # B
        self.outputs.new('MatrixSocket', "Matrix")
        self.outputs.new('VerticesSocket', "X")
        self.outputs.new('VerticesSocket', "Y")
        self.outputs.new('VerticesSocket', "Z")

    def split_columns(self, panel, ratios, aligns):
        """
        Splits the given panel into columns based on the given set of ratios.
        e.g ratios = [1, 2, 1] or [.2, .3, .2] etc
        Note: The sum of all ratio numbers doesn't need to be normalized
        """
        col2 = panel
        cols = []
        ns = len(ratios) - 1  # number of splits
        for n in range(ns):
            n1 = ratios[n]  # size of the current column
            n2 = sum(ratios[n + 1:])  # size of all remaining columns
            p = n1 / (n1 + n2
                      )  # percentage split of current vs remaning columns
            # print("n = ", n, " n1 = ", n1, " n2 = ", n2, " p = ", p)
            split = col2.split(percentage=p, align=aligns[n])
            col1 = split.column(align=True)
            col2 = split.column(align=True)
            cols.append(col1)
        cols.append(col2)

        return cols

    def draw_buttons(self, context, layout):
        row = layout.column().row()
        cols = self.split_columns(row, [1, 1], [True, True])

        cols[0].prop(self, "tu_axes", text="")
        cols[1].prop(self, "tu_mapping", text="")

    def draw_buttons_ext(self, context, layout):
        layout.prop(self, "normalize")

    def orthogonalizeXY(self, X, Y):  # keep X, recalculate Z form X&Y then Y
        Z = X.cross(Y)
        Y = Z.cross(X)
        return X, Y, Z

    def orthogonalizeXZ(self, X, Z):  # keep X, recalculate Y form Z&X then Z
        Y = Z.cross(X)
        Z = X.cross(Y)
        return X, Y, Z

    def orthogonalizeYX(self, Y, X):  # keep Y, recalculate Z form X&Y then X
        Z = X.cross(Y)
        X = Y.cross(Z)
        return X, Y, Z

    def orthogonalizeYZ(self, Y, Z):  # keep Y, recalculate X form Y&Z then Z
        X = Y.cross(Z)
        Z = X.cross(Y)
        return X, Y, Z

    def orthogonalizeZX(self, Z, X):  # keep Z, recalculate Y form Z&X then X
        Y = Z.cross(X)
        X = Y.cross(Z)
        return X, Y, Z

    def orthogonalizeZY(self, Z, Y):  # keep Z, recalculate X form Y&Z then Y
        X = Y.cross(Z)
        Y = Z.cross(X)
        return X, Y, Z

    def orthogonalizer(self):
        order = self.tu_axes.replace(" ", "")
        orthogonalizer = eval("self.orthogonalize" + order)
        return lambda T, U: orthogonalizer(T, U)

    def process(self):
        outputs = self.outputs

        # return if no outputs are connected
        if not any(s.is_linked for s in outputs):
            return

        # input values lists
        inputs = self.inputs
        input_locations = inputs["Location"].sv_get()[0]
        input_scales = inputs["Scale"].sv_get()[0]
        input_vAs = inputs["A"].sv_get()[0]
        input_vBs = inputs["B"].sv_get()[0]

        locations = [Vector(i) for i in input_locations]
        scales = [Vector(i) for i in input_scales]
        vAs = [Vector(i) for i in input_vAs]
        vBs = [Vector(i) for i in input_vBs]

        params = match_long_repeat([locations, scales, vAs, vBs])

        orthogonalize = self.orthogonalizer()

        mT, mU = self.tu_mapping.split(" ")

        xList = []  # ortho-normal X vector list
        yList = []  # ortho-normal Y vector list
        zList = []  # ortho-normal Z vector list
        matrixList = []
        for L, S, A, B in zip(*params):
            T = eval(mT)  # map T to one of A, B or its negative
            U = eval(mU)  # map U to one of A, B or its negative

            X, Y, Z = orthogonalize(T, U)

            if self.normalize:
                X.normalize()
                Y.normalize()
                Z.normalize()

            # prepare the Ortho-Normalized outputs
            if outputs["X"].is_linked:
                xList.append([X.x, X.y, X.z])
            if outputs["Y"].is_linked:
                yList.append([Y.x, Y.y, Y.z])
            if outputs["Z"].is_linked:
                zList.append([Z.x, Z.y, Z.z])

            # composite matrix: M = T * R * S (Tanslation x Rotation x Scale)
            m = [[X.x * S.x, Y.x * S.y, Z.x * S.z, L.x],
                 [X.y * S.x, Y.y * S.y, Z.y * S.z, L.y],
                 [X.z * S.x, Y.z * S.y, Z.z * S.z, L.z], [0, 0, 0, 1]]

            matrixList.append(Matrix(m))

        outputs["Matrix"].sv_set(matrixList)
        outputs["X"].sv_set([xList])
        outputs["Y"].sv_set([yList])
        outputs["Z"].sv_set([zList])
示例#9
0
class SvMatrixTrackToNode(bpy.types.Node, SverchCustomTreeNode):
    """
    Triggers: Align to Track & Up vectors
    Tooltip:  Construct a Matrix from arbitrary Track and Up vectors

    """

    bl_idname = 'SvMatrixTrackToNode'
    bl_label = 'Matrix Track To'
    bl_icon = 'OUTLINER_OB_EMPTY'
    sv_icon = 'SV_MATRIX_TRACK_TO'

    TUA = ["X Y", "X Z", "Y X", "Y Z", "Z X", "Z Y"]
    tu_axes: EnumProperty(
        name="Track/Up Axes",
        description=
        "Select which two of the XYZ axes to be the Track and Up axes",
        items=e(TUA),
        default="X_Y",
        update=updateNode)

    normalize: BoolProperty(name="Normalize Vectors",
                            description="Normalize the output X,Y,Z vectors",
                            default=True,
                            update=updateNode)

    origin: FloatVectorProperty(
        name='Location',
        description="The location component of the output matrix",
        default=(0, 0, 0),
        update=updateNode)

    scale: FloatVectorProperty(
        name='Scale',
        description="The scale component of the output matrix",
        default=(1, 1, 1),
        update=updateNode)

    vA: FloatVectorProperty(name='A',
                            description="A direction",
                            default=(1, 0, 0),
                            update=updateNode)

    vB: FloatVectorProperty(name='B',
                            description='B direction',
                            default=(0, 1, 0),
                            update=updateNode)
    flat_output: BoolProperty(
        name="Flat output",
        description="Flatten output by list-joining level 1",
        default=True,
        update=updateNode)
    TUM = ["A B", "A -B", "-A B", "-A -B", "B A", "B -A", "-B A", "-B -A"]
    tu_mapping: EnumProperty(
        name="Track/Up Mapping",
        description=
        "Map the Track and Up vectors to one of the two inputs or their negatives",
        items=e(TUM),
        default="A_B",
        update=updateNode)

    def sv_init(self, context):
        self.inputs.new('SvVerticesSocket',
                        "Location").prop_name = "origin"  # L
        self.inputs.new('SvVerticesSocket', "Scale").prop_name = "scale"  # S
        self.inputs.new('SvVerticesSocket', "A").prop_name = "vA"  # A
        self.inputs.new('SvVerticesSocket', "B").prop_name = "vB"  # B
        self.outputs.new('SvMatrixSocket', "Matrix")
        self.outputs.new('SvVerticesSocket', "X")
        self.outputs.new('SvVerticesSocket', "Y")
        self.outputs.new('SvVerticesSocket', "Z")

    def split_columns(self, panel, ratios, aligns):
        """
        Splits the given panel into columns based on the given set of ratios.
        e.g ratios = [1, 2, 1] or [.2, .3, .2] etc
        Note: The sum of all ratio numbers doesn't need to be normalized
        """
        col2 = panel
        cols = []
        ns = len(ratios) - 1  # number of splits
        for n in range(ns):
            n1 = ratios[n]  # size of the current column
            n2 = sum(ratios[n + 1:])  # size of all remaining columns
            p = n1 / (n1 + n2
                      )  # percentage split of current vs remaning columns
            # print("n = ", n, " n1 = ", n1, " n2 = ", n2, " p = ", p)
            split = col2.split(factor=p, align=aligns[n])
            col1 = split.column(align=True)
            col2 = split.column(align=True)
            cols.append(col1)
        cols.append(col2)

        return cols

    def draw_buttons(self, context, layout):
        row = layout.column().row()
        cols = self.split_columns(row, [1, 1], [True, True])

        cols[0].prop(self, "tu_axes", text="")
        cols[1].prop(self, "tu_mapping", text="")

    def draw_buttons_ext(self, context, layout):
        self.draw_buttons(context, layout)
        layout.prop(self, "normalize")
        layout.prop(self, "flat_output")

    def rclick_menu(self, context, layout):
        layout.prop_menu_enum(self, "tu_axes")
        layout.prop_menu_enum(self, "tu_mapping")
        layout.prop(self, "normalize")
        layout.prop(self, "flat_output", text="Flat Output", expand=False)

    def orthogonalizeXY(self, X, Y):  # keep X, recalculate Z form X&Y then Y
        Z = X.cross(Y)
        Y = Z.cross(X)
        return X, Y, Z

    def orthogonalizeXZ(self, X, Z):  # keep X, recalculate Y form Z&X then Z
        Y = Z.cross(X)
        Z = X.cross(Y)
        return X, Y, Z

    def orthogonalizeYX(self, Y, X):  # keep Y, recalculate Z form X&Y then X
        Z = X.cross(Y)
        X = Y.cross(Z)
        return X, Y, Z

    def orthogonalizeYZ(self, Y, Z):  # keep Y, recalculate X form Y&Z then Z
        X = Y.cross(Z)
        Z = X.cross(Y)
        return X, Y, Z

    def orthogonalizeZX(self, Z, X):  # keep Z, recalculate Y form Z&X then X
        Y = Z.cross(X)
        X = Y.cross(Z)
        return X, Y, Z

    def orthogonalizeZY(self, Z, Y):  # keep Z, recalculate X form Y&Z then Y
        X = Y.cross(Z)
        Y = Z.cross(X)
        return X, Y, Z

    def orthogonalizer(self):
        order = self.tu_axes.replace("_", "")
        orthogonalizer = eval("self.orthogonalize" + order)
        return lambda T, U: orthogonalizer(T, U)

    def matrix_track_to(self, params, mT, mU, orthogonalize, gates):
        x_list = []  # ortho-normal X vector list
        y_list = []  # ortho-normal Y vector list
        z_list = []  # ortho-normal Z vector list
        matrix_list = []
        print(len(params))
        for L, S, A, B in zip(*params):
            T = eval(mT)  # map T to one of A, B or its negative
            U = eval(mU)  # map U to one of A, B or its negative

            X, Y, Z = orthogonalize(T, U)

            if gates[4]:
                X.normalize()
                Y.normalize()
                Z.normalize()

            # prepare the Ortho-Normalized outputs
            if gates[1]:
                x_list.append([X.x, X.y, X.z])
            if gates[2]:
                y_list.append([Y.x, Y.y, Y.z])
            if gates[3]:
                z_list.append([Z.x, Z.y, Z.z])
            if gates[0]:
                # composite matrix: M = T * R * S (Tanslation x Rotation x Scale)
                m = [[X.x * S.x, Y.x * S.y, Z.x * S.z, L.x],
                     [X.y * S.x, Y.y * S.y, Z.y * S.z, L.y],
                     [X.z * S.x, Y.z * S.y, Z.z * S.z, L.z], [0, 0, 0, 1]]

                matrix_list.append(Matrix(m))

        return matrix_list, x_list, y_list, z_list

    def process(self):
        outputs = self.outputs

        # return if no outputs are connected
        if not any(s.is_linked for s in outputs):
            return

        # input values lists
        inputs = self.inputs
        params = match_long_repeat(
            [Vector_generate(s.sv_get()) for s in inputs])
        orthogonalize = self.orthogonalizer()

        mT, mU = self.tu_mapping.split("_")
        gates = [s.is_linked for s in outputs]
        gates.append(self.normalize)
        x_lists = []  # ortho-normal X vector list
        y_lists = []  # ortho-normal Y vector list
        z_lists = []  # ortho-normal Z vector list
        matrix_lists = []
        if self.flat_output:
            m_add, x_add, y_add, z_add = matrix_lists.extend, x_lists.extend, y_lists.extend, z_lists.extend
        else:
            m_add, x_add, y_add, z_add = matrix_lists.append, x_lists.append, y_lists.append, z_lists.append
        for par in zip(*params):
            matrix_list, x_list, y_list, z_list = self.matrix_track_to(
                match_long_repeat(par), mT, mU, orthogonalize, gates)
            m_add(matrix_list)
            x_add([x_list])
            y_add(y_list)
            z_add(z_list)

        outputs["Matrix"].sv_set(matrix_lists)
        outputs["X"].sv_set(x_lists)
        outputs["Y"].sv_set(y_lists)
        outputs["Z"].sv_set(z_lists)
示例#10
0
class SvBMOpsNodeMK2(bpy.types.Node, SverchCustomTreeNode):
    ''' BMesh Ops '''
    bl_idname = 'SvBMOpsNodeMK2'
    bl_label = 'BMesh Ops 2'
    bl_icon = 'OUTLINER_OB_EMPTY'
    sv_icon = 'SV_BMESH_OPS'

    PV = [
        'remove_doubles(bm,verts=e,dist=v[0])',
        'collapse(bm,edges=e,uvs=v[0])',
        'unsubdivide(bm,verts=e,iterations=v[0])',
        'holes_fill(bm,edges=e,sides=v[0])',
        'dissolve_faces(bm,faces=e,use_verts=v[0])',
        'connect_verts_concave(bm,faces=e)',
        'recalc_face_normals(bm,faces=e)',
        'rotate_edges(bm,edges=e,use_ccw=v[0])',
        'connect_verts_nonplanar(bm,angle_limit=v[0],faces=e)',
        'triangulate(bm,faces=e,quad_method=v[0],ngon_method=v[1])',
        'dissolve_edges(bm,edges=e,use_verts=v[0],use_face_split=v[1])',
        'dissolve_verts(bm,verts=e,use_face_split=v[0],use_boundary_tear=v[1])',
        'grid_fill(bm,edges=e,mat_nr=v[0],use_smooth=v[1],use_interp_simple=v[2])',
        'poke(bm,faces=e,offset=v[0],center_mode=v[1],use_relative_offset=v[2])',
        'bridge_loops(bm,edges=e,use_pairs=v[0],use_cyclic=v[1],use_merge=v[2],merge_factor=v[3],twist_offset=v[4])',
        'smooth_vert(bm,verts=e,factor=v[0],mirror_clip_x=v[1],mirror_clip_y=v[2],mirror_clip_z=v[3],clip_dist=v[4],use_axis_x=v[5],use_axis_y=v[6],use_axis_z=v[7])',
        'join_triangles(bm,faces=e,cmp_seam=v[0],cmp_sharp=v[1],cmp_uvs=v[2],cmp_vcols=v[3],cmp_materials=v[4],angle_face_threshold=v[5],angle_shape_threshold=v[6])',
        'subdivide_edgering(bm,edges=e,interp_mode=v[0],smooth=v[1],cuts=v[2],profile_shape=v[3],profile_shape_factor=v[4])',
        'inset_individual(bm,faces=e,thickness=v[0],depth=v[1],use_even_offset=v[2],use_interpolate=v[3],use_relative_offset=v[4])',
        'inset_region(bm,faces=e,use_boundary=v[0],use_even_offset=v[1],use_interpolate=v[2],use_relative_offset=v[3],use_edge_rail=v[4],thickness=v[5],depth=v[6],use_outset=v[7])',
    ]

    oper: EnumProperty(name="BMop",
                       default=PV[0],
                       items=e(PV),
                       update=updateNode)

    V0: FloatProperty(name='V0', default=0, update=updateNode)
    V1: FloatProperty(name='V1', default=0, update=updateNode)
    V2: FloatProperty(name='V2', default=0, update=updateNode)
    V3: FloatProperty(name='V3', default=0, update=updateNode)
    V4: FloatProperty(name='V4', default=0, update=updateNode)
    V5: FloatProperty(name='V5', default=0, update=updateNode)
    V6: FloatProperty(name='V6', default=0, update=updateNode)
    V7: FloatProperty(name='V7', default=0, update=updateNode)

    def sv_init(self, context):
        si = self.inputs.new
        si('SvStringsSocket', 'bmesh_list')
        si('SvStringsSocket', 'BM_element(e)')
        self.outputs.new('SvStringsSocket', 'bmesh_list')

    def draw_buttons(self, context, layout):
        layout.prop(self, "oper", text="Get")
        for i in range(self.oper.count("=v[")):
            layout.prop(self, "V" + str(i), text="v" + str(i))

    def process(self):
        if not self.outputs['bmesh_list'].is_linked:
            return
        bml, e = self.inputs
        obj = bml.sv_get()
        v = [
            self.V0, self.V1, self.V2, self.V3, self.V4, self.V5, self.V6,
            self.V7
        ]
        outp = []
        op = "bmesh.ops." + self.oper
        if e.is_linked:
            element = e.sv_get()
            for bm, e in zip(obj, element):
                exec(op)
                outp.append(bm.copy())
                bm.free()
        else:
            if "verts=e" in op:
                cur = "verts"
            elif "edges=e" in op:
                cur = "edges"
            elif "faces=e" in op:
                cur = "faces"
            for bm in obj:
                e = getattr(bm, cur)
                exec(op)
                outp.append(bm.copy())
                bm.free()
        self.outputs['bmesh_list'].sv_set(outp)
示例#11
0
class SvBMOpsNode(bpy.types.Node, SverchCustomTreeNode):
    ''' BMesh Ops '''
    bl_idname = 'SvBMOpsNode'
    bl_label = 'bmesh_ops'
    bl_icon = 'OUTLINER_OB_EMPTY'

    PV = [
        'remove_doubles(bm,verts=Vidx,dist=v[0])', 'collapse(bm,edges=Eidx)',
        'unsubdivide(bm,verts=Vidx,iterations=v[0])',
        'holes_fill(bm,edges=Eidx,sides=v[0])',
        'bridge_loops(bm,edges=Eidx,use_pairs=b[0],use_cyclic=b[1],use_merge=b[2],merge_factor=v[0],twist_offset=v[1])',
        'smooth_vert(bm,verts=Vidx,factor=v[0],mirror_clip_x=b[0],mirror_clip_y=b[1],mirror_clip_z=b[2],clip_dist=v[1],use_axis_x=b[3],use_axis_y=b[4],use_axis_z=b[5])',
        'dissolve_verts(bm,verts=Vidx,use_face_split=b[0],use_boundary_tear=b[1])',
        'dissolve_edges(bm,edges=Eidx,use_verts=b[0],use_face_split=b[1])',
        'dissolve_faces(bm,faces=Pidx,use_verts=b[0])',
        'triangulate(bm,faces=Pidx,quad_method=v[0],ngon_method=v[1])',
        'join_triangles(bm,faces=Pidx,cmp_sharp=b[0],cmp_uvs=b[1],cmp_vcols=b[2],cmp_materials=b[3],limit=v[0])',
        'connect_verts_concave(bm,faces=Pidx)',
        'connect_verts_nonplanar(bm,angle_limit=v[0],faces=Pidx)',
        'subdivide_edgering(bm,edges=Eidx,interp_mode=v[0],smooth=v[1],cuts=v[2],profile_shape=v[3],profile_shape_factor=v[4])',
        'inset_individual(bm,faces=Pidx,thickness=v[0],depth=v[1],use_even_offset=b[0],use_interpolate=b[1],use_relative_offset=b[2])',
        'grid_fill(bm,edges=Eidx,mat_nr=v[0],use_smooth=b[0],use_interp_simple=b[1])',
        'edgenet_fill(bm, edges=Eidx, mat_nr=v[0], use_smooth=b[0], sides=v[1])',
        'rotate_edges(bm, edges=Eidx, use_ccw=b[0])'
    ]

    oper = EnumProperty(name="BMop",
                        default=PV[0],
                        items=e(PV),
                        update=updateNode)

    def sv_init(self, context):
        si = self.inputs.new
        si('StringsSocket', 'Objects')
        si('StringsSocket', 'Value(v)')
        si('StringsSocket', 'Bool(b)')
        si('StringsSocket', 'idx')
        self.outputs.new('VerticesSocket', 'Verts')
        self.outputs.new('StringsSocket', 'Edges')
        self.outputs.new('StringsSocket', 'Polys')

    def draw_buttons(self, context, layout):
        layout.prop(self, "oper", "Get")

    def process(self):
        if not self.outputs['Verts'].is_linked:
            return
        si = self.inputs
        obj = si['Objects'].sv_get()
        obl = len(obj)
        if obl > 1:
            b = (si['Bool(b)'].sv_get([[0, 0, 0, 0, 0, 0]]) * obl)[:obl]
            v = (si['Value(v)'].sv_get([[1, 1, 1, 1, 1]]) * obl)[:obl]
            idx = (si['idx'].sv_get([[0]]) * obl)[:obl]
        else:
            b = si['Bool(b)'].sv_get([[0, 0, 0, 0, 0, 0]])
            v = si['Value(v)'].sv_get([[1, 1, 1, 1, 1]])
            idx = si['idx'].sv_get([[0]])
        Sidx = si['idx'].is_linked
        outv = []
        oute = []
        outp = []
        op = "bmesh.ops." + self.oper
        if "verts=Vidx" in op:
            cur = 1
        elif "edges=Eidx" in op:
            cur = 2
        elif "faces=Pidx" in op:
            cur = 3
        for ob, b, v, idx in zip(obj, b, v, idx):
            bm = bmesh.new()
            bm.from_mesh(ob.data)
            if Sidx:
                if cur == 1:
                    bm.verts.ensure_lookup_table()
                    Vidx = [bm.verts[i] for i in idx]
                elif cur == 2:
                    bm.edges.ensure_lookup_table()
                    Eidx = [bm.edges[i] for i in idx]
                elif cur == 3:
                    bm.faces.ensure_lookup_table()
                    Pidx = [bm.faces[i] for i in idx]
            else:
                Vidx, Eidx, Pidx = bm.verts, bm.edges, bm.faces
            exec(op)
            outv.append([i.co[:] for i in bm.verts])
            oute.append([[i.index for i in e.verts] for e in bm.edges])
            outp.append([[i.index for i in p.verts] for p in bm.faces])
            bm.free()
        self.outputs['Verts'].sv_set(outv)
        self.outputs['Edges'].sv_set(oute)
        self.outputs['Polys'].sv_set(outp)

    def update_socket(self, context):
        self.update()
示例#12
0
class SvBMVertsNode(bpy.types.Node, SverchCustomTreeNode):
    ''' BMesh Verts '''
    bl_idname = 'SvBMVertsNode'
    bl_label = 'bmesh_props'
    bl_icon = 'OUTLINER_OB_EMPTY'

    Modes = ['verts', 'faces', 'edges']
    Mod = EnumProperty(name="getmodes",
                       default="verts",
                       items=e(Modes),
                       update=updateNode)
    a = ['hide', 'select']
    PV = a + [
        'is_manifold', 'is_wire', 'is_boundary', 'calc_shell_factor()',
        'calc_edge_angle(-1)'
    ]
    PF = a + ['calc_area()', 'calc_perimeter()', 'material_index', 'smooth']
    PE = a + [
        'calc_face_angle()', 'calc_face_angle_signed()', 'calc_length()',
        'is_boundary', 'is_contiguous', 'is_convex', 'is_manifold', 'is_wire',
        'seam'
    ]
    verts = EnumProperty(name="Vprop",
                         default="is_manifold",
                         items=e(PV),
                         update=updateNode)
    faces = EnumProperty(name="Fprop",
                         default="select",
                         items=e(PF),
                         update=updateNode)
    edges = EnumProperty(name="Eprop",
                         default="select",
                         items=e(PE),
                         update=updateNode)

    def sv_init(self, context):
        si = self.inputs.new
        si('StringsSocket', 'Objects')
        si('VerticesSocket', 'Vert')
        si('StringsSocket', 'Edge')
        si('StringsSocket', 'Poly')
        self.outputs.new('StringsSocket', 'Value')

    def draw_buttons(self, context, layout):
        layout.prop(self, "Mod", "Get")
        layout.prop(self, self.Mod, "")

    def process(self):
        Val = []
        siob = self.inputs['Objects']
        v, e, p = self.inputs['Vert'], self.inputs['Edge'], self.inputs['Poly']
        if siob.is_linked:
            obj = siob.sv_get()
            for OB in obj:
                bm = bmesh.new()
                bm.from_mesh(OB.data)
                get_value(self, bm, Val)
                bm.free()
        if v.is_linked:
            sive, sied, sipo = match_long_repeat(
                [v.sv_get(), e.sv_get([[]]),
                 p.sv_get([[]])])
            for i in zip(sive, sied, sipo):
                bm = bmesh_from_pydata(i[0], i[1], i[2])
                get_value(self, bm, Val)
                bm.free()
        self.outputs['Value'].sv_set(Val)

    def update_socket(self, context):
        self.update()
class SvGetAssetPropertiesMK2(bpy.types.Node, SverchCustomTreeNode,
                              SvAnimatableNode):
    ''' Get Asset Props '''
    bl_idname = 'SvGetAssetPropertiesMK2'
    bl_label = 'Object ID Selector+'
    bl_icon = 'SELECT_SET'
    sv_icon = 'SV_OBJECT_ID_SELECTOR'

    def type_filter(self, object):
        return object.type == self.Type

    def frame_updateNode(self, context):
        ''' must rebuild for each update'''
        self.frame_collection_name.clear()

        if not (self.gp_pointer and self.gp_layer):
            return

        layer_ref = self.gp_pointer.layers.get(self.gp_layer)
        if not layer_ref:
            return

        for idx, f in enumerate(layer_ref.frames):
            self.frame_collection_name.add().name = str(idx) + ' | ' + str(
                f.frame_number)

        # updateNode(self, context)
        if self.gp_selected_frame_mode == 'active_frame':
            if len(self.inputs) == 0:
                self.inputs.new("SvStringsSocket", 'frame#')
        else:
            if len(self.inputs) > 0:
                self.inputs.remove(self.inputs[-1])

        self.process()

    type_collection_name: bpy.props.CollectionProperty(
        type=bpy.types.PropertyGroup)
    frame_collection_name: bpy.props.CollectionProperty(
        type=bpy.types.PropertyGroup)

    M = [
        'actions', 'brushes', 'filepath', 'grease_pencils', 'groups', 'images',
        'libraries', 'linestyles', 'masks', 'materials', 'movieclips',
        'node_groups', 'particles', 'scenes', 'screens', 'shape_keys',
        'sounds', 'speakers', 'texts', 'textures', 'worlds', 'objects'
    ]

    T = [
        'MESH', 'CURVE', 'SURFACE', 'META', 'FONT', 'ARMATURE', 'GPENCIL',
        'LATTICE', 'EMPTY', 'CAMERA', 'LIGHT', 'SPEAKER'
    ]

    Mode: EnumProperty(name="get modes",
                       default="objects",
                       items=e(M),
                       update=updateNode)
    Type: EnumProperty(name="get types",
                       default="MESH",
                       items=e(T),
                       update=updateNode)

    properties_to_skip_iojson: [
        "object_pointer", "image_pointer", "text_pointer"
    ]

    text_pointer: PointerProperty(type=bpy.types.Text,
                                  poll=lambda s, o: True,
                                  update=updateNode)
    object_pointer: PointerProperty(type=bpy.types.Object,
                                    poll=type_filter,
                                    update=updateNode)
    image_pointer: PointerProperty(type=bpy.types.Image,
                                   poll=lambda s, o: True,
                                   update=updateNode)
    pass_pixels: bpy.props.BoolProperty(update=updateNode)

    # GP props
    gp_pointer: PointerProperty(type=bpy.types.GreasePencil,
                                poll=lambda s, o: True,
                                update=updateNode)
    # i can't get this to work. so am revering to StringProperty for gp_layer.
    # gp_layer_pointer: PointerProperty(type=bpy.types.GreasePencilLayers, poll=lambda s, o: True, update=updateNode) # <---- no?
    gp_layer: bpy.props.StringProperty(update=updateNode)
    gp_frame_current: bpy.props.BoolProperty(default=True, update=updateNode)
    gp_frame_override: bpy.props.IntProperty(default=1, update=updateNode)
    gp_stroke_idx: bpy.props.IntProperty(update=updateNode)

    gp_frame_mode_options = [
        (no_space(k), k, '', i)
        for i, k in enumerate(["pick frame", "active frame"])
    ]
    gp_selected_frame_mode: bpy.props.EnumProperty(
        items=gp_frame_mode_options,
        description="offers choice between current frame or available frames",
        default="pick_frame",
        update=frame_updateNode)
    gp_frame_pick: bpy.props.StringProperty(update=frame_updateNode)
    gp_pass_points: bpy.props.BoolProperty(default=True, update=updateNode)

    def draw_gp_options(self, context, layout):
        layout.prop_search(self,
                           'gp_pointer',
                           bpy.data,
                           'grease_pencils',
                           text='name')
        if not self.gp_pointer:
            return

        layout.prop_search(self,
                           'gp_layer',
                           self.gp_pointer,
                           'layers',
                           text='layer')
        layer_ref = self.gp_pointer.layers.get(self.gp_layer)
        if not layer_ref:
            return

        layout.prop(self, 'gp_selected_frame_mode', expand=True)
        frame_data = None
        if self.gp_selected_frame_mode == 'active_frame':
            frame_data = layer_ref.active_frame
        else:
            # maybe display uilist with frame_index and frame_nmber.
            layout.prop_search(self, 'gp_frame_pick', self,
                               'frame_collection_name')
        layout.prop(self, 'gp_pass_points', text='pass points')

    def process_mode_grease_pencils(self):
        data_list = bpy.data.grease_pencils
        if not (self.gp_pointer and self.gp_layer):
            return data_list[:]

        layer_ref = self.gp_pointer.layers.get(self.gp_layer)
        if not layer_ref:
            return data_list[:]

        if self.gp_selected_frame_mode == 'active_frame':
            if len(self.inputs) > 0 and self.inputs[0].is_linked:

                frame_number = self.inputs[0].sv_get()[0][0]
                key = frame_from_available2(frame_number, layer_ref)
                strokes = layer_ref.frames[key].strokes
            else:
                strokes = layer_ref.active_frame.strokes

            if not strokes:
                return []

            if self.gp_pass_points:
                return [[p.co[:] for p in s.points] for s in strokes]
            else:
                return strokes
        else:
            if self.gp_frame_pick:
                idx_from_frame_pick = int(self.gp_frame_pick.split(' | ')[0])
                frame_data = layer_ref.frames[idx_from_frame_pick]
                if frame_data:
                    if self.gp_pass_points:
                        return [[p.co[:] for p in s.points]
                                for s in frame_data.strokes]
                    else:
                        return frame_data.strokes

    def process_mode_objects(self):
        data_list = bpy.data.objects
        if self.object_pointer:
            return [self.object_pointer]
        else:
            return [i for i in data_list if i.type == self.Type]

    def process_mode_texts(self):
        data_list = bpy.data.texts
        if self.text_pointer:
            return [[self.text_pointer.as_string()]]
        else:
            return data_list[:]

    def process_mode_images(self):
        data_list = bpy.data.images
        if self.image_pointer:
            if self.pass_pixels:
                return [[self.image_pointer.pixels[:]],
                        self.image_pointer.size[:]]
            else:
                return [self.image_pointer]
        else:
            return data_list[:]

    def draw_buttons(self, context, layout):
        # layout.operator('node.'   ,text='refresh from scene')
        self.draw_animatable_buttons(layout, icon_only=True)
        layout.row().prop(self, "Mode", text="data")

        if self.Mode == 'objects':
            layout.prop(self, "Type", text="type")
            layout.prop_search(self,
                               'object_pointer',
                               bpy.data,
                               'objects',
                               text='name',
                               icon='OBJECT_DATA')
        elif self.Mode == 'texts':
            layout.prop_search(self,
                               'text_pointer',
                               bpy.data,
                               'texts',
                               text='name')
        elif self.Mode == 'images':
            layout.prop_search(self,
                               'image_pointer',
                               bpy.data,
                               'images',
                               text='name')
            if self.image_pointer and self.image_pointer.name:
                layout.prop(self, 'pass_pixels', text='pixels')
                layout.label(text=f"dimensions: {self.image_pointer.size[:]}")
        elif self.Mode == 'grease_pencils':
            self.draw_gp_options(context, layout)
        else:
            col = layout.column()
            col.alert = True
            col.label(text=f"This node is not yet programmed to do")
            col.label(text=f"anything sensible with bpy.data.{self.Mode}")

    def sv_init(self, context):
        self.outputs.new('SvStringsSocket', "Objects")
        self.width = 210

    def process(self):
        output_socket = self.outputs['Objects']
        if not output_socket.is_linked:
            return

        if self.Mode in {'objects', 'texts', 'images', 'grease_pencils'}:
            data_output = getattr(self, f"process_mode_{self.Mode}")()
        else:
            data_list = getattr(bpy.data, self.Mode)
            data_output = data_list[:]

        output_socket.sv_set(data_output)
示例#14
0
class SvDupliInstancesLite(bpy.types.Node, SverchCustomTreeNode, SvViewerNode):
    """
    Triggers: Fast duplication
    Tooltip: Create Instances from parent object + child
    """
    bl_idname = 'SvDupliInstancesLite'
    bl_label = 'Dupli Instancer Lite'
    bl_icon = 'OUTLINER_OB_EMPTY'
    sv_icon = 'SV_DUPLI_INSTANCER'

    def update_sockets(self, context):
        if self.mode == 'FACES' and self.scale:
            self.inputs['Scale'].hide_safe = False
        else:
            self.inputs['Scale'].hide_safe = True
        updateNode(self, context)

    scale: BoolProperty(default=False,
                        description="scale children",
                        update=update_sockets)
    scale_factor: FloatProperty(default=1,
                                name='Scale',
                                description="Children scale factor",
                                update=updateNode)
    align: BoolProperty(default=False,
                        description="align with vertex normal",
                        update=updateNode)

    show_instancer_for_viewport: BoolProperty(
        default=False,
        description="Show instancer in viewport",
        update=updateNode)
    show_instancer_for_render: BoolProperty(
        default=False,
        description="Show instancer in render",
        update=updateNode)

    show_base_child: BoolProperty(name='Show base child',
                                  default=True,
                                  description="Hide base object in viewport",
                                  update=updateNode)

    auto_release: BoolProperty(
        name='Auto Release',
        description='Remove childs not called by this node',
        update=updateNode)

    modes = [("VERTS", "Verts", "On vertices. Only Translation is used", "",
              1),
             ("FACES", "Polys",
              "On polygons. Translation, Rotation and Scale supported", "", 2)]
    T = [
        ("POS_X", "X", "", "", 1),
        ("POS_Y", "Y", "", "", 2),
        ("POS_Z", "Z", "", "", 3),
        ("NEG_X", "-X", "", "", 4),
        ("NEG_Y", "-Y", "", "", 5),
        ("NEG_Z", "-Z", "", "", 6),
    ]

    mode: EnumProperty(name='Mode',
                       items=modes,
                       default='VERTS',
                       update=update_sockets)

    U = ['X', 'Y', 'Z']

    track: EnumProperty(name="track",
                        default=T[0][0],
                        items=T,
                        update=updateNode)
    up: EnumProperty(name="up", default=U[2], items=e(U), update=updateNode)

    def sv_init(self, context):
        self.width = 160
        self.inputs.new("SvObjectSocket", "Parent")
        self.inputs.new("SvObjectSocket", "Child")
        self.sv_new_input("SvStringsSocket",
                          "Scale",
                          hide_safe=True,
                          prop_name='scale_factor')
        self.outputs.new("SvObjectSocket", "Parent")
        self.outputs.new("SvObjectSocket", "Child")

    def draw_buttons(self, context, layout):
        layout.row(align=True).prop(self, "mode", expand=True)
        col = layout.column(align=True)
        row = col.row(align=True)
        row.label(text='Instancer')
        row.prop(
            self,
            'show_instancer_for_viewport',
            text='',
            toggle=True,
            icon=
            f"RESTRICT_VIEW_{'OFF' if self.show_instancer_for_viewport else 'ON'}"
        )
        row.prop(
            self,
            'show_instancer_for_render',
            text='',
            toggle=True,
            icon=
            f"RESTRICT_RENDER_{'OFF' if self.show_instancer_for_render else 'ON'}"
        )

        row = col.row(align=True)
        row.label(text='Child')
        row.prop(self,
                 'show_base_child',
                 text='',
                 toggle=True,
                 icon=f"HIDE_{'OFF' if self.show_base_child else 'ON'}")
        if self.mode == 'FACES':
            row.prop(self,
                     'scale',
                     text='',
                     icon_value=custom_icon('SV_SCALE'),
                     toggle=True)
        else:
            row.prop(self,
                     'align',
                     text='',
                     icon='MOD_NORMALEDIT',
                     toggle=True)

        row.prop(self, 'auto_release', text='', toggle=True, icon='UNLINKED')
        if self.mode == 'VERTS' and self.align:
            layout.prop(self, 'track')
            layout.prop(self, 'up')

    def set_parent_props(self, parent, scale):
        parent.instance_type = self.mode
        parent.use_instance_vertices_rotation = self.align
        parent.use_instance_faces_scale = self.scale
        parent.show_instancer_for_viewport = self.show_instancer_for_viewport
        parent.show_instancer_for_render = self.show_instancer_for_render
        parent.instance_faces_scale = scale

    def set_child_props(self, parent, child):
        child.parent = parent
        child.track_axis = self.track
        child.up_axis = self.up
        child.hide_set(not self.show_base_child)

    def process(self):
        print(True)
        parent_objects = self.inputs['Parent'].sv_get(deepcopy=False)
        child_objects = self.inputs['Child'].sv_get(deepcopy=False)
        scale = self.inputs['Scale'].sv_get(deepcopy=False)
        if not child_objects or not parent_objects:
            return

        if len(parent_objects) == 1 or len(child_objects) == 1:
            parent = parent_objects[0]
            self.set_parent_props(parent, scale[0][0])
            childs_name = []
            for child in child_objects:
                self.set_child_props(parent, child)
                childs_name.append(child.name)
            if self.auto_release:
                auto_release(parent.name, childs_name)
        else:
            childs_name = {p.name: [] for p in parent_objects}
            if len(scale) == 1:
                scale_f = scale[0]
            else:
                scale_f = [sc[0] for sc in scale]
            for child, parent, sc in zip(child_objects, cycle(parent_objects),
                                         cycle(scale_f)):
                self.set_parent_props(parent, sc)
                self.set_child_props(parent, child)
                childs_name[parent.name].append(child.name)
            if self.auto_release:
                for p in parent_objects:
                    auto_release(p.name, childs_name[p.name])

        self.outputs['Parent'].sv_set(parent_objects)
        self.outputs['Child'].sv_set(child_objects)