# extrusions and boolean modifiers

I'm starting to use blender and I stumbled into a couple of problems.

I have several 2d shapes, mostly circles and closed polygons. For the sake of simplicity I started to work with them as if they live on z=0 plane. My final goal is to be able to perform something like boolean modifiers on the 2d shapes in order to extrude the results, for example making two circular holes on a rectangle, using the python API.

First question. If I take a rectangle on the z=0 plane and then apply a bmesh.ops.extrude_face_region on the mesh...the face along the first edge is missing:

import bpy
import bmesh

rect_v = [(-2,-2,0),(5,-2,0),(5,2,0),(-2,2,0)]
rect_e = [(i,(i+1)%len(rect_v)) for i in range(len(rect_v))]
rect_f = [tuple(range(len(rect_v)))]

me_rect = bpy.data.meshes.new("Rect")
obj_rect = bpy.data.objects.new("Rect", me_rect)
me_rect.from_pydata(rect_v, rect_e, rect_f)
me_rect.update()

bm4 = bmesh.new()
bm4.from_mesh(me_rect)
bmesh.ops.translate(bm4,verts=bm4.verts, vec=(0.0, 0.0, -1.0))

edges_start = bm4.edges[:]
faces_start = bm4.faces[:]
verts_start = bm4.verts[:]
ret = bmesh.ops.extrude_face_region(bm4, geom = edges_start + faces_start)
geom_extrude_mid = ret["geom"]
verts_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMVert)]
edges_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMEdge) and ele.is_boundary]
bmesh.ops.translate(bm4,verts=verts_extrude_b, vec=(0.0, 0.0, 2.0))
bm4.to_mesh(me_rect)

me_rect.update()


Can someone tell me why this is happenning?

Second question. I addition to my initial rectangle I create two circles. I join them into a single mesh. Then I extrude them by the edges and finally I try to perform a boolean difference between the 2d rectangle and the extruded circles (I came up with this workaround when I found that extrusions didn't work well on ovelapped shapes, this procedure actually works in other instances, for example want to generate a 2d ring from two concentric circles -no joint mesh in that case- see the end of this post). When the modifier is executed the application crashes, and running the script on console throws an EXCEPTION_ACCESS_VIOLATION. I checked for the normals on the objects and they look fine to me.

The full script:

import bpy
import bmesh

rect_v = [(-2,-2,0),(5,-2,0),(5,2,0),(-2,2,0)]
rect_e = [(i,(i+1)%len(rect_v)) for i in range(len(rect_v))]

rect_f = [tuple(range(len(rect_v)))]

me_rect = bpy.data.meshes.new("Rect")
obj_rect = bpy.data.objects.new("Rect", me_rect)
me_rect.from_pydata(rect_v, rect_e, rect_f)
me_rect.update()
# end Rectangle

c1mesh = bpy.data.meshes.new("Disk1")
c1object = bpy.data.objects.new("Disk1", c1mesh)
bm1 = bmesh.new()
bm1.from_mesh(c1mesh)
bmesh.ops.create_circle(bm1, cap_ends=False, diameter=1, segments=128)
bm1.to_mesh(c1mesh)
#bm1.free()

c2mesh = bpy.data.meshes.new("Disk2")
c2object = bpy.data.objects.new("Disk2", c2mesh)
bm2 = bmesh.new()
bm2.from_mesh(c2mesh)
bmesh.ops.create_circle(bm2, cap_ends=False, diameter=1, segments=128)
bmesh.ops.translate(bm2, verts=bm2.verts, vec=(3.0, 0.0, 0.0))
bm2.to_mesh(c2mesh)

me = bpy.data.meshes.new("Joint")
joint_obj = bpy.data.objects.new("Joint", me)

bm3 = bmesh.new()
bm3.from_mesh(c1mesh)
bm3.from_mesh(c2mesh)

bm3.to_mesh(me)

# ancillary extrude
bmesh.ops.translate(bm3, verts=bm3.verts, vec=(0.0, 0.0, -1.01))
edges_start = bm3.edges[:]
faces_start = []
verts_start = bm3.verts[:]

ret = bmesh.ops.extrude_edge_only(bm3, edges = edges_start)
geom_extrude_mid = ret["geom"]
verts_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMVert)]
edges_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMEdge) and ele.is_boundary]

