Python script performing boolean operations slowing down I have a script which takes an SVG path, converts it to a mesh, joins all the edges together, extrudes it, and adds the missing faces. It then reads in a CNC drill file and drills holes in the mesh using a cylinder and the boolean DIFFERENCE operator.

As it stands, it works. However it starts out nice and quick, but rapidly each boolean operation starts to take longer and longer, ending up as a couple of seconds per operation.

The boolean section of the script I found somewhere online (I can't find where now), so I assume it's the right way to do it. But it may not be. So I'd like some pointers or ideas on how it can be sped up.

Here's the core of the script where the boolean work is done:

bpy.ops.mesh.primitive_cylinder_add()
bit = bpy.context.object
bit.name="Drill Bit"
bit.dimensions=[4,4,10]

def subtract(target, opObj):
   '''subtract opObj from the target'''

   # Deselect All
   bpy.ops.object.select_all(action='DESELECT')

   # Select the new object.
   target.select = True
   bpy.context.scene.objects.active = target

   # Add a modifier
   bpy.ops.object.modifier_add(type='BOOLEAN')

   mod = target.modifiers
   mod[0].name = "SubEmUp"
   mod[0].object = opObj
   mod[0].operation = 'DIFFERENCE'

   # Apply modifier - I assume this is the bit that is taking a long
   # time but I cannot be sure yet.
   bpy.ops.object.modifier_apply(apply_as='DATA', modifier=mod[0].name)


for line in content:
    if line == '%':
        inHeader = False
        continue
    if inHeader:
        # T61C0.300
        if line.startswith('T'):
            parts = line.split('C')
            drills[parts[0]] = float(parts[1])
    else:
        # T61
        if line.startswith('T'):
            drillWidth = drills[line]
            print("Selecting drill width " + str(drillWidth) + "mm")
            bit.dimensions=[drillWidth, drillWidth, 50]
            continue
        # X009050Y046150
        if line.startswith('X'):
            coords = line[1:].split('Y')
            x = float(coords[0])
            y = float(coords[1])
            x = x / 1000
            y = y / 1000
            print("Drilling at " + str(x) + "," + str(y))
            bit.location=[x, y, 0]
            subtract(pcb, bit)
            # I added this to see why the script was taking so long.
            bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)

bpy.ops.object.select_all(action='DESELECT')
bit.select = True
bpy.ops.object.delete()


pcb is the mesh generated earlier. 

Is there some way I can "batch up" all the boolean modifiers and perform them all in one operation? Would it be better to make one "drill bit" per hole and locate them all, then join them into one big drill object and subtract that from the main mesh? (would that even work?)
After some experimenting I found two things that can improve performance.

First is the mesh you are cutting into, cutting holes into a large face is slower than if it was subdivided into many faces, this would be making it easier for the boolean operation to find connecting edges.

For example the subdivided object on the right will give a faster boolean result than the single faced object on the left, by faster I mean it can cut the time almost in half.



In my testing I was starting with a cube so I could do a simple subdivide. With your extruded shape you may want to add loop cuts across your larger faces so you don't add unneeded cuts to smaller bevel edges etc.

For the second speedup, the really odd thing is that your approach of using one drill object that you move and reuse for each hole seems to be the slow way, I don't get why but creating and deleting a new drill object for each hole is faster.

Also using target.modifiers.new is faster than bpy.ops.object.modifier_add.

def drillIt(target, x, y, d):
    '''Drill a hole at x,y with d diameter - using a boolean modifier'''
    # this should get similar result as subtract()
    # for some reason this runs faster

    bpy.ops.mesh.primitive_cylinder_add(vertices=8, radius=d/2, depth=50,
                location=(x, y, 0))
    drill = bpy.context.object

    # Add a modifier
    mod = target.modifiers.new('Boolean',type='BOOLEAN')
    mod.object = drill
    mod.operation = 'DIFFERENCE'
    target.select = True
    bpy.context.scene.objects.active = target
    bpy.ops.object.modifier_apply(apply_as='DATA', modifier=mod.name)
    bpy.context.scene.objects.unlink(drill)


Remove the use of bit and instead of -

bit.location=[x, y, 0]
subtract(pcb, bit)


use -

drillIt(pcb, x, y, drillWidth)