Home Technical Talk

Pedro's Super Smart Create for Blender

interpolator
Offline / Send Message
maxivz interpolator
Hey Guys, I have been playing around with blender and some scripting lately. I decided to port Pedro's excellent  super smart create script
I am really new to Blender and my python coding skills are not the finest, so please if you find any better way to do stuff or if i'm making any stupid shit just let me know.
Anyways, here's the tool (the descriptions are taken from Pedro's thread, so you can compare the functionality).

Connects verts that belong to the same face 



If you select one vert or two verts that share the same edge and are on a border it will invoke f2(make sure you have f2 enabled):


Divides the selected edge in 2, putting a vert in the middle of the edge




Connects the selected edges if there is faces in between the edges


Caps selected borders

Bridges selected edges if possible

When you select 2 adjacent edges it creates a face


Bridges selected polys


Heres an extra one, tries to make quads from a selected face.



This last feature  works pretty good if you cap a border and then run the script again to make quads out of it:


Installation:
Pretty much the standard blender plugin installation. Load it up from the install from file option in user Preferences and make sure you enable it.
You can either run it from the mesh-> Super Smart Create menu or assign a hotkey to it. Id recommend you to assign a hotkey to it, to make it even easier to use. To assign a hotkey you can find it in Input ->  3D View- > Mesh -> Super Smart Create
I have developed it in Blender 2.78c, so no idea if it works with older versions or not

Download(save this as a .py file):
bl_info = {
    "name": "Super Smart Create",
    "author": "Maximiliano Vazquez, Original idea: Pedro Amorim",
    "version": (1, 0),
    "blender": (2, 65, 0),
    "location": "Mesh  > Super Smart Create",
    "description": "Context Sensitive mesh modification",
    "warning": "",
    "wiki_url": "",
    "tracker_url": "",
    "category": "Mesh"}
    
import bpy
import bmesh
from bpy.types import Operator, AddonPreferences
from bpy.props import StringProperty
import mesh_f2

#Global Variables
ITERATION_LIMIT = 200

#Functions

def list_intersection(a, b):
    return list(set(a) & set(b))

def list_difference(a,b):
    return list(set(a)- set(b))

def get_bmesh():
    return bmesh.from_edit_mesh(bpy.context.edit_object.data)

def update_indexes(bm ,verts=False, edges=False, faces=False):
    if verts:
        bm.verts.index_update()
    if edges:
        bm.edges.index_update()
    if faces:
        bm.faces.index_update()
    bm.verts.ensure_lookup_table()
    bm.edges.ensure_lookup_table()
    bm.faces.ensure_lookup_table()
    bmesh.update_edit_mesh(bpy.context.edit_object.data)
    return bm

def get_selected(bm,verts=False, edges = False, faces = False, get_item = False):
    if verts:
        bm = update_indexes(bm, verts=True)
        selected_verts = []
        for vert in bm.verts:
            if vert.select :
                if get_item:
                    selected_verts.append(vert)
                else:
                    selected_verts.append(vert.index)
        return selected_verts
    if edges:
        bm = update_indexes(bm,edges=True)
        selected_edges = []
        for edge in bm.edges:
            if edge.select:
                if get_item:
                    selected_edges.append(edge)
                else:
                    selected_edges.append(edge.index)
        return selected_edges
    if faces:
        bm = update_indexes(bm,faces=True)
        selected_faces = []
        for face in bm.faces:
            if face.select:
                if get_item:
                    selected_faces.append(face)
                else:
                    selected_faces.append(face.index)
        return selected_faces

def select_from_index(bm,indexes, verts = False,edges = False, faces = False, replace = False, add_to_history = False):
    if replace:
        bpy.ops.mesh.select_all(action='DESELECT')
    if verts:
        for index in indexes:
            bm.verts[index].select = True
            if add_to_history:
                bm.select_history.add(bm.verts[index])
    if edges:
        for index in indexes:
            bm.edges[index].select = True
            if add_to_history:
                bm.select_history.add(bm.edges[index])
    if faces:
        for index in indexes:
            bm.faces[index].select = True
            if add_to_history:
                bm.select_history.add(bm.faces[index])
                
def select_from_item(bm,items, verts = False,edges = False, faces = False, replace = False, add_to_history = False):
    if replace:
        bpy.ops.mesh.select_all(action='DESELECT')
    if verts:
        for item in items:
            bm.verts[item.index].select = True
            if add_to_history:
                bm.select_history.add(bm.verts[item.index])
    if edges:
        for item in items:
            bm.edges[item.index].select = True
            if add_to_history:
                bm.select_history.add(bm.edges[item.index])
    if faces:
        for item in items:
            bm.faces[item.index].select = True
            if add_to_history:
                bm.select_history.add(bm.faces[item.index])

def verts_share_edge(bm):
    other_verts = []
    verts = get_selected(bm,verts = True, get_item = True)
    for vert in verts:
        for edge in vert.link_edges:
            other_vert = edge.other_vert(vert)
            other_verts.append(other_vert)
    return vert in other_verts
    
