Scripting a boolean modifier loop, but I'm doing something wrong I would like to make an opaque screen with many circular holes of different diameters and locations by an automated by a python script.

The locations and sizes will come from an algorithm and will appear random and some holes will overlap.

The script doesn't quite run - it gets hung up on the line indicated where I am trying to say "use this cylinder to make the hole!



The error in the console:

Traceback (most recent call last):
  File "/Users/david/Documents/fishing/static concentrator/static concentrator v01.blend/Text", line 31, in &lt;module&gt;
TypeError: bpy_struct: item.attr = val: BooleanModifier.object ID type does not support assignment to its self
Error: Python script fail, look in the console for now...


The script:

import numpy as np
import bpy

# make a screen
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 2))
screen = bpy.context.active_object
screen.scale = 0.05, 2, 2
screen.location = 0, 0, 2

bpy.ops.mesh.primitive_cylinder_add(radius=1, depth=1,  location=(0, 0, 2))
cyl = bpy.context.active_object
cyl.rotation_euler = 0, 0.5*np.pi, 0
bpy.ops.object.select_all(action='DESELECT')


scales, offsets = np.array([4, 4, 0.1]), np.array([-0.5, 0, 1])

holes = (scales * (np.random.random(300).reshape(-1, 3) + offsets))

for y, z, r in holes:

    cyl.location = 0, y, z
    cyl.scale = r, r, 1

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

    # bpy.context.space_data.context = 'MODIFIER'
    bpy.ops.object.modifier_add(type='BOOLEAN')
    bpy.context.object.modifiers["Boolean"].operation = 'DIFFERENCE'
    bpy.context.object.modifiers["Boolean"].object = cyl  # Hey! Use this to cut the hole please!!
    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
    bpy.ops.object.select_all(action='DESELECT')


The alternate script with a tiny loop and without numpy: 

import bpy
import math

# make a screen
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 2))
screen = bpy.context.active_object
screen.scale = 0.05, 2, 2
screen.location = 0, 0, 2

# make a cylinder
bpy.ops.mesh.primitive_cylinder_add(radius=1, depth=1,  location=(0, 0, 2))
cyl = bpy.context.active_object
cyl.rotation_euler = 0, 0.5*math.pi, 0
bpy.ops.object.select_all(action='DESELECT')

holes = [(1, 3, 0.25), (0, 2, 0.15)]

for y, z, r in holes:

    cyl.location = 0, y, z
    cyl.scale = r, r, 1

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

    # bpy.context.space_data.context = 'MODIFIER'
    bpy.ops.object.modifier_add(type='BOOLEAN')
    bpy.context.object.modifiers["Boolean"].operation = 'DIFFERENCE'
    bpy.context.object.modifiers["Boolean"].object = cyl  # Hey! Use this to cut the hole please!!
    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
    bpy.ops.object.select_all(action='DESELECT')
This should work for you:

import bpy
import math

# make a screen
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 2))
screen = bpy.context.active_object
screen.scale = 0.05, 2, 2
screen.location = 0, 0, 2

# make a cylinder
bpy.ops.mesh.primitive_cylinder_add(radius=1, depth=1,  location=(0, 0, 2))
cyl = bpy.context.active_object
cyl.rotation_euler = 0, 0.5*math.pi, 0
bpy.ops.object.select_all(action='DESELECT')

holes = [(1, 3, 0.25), (0, 2, 0.15)]

for y, z, r in holes:

    cyl.location = 0, y, z
    cyl.scale = r, r, 1

    bpy.ops.object.select_all(action='DESELECT')
    screen.select = True  # this doesn't matter, the active object does
    bpy.context.scene.objects.active = screen

    # bpy.context.space_data.context = 'MODIFIER'
    bpy.ops.object.modifier_add(type='BOOLEAN')
    bpy.context.object.modifiers["Boolean"].operation = 'DIFFERENCE'
    bpy.context.object.modifiers["Boolean"].object = cyl  # Hey! Use this to cut the hole please!!
    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
    bpy.ops.object.select_all(action='DESELECT')


The key is that it doesn't matter what is selected, but what is active.