Skip to content
Snippets Groups Projects
mesh_ktools.py 99.1 KiB
Newer Older
  • Learn to ignore specific revisions
  •                         for key, value in edge_dic.items():
                                if value[0] in end_verts:
                                    sel.remove(key)
                                    continue
                                if value[1] in end_verts:
                                    sel.remove(key)
    
    
                            bmesh.update_edit_mesh(me, True, False)
    
                            # Select the resulting edges
                            bpy.ops.mesh.select_all(action='DESELECT')
                            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    
                            for e in sel:
                                mesh.edges[e].select = True
                            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    
                            bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
                            bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
    
                            bm = bmesh.from_edit_mesh(me)
    
                            # Store current faces
                            for f in bm.faces:
                                if f.select:
                                    cur_faces.append(f.index)
    
                            # Compare current and original faces
                            for x in org_faces:
                                if x in cur_faces:
                                    new_faces.append(x)
    
                            bmesh.update_edit_mesh(me, True, False)
    
                            # Select the resulting faces
                            bpy.ops.mesh.select_all(action='DESELECT')
                            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
    
                            for e in new_faces:
                                mesh.polygons[e].select = True
                            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    
                        else:
                            me = bpy.context.object.data
                            bm = bmesh.from_edit_mesh(me)
    
                            sel = []
                            edge_dic = {}
                            vert_list = []
                            end_verts = []
    
                            # Store edges and verts in dictionary
                            for e in bm.edges:
                                if e.select:
                                    sel.append(e.index)
    
                                    # Populate vert_list
                                    vert_list.append(e.verts[0].index)
                                    vert_list.append(e.verts[1].index)
    
                                    # Store dictionary
                                    edge_dic[e.index] = [e.verts[0].index, e.verts[1].index]
    
                            # Store end verts
                            for v in vert_list:
                                if vert_list.count(v) == 1:
                                    end_verts.append(v)
    
                            # Check verts in dictionary
                            for key, value in edge_dic.items():
                                if value[0] in end_verts:
                                    sel.remove(key)
                                    continue
                                if value[1] in end_verts:
                                    sel.remove(key)
    
    
                            bmesh.update_edit_mesh(me, True, False)
    
                            # Select the resulting edges
                            bpy.ops.mesh.select_all(action='DESELECT')
    
                            bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
                            mesh = bpy.context.active_object.data.edges
                            for e in sel:
                                mesh[e].select = True
                            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    
                    return {'FINISHED'}
    
    class paintSelect(bpy.types.Operator):
        """Click and drag to select"""
        bl_idname = "view3d.select_paint"
        bl_label = "Paint Select"
    
        bl_options = {'REGISTER', 'UNDO'}
    
        deselect: BoolProperty(default = False, description = 'Deselect objects, polys, edges or verts')
        toggle: BoolProperty(default = False, description = 'Toggles the selection. NOTE: this option can be slow on heavy meshes')
        sel_before: IntProperty(description = 'Do Not Touch', options = {'HIDDEN'})
        sel_after: IntProperty(description = 'Do Not Touch', options = {'HIDDEN'})
    
    
        def modal(self, context, event):
    
            #if event.type == 'MOUSEMOVE':
            refresh = event.mouse_x
    
            if self.deselect == False:
                bpy.ops.view3d.select('INVOKE_DEFAULT', extend = True, deselect = False)
            else:
                bpy.ops.view3d.select('INVOKE_DEFAULT', extend = False, deselect = True, toggle = True)
    
    
    
            if event.value == 'RELEASE':
    
                return {'FINISHED'}
    
    
            return {'RUNNING_MODAL'}
    
        def invoke(self, context, event):
    
            if self.toggle:
                sel_ob = len(bpy.context.selected_objects)
    
                if sel_ob >= 1:
                    mode = bpy.context.object.mode
    
                    if mode == 'EDIT':
                        sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
    
                        # Get Selection before
                        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
                        ob = bpy.context.object.data
                        # check verts
                        if sel_mode[0]:
                            for v in ob.vertices:
                                if v.select:
                                    self.sel_before += 1
                        # check edges
                        elif sel_mode[1]:
                            for e in ob.edges:
                                if e.select:
                                    self.sel_before += 1
                        # check polys
                        else:
                            for p in ob.polygons:
                                if p.select:
                                    self.sel_before += 1
    
                        # Toggle Selection
                        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
                        bpy.ops.view3d.select('INVOKE_DEFAULT', extend = False, toggle = True)
    
                        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
                        ob = bpy.context.object.data
                        # check verts after
                        if sel_mode[0]:
                            for v in ob.vertices:
                                if v.select:
                                    self.sel_after += 1
    
                        # check edges after
                        elif sel_mode[1]:
                            for e in ob.edges:
                                if e.select:
                                    self.sel_after += 1
                        # check polys after
                        else:
                            for p in ob.polygons:
                                if p.select:
                                    self.sel_after += 1
    
                        if self.sel_after > self.sel_before:
                            self.deselect = False
                        elif self.sel_after == self.sel_before:
                            bpy.ops.object.mode_set(mode='EDIT', toggle=False)
                            bpy.ops.mesh.select_all(action='DESELECT')
                            return {'FINISHED'}
                        else:
                            self.deselect = True
    
                        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    
                    elif mode == 'OBJECT':
                        bpy.ops.view3d.select('INVOKE_DEFAULT', extend = False, toggle = True)
    
                        sel_ob_after = len(bpy.context.selected_objects)
    
                        if sel_ob_after < sel_ob:
    
                            self.deselect = True
    
    
    
            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
    
    
    class pathSelectRing(bpy.types.Operator):
        """Selects the shortest edge ring path"""
        bl_idname = "mesh.path_select_ring"
        bl_label = "Path Select Ring"
    
        bl_options = {'REGISTER', 'UNDO'}
    
    
        pick: BoolProperty(name = "Pick Mode", description = "Pick Mode", default = False)
        collapse: BoolProperty(name = "Collapse", description = "Collapses everything between your two selected edges", default = False)
    
    
        def draw(self, context):
            layout = self.layout
    
    
        def execute(self, context):
    
            me = bpy.context.object.data
            bm = bmesh.from_edit_mesh(me)
            mesh = bpy.context.active_object.data
            sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
    
            org_sel = []
            start_end = []
            active_edge = []
            border_sel = []
            vert_sel = []
            face_sel = []
    
            if sel_mode[1]:
    
                bpy.context.tool_settings.mesh_select_mode = [False, True, False]
    
                if self.pick:
                    bpy.ops.view3d.select('INVOKE_DEFAULT', extend=True, deselect=False, toggle=False)
    
    
    
                # Store the Start and End edges
    
                iterate = 0
                for e in reversed(bm.select_history):
                    if isinstance(e, bmesh.types.BMEdge):
                        iterate += 1
                        start_end.append(e)
                        if iterate >= 2:
    
                if len(start_end) <= 1:
                    if self.collapse:
                        bpy.ops.mesh.merge(type='COLLAPSE', uvs=True)
                        return{'FINISHED'}
                    return{'CANCELLED'}
    
                # Store active edge
                for e in reversed(bm.select_history):
                    if isinstance(e, bmesh.types.BMEdge):
                        active_edge = e.index
    
                # Store original edges
                for e in bm.edges:
                    if e.select:
                        org_sel.append(e)
    
                # Store visible faces
                bpy.ops.mesh.select_all(action='SELECT')
                for f in bm.faces:
                    if f.select:
                        face_sel.append(f)
    
                # Store boundry edges
                bpy.ops.mesh.region_to_loop()
    
                for e in bm.edges:
                    if e.select:
                        border_sel.append(e)
    
                bpy.ops.mesh.select_all(action='DESELECT')
    
                # Select Start and End edges
                for e in start_end:
                    e.select = True
    
                # Hide trick
                bpy.ops.mesh.loop_multi_select(ring=True)
    
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=True, type='FACE')
                bpy.ops.mesh.hide(unselected=True)
    
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
                bpy.ops.mesh.select_all(action='DESELECT')
                for e in start_end:
                    e.select = True
                bpy.ops.mesh.shortest_path_select()
                bpy.ops.mesh.select_more()
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
    
                bpy.ops.mesh.select_all(action='INVERT')
                bpy.ops.mesh.reveal()
                bpy.ops.mesh.select_all(action='INVERT')
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=True, type='EDGE')
    
                # Deselect border edges
                for e in border_sel:
                    e.select = False
    
                # Add to original selection
                for e in bm.edges:
                    if e.select:
                        org_sel.append(e)
    
                # Restore hidden polygons
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
                for f in face_sel:
                    f.select = True
                bpy.ops.mesh.hide(unselected=True)
    
                # Reselect original selection
                bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
                bpy.ops.mesh.select_all(action='DESELECT')
                for e in org_sel:
                    e.select = True
    
                # Set active edge
                bm.select_history.add(bm.edges[active_edge])
    
                if self.collapse:
                    bpy.ops.mesh.merge(type='COLLAPSE', uvs=True)
    
                bmesh.update_edit_mesh(me, True, False)
    
                return {'FINISHED'}
    
            else:
                self.report({'WARNING'}, "This tool only workins in edge mode.")
                return {'CANCELLED'}
    
    
    
    
    #Draws the Custom Menu in Object Mode
    class ktools_menu(bpy.types.Menu):
            bl_label = "KTools - Object Mode"
            bl_idname = "OBJECT_MT_ktools_menu"
    
            def draw(self, context):
    
                    layout = self.layout
                    layout.operator_context = 'INVOKE_DEFAULT'
                    layout.operator("mesh.draw_poly")
    
                    layout.operator("object.toggle_silhouette")
    
                    layout.operator("mesh.quickbool")
                    layout.operator("mesh.calc_normals")
                    layout.operator("object.custom_autosmooth")
                    layout.operator("object.basic_rename")
                    layout.operator("object.lattice_to_selection")
    
    
    #Draws the Custom Menu in Edit Mode
    class VIEW3D_MT_edit_mesh_ktools_menuEdit(bpy.types.Menu):
            bl_label = "KTools - Edit Mode"
            bl_idname = "VIEW3D_MT_edit_mesh_ktools_menuEdit"
    
            def draw(self, context):
    
    
                    layout = self.layout
    
                    layout.operator("mesh.cut_tool")
                    layout.operator("mesh.snaptoaxis")
                    layout.operator("mesh.autotubes")
                    layout.operator("mesh.shrinkwrap_smooth")
    
                    layout.operator_context = 'INVOKE_DEFAULT'
                    layout.operator("mesh.build_corner")
                    layout.operator("object.lattice_to_selection")
    
                    layout.separator()
    
                    layout.operator("mesh.path_select_ring")
                    layout.operator("mesh.grow_loop")
                    layout.operator("mesh.shrink_loop")
                    layout.operator("mesh.extend_loop")
    
                    layout.separator()
    
                    layout.operator("mesh.draw_poly")
    
                    layout.operator("object.toggle_silhouette")
                    layout.operator("mesh.quickbool")
    
                    layout.operator("object.custom_autosmooth")
                    layout.operator("mesh.calc_normals")
                    layout.operator("object.basic_rename")
    
    
    
    #Calls the KTools Object Menu
    class ktools(bpy.types.Operator): #Namesuggestion: K-Tools or K-Mac
    
            """Calls the KTools Menu"""
            bl_idname = "object.ktools"
            bl_label = "KTools Object Menu"
            #bl_options = {'REGISTER', 'UNDO'}
    
    
            def execute(self, context):
    
    
    
                bpy.ops.wm.call_menu(name=ktools_menu.bl_idname)
                return {'FINISHED'}
    
    
                """
                sel_ob = bpy.context.object
    
                    mode = bpy.context.active_object.mode
    
                    if mode == 'EDIT':
                            bpy.ops.wm.call_menu(name=VIEW3D_MT_edit_mesh_ktools_menuEdit.bl_idname)
    
                    else:
                            bpy.ops.wm.call_menu(name=ktools_menu.bl_idname)
    
    
                    return {'FINISHED'}
    
    
                else:
                    bpy.ops.wm.call_menu(name=ktools_menu.bl_idname)
                    return {'FINISHED'}
                    #self.report({'WARNING'}, "Active object is not a mesh.")
                    #return {'CANCELLED'}
                    """
    
    #Calls the KTools Edit Menu
    class ktools_mesh(bpy.types.Operator): #Namesuggestion: K-Tools or K-Mac
    
            """Calls the KTools Edit Menu"""
            bl_idname = "mesh.ktools_mesh"
            bl_label = "KTools Mesh Menu"
            #bl_options = {'REGISTER', 'UNDO'}
    
    
            def execute(self, context):
    
                bpy.ops.wm.call_menu(name=VIEW3D_MT_edit_mesh_ktools_menuEdit.bl_idname)
    
                return {'FINISHED'}
    
    
    
    # draw function for integration in menus
    def menu_func(self, context):
        self.layout.separator()
        self.layout.menu("VIEW3D_MT_edit_mesh_ktools_menuEdit", text = "KTools")
    
    def menu_func_ob(self, context):
        self.layout.separator()
    
        self.layout.menu("OBJECT_MT_ktools_menu", text = "KTools")
    
    
    #Register and Unregister all the operators
    def register():
            bpy.utils.register_class(lattice_to_selection)
            bpy.utils.register_class(calc_normals)
            bpy.utils.register_class(snaptoaxis)
            bpy.utils.register_class(quickbool)
            bpy.utils.register_class(autotubes)
            bpy.utils.register_class(basicRename)
            bpy.utils.register_class(cut_tool)
            bpy.utils.register_class(customAutoSmooth)
            bpy.utils.register_class(shrinkwrapSmooth)
            bpy.utils.register_class(buildCorner)
            bpy.utils.register_class(drawPoly)
            bpy.utils.register_class(toggleSilhouette)
            bpy.utils.register_class(growLoop)
            bpy.utils.register_class(extendLoop)
            bpy.utils.register_class(shrinkLoop)
            bpy.utils.register_class(paintSelect)
            bpy.utils.register_class(pathSelectRing)
            bpy.utils.register_class(ktools_menu)
            bpy.utils.register_class(VIEW3D_MT_edit_mesh_ktools_menuEdit)
            bpy.utils.register_class(ktools)
            bpy.utils.register_class(ktools_mesh)
    
    
            bpy.types.VIEW3D_MT_edit_mesh_specials.prepend(menu_func)
            bpy.types.VIEW3D_MT_object_specials.prepend(menu_func_ob)
    
            kc = bpy.context.window_manager.keyconfigs.addon
            if kc:
                # Add paint select to CTRL+SHIFT+ALT+LeftMouse
                km = kc.keymaps.new(name="3D View", space_type="VIEW_3D")
    
                kmi = km.keymap_items.new('view3d.select_paint', 'LEFTMOUSE', 'PRESS', shift=True, ctrl=True, alt=True)
    
    
    
    def unregister():
            bpy.utils.unregister_class(lattice_to_selection)
            bpy.utils.unregister_class(calc_normals)
            bpy.utils.unregister_class(snaptoaxis)
            bpy.utils.unregister_class(quickbool)
            bpy.utils.unregister_class(autotubes)
            bpy.utils.unregister_class(basicRename)
            bpy.utils.unregister_class(cut_tool)
            bpy.utils.unregister_class(customAutoSmooth)
            bpy.utils.unregister_class(shrinkwrapSmooth)
            bpy.utils.unregister_class(buildCorner)
            bpy.utils.unregister_class(drawPoly)
            bpy.utils.unregister_class(toggleSilhouette)
            bpy.utils.unregister_class(growLoop)
            bpy.utils.unregister_class(extendLoop)
            bpy.utils.unregister_class(shrinkLoop)
            bpy.utils.unregister_class(paintSelect)
            bpy.utils.unregister_class(pathSelectRing)
            bpy.utils.unregister_class(ktools_menu)
            bpy.utils.unregister_class(VIEW3D_MT_edit_mesh_ktools_menuEdit)
            bpy.utils.unregister_class(ktools)
            bpy.utils.unregister_class(ktools_mesh)
    
            bpy.types.VIEW3D_MT_edit_mesh_specials.remove(menu_func)
    
            bpy.types.VIEW3D_MT_object_specials.remove(menu_func_ob)
    
    
            kc = bpy.context.window_manager.keyconfigs.addon
            if kc:
                km = kc.keymaps["3D View"]
                for kmi in km.keymap_items:
                    if kmi.idname == 'view3d.select_paint':
                        km.keymap_items.remove(kmi)
                        break
    
    
    
    # This allows you to run the script directly from blenders text editor
    # to test the addon without having to install it.
    if __name__ == "__main__":
            register()