def is_border(bm):
    edge_list = get_selected(bm,edges = True, get_item = True)
    select_from_index(bm,[edge_list[0].index],edges = True, replace = True)
    bpy.ops.mesh.loop_multi_select(ring=False)
    border_selection = get_selected(bm, edges = True, get_item = True)
    border_edges = all(len((edge.link_faces)) is 1 for edge in edge_list)
    is_complete_border = all(edge in edge_list for edge in border_selection)
    select_from_item(bm,edge_list,edges = True, replace = True)
    return border_edges and is_complete_border

def is_adjacent(bm):
    edge_list = get_selected(bm,edges = True)
    select_from_index(bm,[edge_list[0]],edges = True, replace = True)
    bpy.ops.mesh.select_more()
    new_selection = get_selected(bm, edges = True)
    select_from_index(bm,edge_list,edges = True, replace = True)
    return all(edge in new_selection for edge in edge_list)

def is_ring(bm):
    selection = get_selected(bm,edges = True, get_item = True)
    result = all(len((edge.link_faces)) is 2 for edge in selection)
    return result

def split_edge_select_vert(bm, change_selection = False):
    selection = get_selected(bm,verts = True)
    bpy.ops.mesh.subdivide()
    new_selection = get_selected(bm,verts = True)
    new_selection = list_difference(new_selection, selection)
    if change_selection:
        select_from_index(bm,new_selection, verts = True,replace = True)
        bpy.context.scene.tool_settings.mesh_select_mode = [True,False,False]
    return new_selection

def are_border_verts(bm, selection):
    selection = get_selected(bm,verts = True)
    return all(len(bm.verts[vert].link_faces) <= 3 for vert in selection)


def quad_fill(bm):
    selection = get_selected(bm,edges = True)
    bpy.ops.mesh.delete(type='FACE')
    select_from_index(bm,selection, edges = True,replace = True)
    bpy.ops.mesh.fill_grid()

def super_smart_create():
    bm = get_bmesh()
    selectionMode = (tuple(bpy.context.scene.tool_settings.mesh_select_mode))
    #if Vertex is selected
    if selectionMode[0]:
        selection = get_selected(bm,verts = True)
        if len(selection) == 1 or (verts_share_edge(bm) and are_border_verts(bm,selection)):
            print(are_border_verts(bm,selection))
            mesh_f2.bpy.ops.mesh.f2('INVOKE_DEFAULT')
        else:    
            bpy.ops.mesh.vert_connect()
    #if Edge is selected
    elif selectionMode[1]:
        selection = get_selected(bm,edges = True)
        if len(selection) == 1:
            split_edge_select_vert(bm,change_selection = True)                     
        elif is_border(bm):
            bpy.ops.mesh.edge_face_add()
            bpy.context.scene.tool_settings.mesh_select_mode = [False,False,True]
        elif is_ring(bm):
            bpy.ops.mesh.subdivide(number_cuts = 1, quadcorner = 'INNERVERT')
            bpy.ops.mesh.select_less()
        elif is_adjacent(bm):
            bpy.ops.mesh.edge_face_add()
            bpy.context.scene.tool_settings.mesh_select_mode = [False,True,False]
        else:
            bpy.ops.mesh.bridge_edge_loops()
            bpy.context.scene.tool_settings.mesh_select_mode = [False,True, False]
    #if Face is selected           
    elif selectionMode[2]:
        selection = get_selected(bm,faces = True)
        if len(selection) == 1:
            quad_fill(bm)
        if len(selection) > 1:
            bpy.ops.mesh.bridge_edge_loops()
            
    #bm.free()
    
class SuperSmartCreate(bpy.types.Operator):
    """ Super Smart Create"""
    bl_idname = "mesh.super_smart_create"
    bl_label = "Super Smart Create"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self,context):
        super_smart_create()
        return {'FINISHED'}

class SuperSmartCreatePreferences(bpy.types.AddonPreferences):
    bl_idname = __name__
    assigned_hotkey = StringProperty(
            name="Assigned Hotkey",
            default = 'NONE',
            )
            
    def draw(self, context):
        layout = self.layout
        layout.prop(self,assigned_hotkey)
        
                        
def SuperSmartCreatePrefs_Menu(self, context):
    self.layout.operator(SuperSmartCreate.bl_idname)

# store keymaps here to access after registration
addon_keymaps = []
    
def register():
    bpy.utils.register_class(SuperSmartCreate)
    #Make menu
    bpy.types.VIEW3D_MT_edit_mesh.append(SuperSmartCreatePrefs_Menu)
    
    ##Handle Keymap
    wm = bpy.context.window_manager
    km = wm.keyconfigs.addon.keymaps.new(name='Mesh', space_type='EMPTY')
    kmi = km.keymap_items.new(SuperSmartCreate.bl_idname, 'W', 'PRESS', alt = True)
    addon_keymaps.append((km, kmi))
    

def unregister():
    bpy.utils.unregister_class(SuperSmartCreate)
    #bpy.utils.unregister_class(SuperSmartCreatePreferences)
    #Remove Menu
    bpy.types.VIEW3D_MT_edit_mesh.remove(SuperSmartCreatePrefs_Menu)    
    #Remove Keymaps
    for km, kmi in addon_keymaps:
        km.keymap_items.remove(kmi)
    addon_keymaps.clear()
    
if __name__ == "__main__":
    register()

Please report any problems, suggestions, so I can *hopefully* improve it . Hope you guys find it useful.

Replies

Sign In or Register to comment.