Automate bpy.ops.mesh.extrude with a vector

I would like to know how to script the extrude with a vector provided in Blender 2.5x.

I tried to do it manually, first select a set of vertices, then “E” or select the “Extrude Region” under the “Add” section of the “Mesh Tools”, then I can specify the vector by entering the X, Y and Z value. How can I automate these steps by Python?

The bpy.ops.mesh.extrude(type=‘REGION’) same as pressing the E key, but how can I enter the vector?

This is something I’ve been wondering too. I don’t know the answer yet, but I’d love to find out!


import bpy
from mathutils import Vector

myVec = Vector((1.0,2.0,1.0))

bpy.ops.mesh.extrude_region_move(MESH_OT_extrude={"type":'REGION'}, TRANSFORM_OT_translate={"value":(0, 0, 0), "constraint_axis":(False, False, True), "constraint_orientation":'GIMBAL', "mirror":False, "proportional":'DISABLED', "proportional_edit_falloff":'SMOOTH',"snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "texture_space":False, "release_confirm":False})

bpy.ops.transform.translate(value=myVec, constraint_axis=(False, False, False), constraint_orientation='NORMAL')

the faces appear inverted, but seem to get recalculated once you perform another similar operation. The above can be shortened to:


import bpy
from mathutils import Vector
myVec = Vector((1.0,2.0,1.0))
bpy.ops.mesh.extrude_region_move(MESH_OT_extrude={"type":'REGION'}, TRANSFORM_OT_translate={"value":myVec})

i hope that helps

Thank you. It work. Now I have to find a way to rotate the set of selected vertices to make the region extrudes alone the edges nicely.

good! amy_aimei, make and post a screen shot of the steps that you would do by hand, that you would like to do with python. Also look at the reporting console (drag down the Information window, it’s hidden away) while you perform the operations manually. The reporting console usually shows what python functions are used and what their arguments are.

If you can mange to keep track of newly created edges, then you can use bpy to keep track of the Normal direction that they would produce if they formed solid/closed faces. A Normal can be calculated using 3 coordinates, it is the smallest ‘flat’ unit we can work with in 3d graphics. So you might pick any three vertices of the new edges and do


import bpy
from mathutils import Vector, geometry

co_1 = Vector((-1.3349171876907349, -0.4734605848789215, 0.3062398433685303))
co_2 = Vector((0.6650824546813965, -0.4734615385532379, 0.3062398433685303))
co_3 = Vector((0.6698348522186279, 0.9469220638275146, -0.6124801635742188))
# presume this to be a clockwise sequence
print(geometry.normal(co_1,co_2,co_3))
# note the different result from counter clockwise coordinate sequence
print(geometry.normal(co_3,co_2,co_1))

That allows you to give 3 coordinates and it returns the direction of the face that they would produce. This is called the Normal direction. For example: When you tilt a face and extrude it blender will indicate the Normal Axis with the guide line. I suggest you experiment a little and show us what you come up with! Good luck!

https://sites.google.com/site/amyaimei/blender/images/extrude.jpg

Above shows the 2D view of what I want to achieve. All start with a set of edges. In this example, there are 3 edges, total 4 vertices. If a region is extruded by using the vector (x2-x1, y2-y1, z2-z1), the result will look like the shape in the middle of the picture. I want to adjust the angle once the extrusion is finished at the end of one of the edges so that angle a is the same as angle b as shown in the left-most shape in the picture. I would like to find a simple way to calculate the 3D rotation matrix, then apply the 3D rotation to the vertices of the selected region. Once the rotation is applied, continue the extrusion along the next edge. At the end, the extruded region has to be adjusted to be perpendicular to the last edge. Any idea of how these calculations should be?

do a dir(Vector()) in the python console, you’ll find some useful functions in particular .angle and .rotation.

blender.org/documentation/…/ops.transform.rotate

be careful while experimenting with these operators, blender can sometimes quit without warning when no object is selected.

commands for python console like help(Vector().angle) can at times also give insight into the command.

Hi Zeffi,

I wanted to do something similar for a loop, but always extrude it inward, leaving the new edges parallel to the original as much as possible. Since this overlaps a lot with what this person was trying to do, and they never posted their results/methods, I thought I might put this here. (.blend and code to follow in next post)

-assume an edge loop is selected and has been extruded but that the resulting extruded vertices have not moved

  1. Get a list of the vertex indices of the new loop in order
  2. determine which direction around the loop that order corresponds to(ccw or cw w/ respect to z axis)
  3. Get the vector representation of the two edges that each vertex is comprised of and interpolate (lerp) them
  4. Translate the vertex by some amount in the direction perpendicular to the z axis and perpendicular to the curve.

everything works fine except for when the object origin location is not at the origin. Here are the results

before
http://dl.dropbox.com/u/2586482/SreenShots/ptr_extrusion.png

after 2 iterations
http://dl.dropbox.com/u/2586482/SreenShots/post_extrusion.png

Here is a .blend and the script

any idea why it doesn’t work on objects not at origin?

http://dl.dropbox.com/u/2586482/extrusion_python.blend

import bpy

## For Blender 2.58 r 37702
def extrude_edges_in(me, edges, mx, res):
    from mathutils import Vector, Matrix
    from bpy_extras.mesh_utils import edge_loops_from_edges
    '''
    args:
        me - Blender Mesh Data
        edges - edges (not indices of edges)
        mx  - world matrix
        res - distance to be extruded
    '''
    
    z = Vector((0,0,1))
    if not mx:
        mx = Matrix()
    
    verts_in_order = edge_loops_from_edges(me,edges)
    verts_in_order = verts_in_order[0]
       
    verts_in_order.append(verts_in_order[1])
    l = len(verts_in_order)    
    verts_alone = verts_in_order[0:l-2]
    
    
    lerps = []
    curl = 0
    
    for n in range(0,l-2):
        a = verts_in_order[n]
        b = verts_in_order[n+1]
        c = verts_in_order[n+2]
        v0 = me.vertices[a]
        v1 = me.vertices[b]
        v2 = me.vertices[c]
        
        #Vec representation of the two edges
        V0 = (v1.co - v0.co)*mx
        V1 = (v2.co - v1.co)*mx
        
        ##XY projection
        temp0 = Vector((V0[0],V0[1],0))
        temp1 = Vector((V1[0],V1[1],0))
        
        cross0 = temp0.cross(temp1)
        
        sign = 1
        if cross0[2]<0:
            sign = -1
        
        rot = temp0.rotation_difference(temp1)  
        ang = rot.angle
    
        curl = curl + ang*sign
        lerps.append(V0.lerp(V1,.5))
        
    clockwise = 1

    if curl < 0:
        clockwise = -1
    print(curl)
    
    
    bpy.ops.object.mode_set(mode = 'EDIT')
    bpy.ops.mesh.select_all(action = 'DESELECT')
    bpy.ops.object.mode_set(mode = 'OBJECT')
        
    for n in range(0,l-2):
        #ignore this stuff, its for other things.
        #a = verts_in_order[n]
        b = verts_in_order[n+1]
        #c = verts_in_order[n+2]
        #v0 = me.vertices[a]
        v1 = me.vertices[b]
        #v2 = me.vertices[c]

    
        V = lerps[n]
        Trans = z.cross(V)*clockwise
        Trans.normalize()
    
        v1.select = True
        bpy.ops.object.editmode_toggle()
        bpy.ops.transform.translate(value = Trans*res)
        bpy.ops.mesh.select_all(action = 'DESELECT')
        bpy.ops.object.editmode_toggle()



#test calls

ob = bpy.context.object
me = ob.data
mx = ob.matrix_local
sel_verts = [v.index for v in me.vertices if v.select]  #notice these are indices
sel_edges = [e for e in me.edges if e.select == True]   #notice these are Mesh Data Edges

extrude_edges_in(me, sel_edges, mx, .1)

Thanks Zeffii. I fixed the .blend for 2.58. Moved a function around in the move. I will just temporarily just bounce the object origin around…and see what happens when I run it on a parented object :slight_smile: (code updated as well)

cool script btw !

Thanks Zeffi, I’m glad you like it. I’ve messed around enough, I’m content to just move the origin to the center. Another script in whic I use extrusion is a “hole filler” or “loop filler.” It works as long as there is a “clear line of sight” from each vertex of the loop to the median point of the loop (the average of all vert locations). Otherwise you get things crossing over each other.

  1. Start with a loop
  2. Get the average distance from each vertex to the median point
  3. Using a predefined step, figure out how many extrude and scale’s will be needed to collapse it to center
  4. Loop through, extrude/scale/remove doubles/relax (you will need Loop Tools add on).

It attempts to fill it with a relatively evenly spaced mesh.

http://dl.dropbox.com/u/2586482/SreenShots/unfilled_loop.png

http://dl.dropbox.com/u/2586482/SreenShots/filled_loop.png

seems handy!

you might be interested in a small test i did, instead of moving the origin…


especially the lines with ‘dif_vector’