bmesh.ops.translate(bm3,verts=verts_extrude_b, vec=(0.0, 0.0, 2.02))
bm3.to_mesh(me)
bm3.free()
me.update()

bm4.to_mesh(me_rect)

# this crashes blender, also if I comment this out and try to do it from
# the GUI it also crashes
obj_rect.select= True
bpy.context.scene.objects.active = obj_rect
bool_one = obj_rect.modifiers.new(type="BOOLEAN", name="bool1")
bool_one.object = joint_obj
bool_one.operation = 'DIFFERENCE'

bpy.ops.object.modifier_apply(apply_as='DATA', modifier="bool1")


Here is a working example of what I'm trying to achieve (cylinder with hole from two concentric circles):

import bmesh
import bpy

c1mesh = bpy.data.meshes.new("Disk1")
c1object = bpy.data.objects.new("Disk1", c1mesh)
bm = bmesh.new()
bm.from_mesh(c1mesh)
bmesh.ops.create_circle(bm, cap_ends=True, diameter=2, segments=128)
bm.to_mesh(c1mesh)
bm.free()

c2mesh = bpy.data.meshes.new("Disk2")
c2object = bpy.data.objects.new("Disk2", c2mesh)

bm = bmesh.new()
bm.from_mesh(c2mesh)
bmesh.ops.create_circle(bm, cap_ends=False, diameter=1, segments=128)
bmesh.ops.translate(
bm,
verts=bm.verts,
vec=(0.0, 0.0, -0.01))

edges_start = bm.edges[:]
faces_start = []
verts_start = bm.verts[:]
ret = bmesh.ops.extrude_edge_only(bm, edges = edges_start)
geom_extrude_mid = ret["geom"]
verts_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMVert)]
edges_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMEdge) and ele.is_boundary]

bmesh.ops.translate(
bm,
verts=verts_extrude_b,
vec=(0.0, 0.0, 0.02))

bm.to_mesh(c2mesh)
c1object.select= True
bpy.context.scene.objects.active = c1object
bool_one = c1object.modifiers.new(type="BOOLEAN", name="bool1")
bool_one.object = c2object
bool_one.operation = 'DIFFERENCE'

bpy.ops.object.modifier_apply(apply_as='DATA', modifier="bool1")
bpy.ops.object.select_all(action='DESELECT')
c2object.select = True
bpy.ops.object.delete()
bm.free()

bm = bmesh.new()
bm.from_mesh(c1mesh)
edges_start = bm.edges[:]
verts_start = bm.verts[:]
faces_start = bm.faces[:]

ret = bmesh.ops.extrude_face_region(bm, geom = edges_start + faces_start)
geom_extrude_mid = ret["geom"]
verts_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMVert)]
edges_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMEdge) and ele.is_boundary]

bmesh.ops.translate(
bm,
verts=verts_extrude_b,
vec=(0.0, 0.0, 2))

bm.to_mesh(c1mesh)
c1mesh.update()
bm.free()


The answer to my problem was that my 2d polygons (the rectangle in my example) was non-manifold.

After hours of googling around and playing with the GUI I discovered that if I changed the way that I create the polygon mesh:

rect_v = [(-2,-2,0),(5,-2,0),(5,2,0),(-2,2,0)]
rect_e = [(i,(i+1)%len(rect_v)) for i in range(len(rect_v))]

rect_f = [tuple(range(len(rect_v)))]

me_rect = bpy.data.meshes.new("Rect")
obj_rect = bpy.data.objects.new("Rect", me_rect)
me_rect.from_pydata(rect_v, rect_e, rect_f)
me_rect.update()


to

rect_v = [(-2,-2,0),(5,-2,0),(5,2,0),(-2,2,0)]
#rect_e = [(i,(i+1)%len(rect_v)) for i in range(len(rect_v))]
rect_e = []
rect_f = [tuple(range(len(rect_v)))]

me_rect = bpy.data.meshes.new("Rect")
obj_rect = bpy.data.objects.new("Rect", me_rect)