Results 1 to 13 of 13
  1. #1

    Copy object to face, edge, or vertex script (updated to 2.5.3.1)

    I'm learning Blender Python 2.5 and here's my first real script. It copies an object to the selected vertexes, edges or faces of another object. Use is explained in the comments.

    Here's a quick example of the the type of thing you can build with it. The base object is an icosphere with subdivisons set to 1. The spike is an edited cone and was copied to the vertexes, the torus was copied to the faces and the tube to the edges,



    Code:
    """
    EFH 1/08/10 Updated to Blender 2.53.0 Beta
    script to copy a selected object to the selected vertexs, edges or faces of the active object
    
    To use:
    select object to copy from - RMB
    select object to copy to - SHIFT RMB
    enter edit mode - TAB
    choose desired select mode - CTRL TAB face or edge or vertex
    select several faces, edges or verts - RMB, SHIFT RMB
    exit edit mode - TAB
    run script - ALT P
    
    The choosen select mode will determine if the selected object is copied to 
    the vertex, edge, or face of the active object.
    
    For face select mode:
    The z axis of the copy from will be aligned with the face normal.
    The x axis of the copy from will point toward one of the face vertexs.
    
    For edge select mode:
    The x axis of the copy from will be aligned along the edge.
    The z axis of the copy from will be the average of the edge's vertex normals.
    
    For vertex select mode:
    The z axis of the copy from will be aligned with the vertex normal.
    The x axis of the copy from will point along an edge.     
    
    Any scaling or rotation of the source_obj mesh to the desired orientation to the 
    x and z axes has to be done in edit mode. Also in edit mode the source_obj mesh can be moved 
    realative to the pivot point. This will offset the copies relative to the face centers.
    
    """
    
    import bpy
    import mathutils
    
    def copyto(source_obj, pos, xdir, zdir):
         """
         copy the source_obj to pos, so its z-axis points in zdir and its x-axis
         points in xdir
           
         """
         #select only source_obj
         bpy.ops.object.select_all(action='DESELECT')
         source_obj.select = True
         #duplicate source_obj
         bpy.ops.object.duplicate()
         #and leaves copy selected but not active
         copy_obj = bpy.context.selected_objects[0]
         
         xdir = xdir.normalize()
         zdir = zdir.normalize()
         #rotation first
         z_axis = zdir
         x_axis = xdir    
         y_axis = z_axis.cross(x_axis)
         rot_mat = mathutils.Matrix(x_axis,y_axis,z_axis)
         rot_mat = rot_mat.to_4x4()
         copy_obj.matrix_world = rot_mat 
              
         #move object onto face   
         copy_obj.location = pos
    
         return copy_obj
    
    
    #need to be in object mode for script to work
    bpy.ops.object.mode_set(mode='OBJECT')
    
    sel_faces = []
    sel_verts = []
    sel_edges = []
    
    copy_list = []
    
    obj = bpy.context.active_object
    #objects are not in selection order
    #for now find a selected object that isn't active object
    #if more than two objects are selected should do something else
    
    for s_obj in bpy.context.selected_objects:
        if s_obj != obj:
            source_obj = s_obj
    
    if bpy.context.tool_settings.mesh_selection_mode[0] == True:
        #vertex select mode
        for v in obj.data.verts:
            if v.select == True:
                sel_verts.append(v)
    
        #make a set for each vertex. The set contains all the connected verts
        #use sets so the list is unique
        vert_con = [set() for i in range(len(obj.data.verts))]
        for e in obj.data.edges:
            vert_con[e.verts[0]].add(e.verts[1])
            vert_con[e.verts[1]].add(e.verts[0])
        
        for v in sel_verts:
            pos = obj.matrix_world * v.co
            xco = obj.matrix_world * obj.data.verts
    [list(vert_con[v.index])[0]].co
           
            zdir = obj.matrix_world * (v.co + v.normal) - pos
            zdir = zdir.normalize()
            
            edir = pos - xco
            
            #edir is nor perpendicular to z dir
            #want xdir to be projection of edir onto plane through pos with direction zdir
            xdir = edir - edir.dot(zdir) * zdir
            xdir = -xdir.normalize()
            
            copy = copyto(source_obj, pos, xdir, zdir)
            copy_list.append(copy)
    
    
    if bpy.context.tool_settings.mesh_selection_mode[1] == True:
        #edge select mode
        for e in obj.data.edges:
            if e.select == True:
                sel_edges.append(e)
        for e in sel_edges:
            #pos is average of two edge vertexs
            v0 = obj.matrix_world * obj.data.verts[e.verts[0]].co
            v1 = obj.matrix_world * obj.data.verts[e.verts[1]].co
            pos = (v0 + v1)/2
            #xdir is along edge
            xdir = v0-v1
            xdir = xdir.normalize()
            #project each edge vertex normal onto plane normal to xdir
            vn0 = obj.matrix_world * (obj.data.verts[e.verts[0]].co + obj.data.verts[e.verts[0]].normal) - v0
            vn1 = obj.matrix_world * (obj.data.verts[e.verts[1]].co + obj.data.verts[e.verts[1]].normal) - v1
            vn0p = vn0 - vn0.dot(xdir)*xdir
            vn1p = vn1 - vn1.dot(xdir)*xdir
            #the mean of the two projected normals is the zdir
            zdir = vn0p + vn1p
            zdir = zdir.normalize()
            
            copy = copyto(source_obj, pos, xdir, zdir)
            copy_list.append(copy)
    
    
    if bpy.context.tool_settings.mesh_selection_mode[2] == True:
        #face select mode
        for f in obj.data.faces:
            if f.select == True:
                sel_faces.append(f)
    
        for f in sel_faces:       
             #get face center of transformed object
             fco = obj.matrix_world * f.center
             #get first vertex corner of transformed object
             vco = obj.matrix_world * obj.data.verts[f.verts[0]].co
             #get face normal of transformed object
             fn = obj.matrix_world*(f.center + f.normal) - fco
             fn = fn.normalize()
        
             copy = copyto(source_obj, fco, vco - fco, fn)
             copy_list.append(copy)
    
    #select all copied objects
    for copy in copy_list:
        copy.select = True
    I hope it's useful or helps someone with learning blender python.

    cheers elfnor
    Last edited by elfnor; 01-Sep-10 at 05:29. Reason: update title



  2. #2



  3. #3
    Hi elfnor!

    Can you update your script to actual blender version ?
    verts => vertices
    and more



  4. #4
    Member tungee's Avatar
    Join Date
    Nov 2007
    Location
    Germany Frankfurt
    Posts
    1,421
    Very useful scripsts lately, Thanx elfnor!
    But i doesnot work on the latest builds.



  5. #5
    Member tungee's Avatar
    Join Date
    Nov 2007
    Location
    Germany Frankfurt
    Posts
    1,421
    Any news on this?



  6. #6

    Updated Script 2.5.3.1

    Thanks everyone for the interest.

    Here's the script updated for 2.5.3.1. I tested it on r31458.

    I just needed to replace vert -> vertices and mesh_selection_mode -> mesh_select_mode

    Code:
    """
    EFH 31/08/10 Updated to Blender 2.53.1 r31458 
    script to copy a selected object to the selected vertices, edges or faces of the active object
    
    To use:
    select object to copy from - RMB
    select object to copy to - SHIFT RMB
    enter edit mode - TAB
    choose desired select mode - CTRL TAB face or edge or vertex
    select several faces, edges or vertices - RMB, SHIFT RMB
    exit edit mode - TAB
    run script - ALT P
    
    The choosen select mode will determine if the selected object is copied to 
    the vertex, edge, or face of the active object.
    
    For face select mode:
    The z axis of the copy from will be aligned with the face normal.
    The x axis of the copy from will point toward one of the face vertexs.
    
    For edge select mode:
    The x axis of the copy from will be aligned along the edge.
    The z axis of the copy from will be the average of the edge's vertex normals.
    
    For vertex select mode:
    The z axis of the copy from will be aligned with the vertex normal.
    The x axis of the copy from will point along an edge.     
    
    Any scaling or rotation of the source_obj mesh to the desired orientation to the 
    x and z axes has to be done in edit mode. Also in edit mode the source_obj mesh can be moved 
    realative to the pivot point. This will offset the copies relative to the face centers.
    
    """
    
    import bpy
    import mathutils
    
    def copyto(source_obj, pos, xdir, zdir):
         """
         copy the source_obj to pos, so its z-axis points in zdir and its x-axis
         points in xdir
           
         """
         #select only source_obj
         bpy.ops.object.select_all(action='DESELECT')
         source_obj.select = True
         #duplicate source_obj
         bpy.ops.object.duplicate()
         #and leaves copy selected but not active
         copy_obj = bpy.context.selected_objects[0]
         
         xdir = xdir.normalize()
         zdir = zdir.normalize()
         #rotation first
         z_axis = zdir
         x_axis = xdir    
         y_axis = z_axis.cross(x_axis)
         rot_mat = mathutils.Matrix(x_axis,y_axis,z_axis)
         rot_mat = rot_mat.to_4x4()
         copy_obj.matrix_world = rot_mat 
              
         #move object onto face   
         copy_obj.location = pos
    
         return copy_obj
    
    
    #need to be in object mode for script to work
    bpy.ops.object.mode_set(mode='OBJECT')
    
    sel_faces = []
    sel_verts = []
    sel_edges = []
    
    copy_list = []
    
    obj = bpy.context.active_object
    #objects are not in selection order
    #for now find a selected object that isn't active object
    #if more than two objects are selected should do something else
    
    for s_obj in bpy.context.selected_objects:
        if s_obj != obj:
            source_obj = s_obj
    
    if bpy.context.tool_settings.mesh_select_mode[0] == True:
        #vertex select mode
        for v in obj.data.vertices:
            if v.select == True:
                sel_verts.append(v)
    
        #make a set for each vertex. The set contains all the connected vertices
        #use sets so the list is unique
        vert_con = [set() for i in range(len(obj.data.vertices))]
        for e in obj.data.edges:
            vert_con[e.vertices[0]].add(e.vertices[1])
            vert_con[e.vertices[1]].add(e.vertices[0])
        
        for v in sel_verts:
            pos = obj.matrix_world * v.co
            xco = obj.matrix_world * obj.data.vertices
    [list(vert_con[v.index])[0]].co
           
            zdir = obj.matrix_world * (v.co + v.normal) - pos
            zdir = zdir.normalize()
            
            edir = pos - xco
            
            #edir is nor perpendicular to z dir
            #want xdir to be projection of edir onto plane through pos with direction zdir
            xdir = edir - edir.dot(zdir) * zdir
            xdir = -xdir.normalize()
            
            copy = copyto(source_obj, pos, xdir, zdir)
            copy_list.append(copy)
    
    
    if bpy.context.tool_settings.mesh_select_mode[1] == True:
        #edge select mode
        for e in obj.data.edges:
            if e.select == True:
                sel_edges.append(e)
        for e in sel_edges:
            #pos is average of two edge vertexs
            v0 = obj.matrix_world * obj.data.vertices[e.vertices[0]].co
            v1 = obj.matrix_world * obj.data.vertices[e.vertices[1]].co
            pos = (v0 + v1)/2
            #xdir is along edge
            xdir = v0-v1
            xdir = xdir.normalize()
            #project each edge vertex normal onto plane normal to xdir
            vn0 = obj.matrix_world * (obj.data.vertices[e.vertices[0]].co 
                  + obj.data.vertices[e.vertices[0]].normal) - v0
            vn1 = obj.matrix_world * (obj.data.vertices[e.vertices[1]].co 
                  + obj.data.vertices[e.vertices[1]].normal) - v1
            vn0p = vn0 - vn0.dot(xdir)*xdir
            vn1p = vn1 - vn1.dot(xdir)*xdir
            #the mean of the two projected normals is the zdir
            zdir = vn0p + vn1p
            zdir = zdir.normalize()
            
            copy = copyto(source_obj, pos, xdir, zdir)
            copy_list.append(copy)
    
    
    if bpy.context.tool_settings.mesh_select_mode[2] == True:
        #face select mode
        for f in obj.data.faces:
            if f.select == True:
                sel_faces.append(f)
    
        for f in sel_faces:       
             #get face center of transformed object
             fco = obj.matrix_world * f.center
             #get first vertex corner of transformed object
             vco = obj.matrix_world * obj.data.vertices[f.vertices[0]].co
             #get face normal of transformed object
             fn = obj.matrix_world*(f.center + f.normal) - fco
             fn = fn.normalize()
        
             copy = copyto(source_obj, fco, vco - fco, fn)
             copy_list.append(copy)
    
    #select all copied objects
    for copy in copy_list:
        copy.select = True
    I've posted both versions here http://elfnor.deviantart.com/art/Copy-2-Blender-Python-Script-177632885.
    and will post any more updates I do there also.

    elfnor



  7. #7

    Sorry for MegaBump

    Hi i apologize for bumping this old thread but this script is very useful and it was obsolete
    so i updated it to latest. If any one still encounters bugs please post

    Code:
    #Updated to 2.61 on 17 jan 2012 By Brenel (Original by Author Elfnor)
    
    import bpy
    import mathutils
    
    def copyto(source_obj, pos, xdir, zdir):
         """
         copy the source_obj to pos, so its z-axis points in zdir and its x-axis
         points in xdir
           
         """
         #select only source_obj
         bpy.ops.object.select_all(action='DESELECT')
         source_obj.select = True
         #duplicate source_obj
         bpy.ops.object.duplicate()
         #and leaves copy selected but not active
         copy_obj = bpy.context.selected_objects[0]
         
         xdir.normalize()
         zdir.normalize()
         #rotation first
         z_axis = zdir
         x_axis = xdir    
         y_axis = z_axis.cross(x_axis)
         print(x_axis)
         print(y_axis)
         print(z_axis)
         rot_mat = mathutils.Matrix((x_axis,y_axis,z_axis))
         rot_mat = rot_mat.to_4x4()
         copy_obj.matrix_world = rot_mat 
              
         #move object onto face   
         copy_obj.location = pos
    
         return copy_obj
    
    
    #need to be in object mode for script to work
    bpy.ops.object.mode_set(mode='OBJECT')
    
    sel_faces = []
    sel_verts = []
    sel_edges = []
    
    copy_list = []
    
    obj = bpy.context.active_object
    #objects are not in selection order
    #for now find a selected object that isn't active object
    #if more than two objects are selected should do something else
    
    for s_obj in bpy.context.selected_objects:
        if s_obj != obj:
            source_obj = s_obj
    
    if bpy.context.tool_settings.mesh_select_mode[0] == True:
        #vertex select mode
        for v in obj.data.vertices:
            if v.select == True:
                sel_verts.append(v)
    
        #make a set for each vertex. The set contains all the connected vertices
        #use sets so the list is unique
        vert_con = [set() for i in range(len(obj.data.vertices))]
        for e in obj.data.edges:
            vert_con[e.vertices[0]].add(e.vertices[1])
            vert_con[e.vertices[1]].add(e.vertices[0])
        
        for v in sel_verts:
            pos = obj.matrix_world * v.co
            xco = obj.matrix_world * obj.data.vertices
    [list(vert_con[v.index])[0]].co
           
            zdir = obj.matrix_world * (v.co + v.normal) - pos
            zdir.normalize()
            
            edir = pos - xco
            
            #edir is nor perpendicular to z dir
            #want xdir to be projection of edir onto plane through pos with direction zdir
            xdir = edir - edir.dot(zdir) * zdir
            xdir.normalize()
            
            copy = copyto(source_obj, pos, xdir, zdir)
            copy_list.append(copy)
    
    
    if bpy.context.tool_settings.mesh_select_mode[1] == True:
        #edge select mode
        for e in obj.data.edges:
            if e.select == True:
                sel_edges.append(e)
        for e in sel_edges:
            #pos is average of two edge vertexs
            v0 = obj.matrix_world * obj.data.vertices[e.vertices[0]].co
            v1 = obj.matrix_world * obj.data.vertices[e.vertices[1]].co
            pos = (v0 + v1)/2
            #xdir is along edge
            xdir = v0-v1
            #print(xdir)
            xdir.normalize()
            #project each edge vertex normal onto plane normal to xdir
            vn0 = obj.matrix_world * (obj.data.vertices[e.vertices[0]].co 
                  + obj.data.vertices[e.vertices[0]].normal) - v0
            vn1 = obj.matrix_world * (obj.data.vertices[e.vertices[1]].co 
                  + obj.data.vertices[e.vertices[1]].normal) - v1
            vn0p = vn0 - vn0.dot(xdir)*xdir
            vn1p = vn1 - vn1.dot(xdir)*xdir
            #the mean of the two projected normals is the zdir
            zdir = vn0p + vn1p
            zdir.normalize()
            
            copy = copyto(source_obj, pos, xdir, zdir)
            copy_list.append(copy)
    
    
    if bpy.context.tool_settings.mesh_select_mode[2] == True:
        #face select mode
        for f in obj.data.faces:
            if f.select == True:
                sel_faces.append(f)
    
        for f in sel_faces:       
             #get face center of transformed object
             fco = obj.matrix_world * f.center
             #get first vertex corner of transformed object
             vco = obj.matrix_world * obj.data.vertices[f.vertices[0]].co
             #get face normal of transformed object
             fn = obj.matrix_world*(f.center + f.normal) - fco
             fn.normalize()
        
             copy = copyto(source_obj, fco, vco - fco, fn)
             copy_list.append(copy)
    
    #select all copied objects
    for copy in copy_list:
        copy.select = True



  8. #8
    Looks nice but it needs a license and bl_info.



  9. #9
    Originally Posted by metalliandy View Post
    Looks nice but it needs a license and bl_info.
    Yeah Elfnor did not add any license ...this can become good addon i think.



  10. #10
    I've been looking for something to do this for months. Now I can try to build the Lexx.
    Question though. How do I install this script? Where do I get it? An add-on somewhere?
    This is such a useful idea, it needs to be trunked (as add-on I guess) ASAP.
    Laptop: Asus G74SX-XR1 12Gb RAM, 3Gb GT560M, 64Gb SSD, 640 HDD
    OS: Win7 Professional



  11. #11
    Member
    Join Date
    Oct 2013
    Location
    Belgium
    Posts
    297
    There is a new update for this script https://github.com/elfnor/copy2_blender_addon , but i have problems to enable this script with blender 2.71 or higher , can someone try this



  12. #12
    Member eppo's Avatar
    Join Date
    Jul 2011
    Location
    Jurmala, Latvia
    Posts
    5,310
    That's a funny typo in the script, easy to correct. Open script in text editor window, in the beginning, find the line
    Code:
    "warning": ""
    (line 27 to be exact)
    and add comma at the end, save, install, run.
    Last edited by eppo; 19-Jun-15 at 13:48.



  13. #13
    Member
    Join Date
    Oct 2013
    Location
    Belgium
    Posts
    297
    Thanks eppo after changing the code ( line 27 ) i can enable the addon and run the script . Thanks



Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •