# randomly distribute objects over a plane

I have a number of different objects (e.g. cube, cylinder, monkey, furniture, etc) which I would like to distribute randomly over a plane/surface (the floor in this case) without having any intersections between the objects themselves as well as the wall. The objects there is no problem to be rotated so that they fit the "room" structure.

From a quick view I noticed people suggesting using the particles operator or the randomize transform. Would any of these alternatives work? I would like to do this in a python script.

Testing sample/example:

This is the file with furniture that I would like to position over the floor plane in random positions:

Update:

It seems that using the randomize transform I can move the objects around the scene:

import bpy,random
from math import *

for obj in bpy.context.selected_objects:
bpy.ops.object.randomize_transform(random_seed =random.randint(0,100), loc=(2, 2, 0), scale=(1, 1, 1))


The problem now is how to specify that I want the objects to be only within the borders of the floor (or the wall) object. I was thinking to specify loc= to the limits of the the bounding box of the floor but this will not handle the extruded parts. So there is the possibility that the moved object will be outside or intersecting to the wall. Moreover, from what I've noticed the randomize transform does not handle intersections thus this is also something that I would need to address.

Update 2:

Based on the script from @james_t below as well as from this answer I've created the following solution:

import bpy,random
from math import *
from mathutils.bvhtree import BVHTree

import bmesh
import numpy as np
from mathutils import Vector

def numpy_apply_transforms(ob, co):
m = np.array(ob.matrix_world)
mat = m[:3, :3].T
loc = m[:3, 3]
return co @ mat + loc

def are_inside(points, bool_name, boundary='inside'):
"""
input:
points
- a list of vectors (can also be tuples/lists)
bm
- a manifold bmesh with verts and (edge/faces) for which the
returns:
a list
- a mask lists with True if the point is inside the bmesh, False otherwise
"""

rpoints = []

target_object = bpy.context.object
bool_object   = bpy.data.objects[bool_name]

#create mesh data
bm = bmesh.new()
bm.from_mesh(bool_object.data)
bmesh.ops.transform(bm, matrix=bool_object.matrix_world, verts=bm.verts) #local to global coord
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
bm.faces.ensure_lookup_table()
bvh = BVHTree.FromBMesh(bm, epsilon=0.0001)

points = numpy_apply_transforms(target_object, points) #local to global coord

# return points on polygons
for point in points:
fco, normal, _, _ = bvh.find_nearest(point)
p2 = fco - Vector(point)
v = p2.dot(normal)
if boundary == 'outside':
else:

return rpoints

obj_list = ['IKEA_bed_LEIRVIK', 'IKEA_chair_MARKUS']

#print(bpy.data.objects['Wall'].dimensions.x)
#print(bpy.data.objects['Wall'].dimensions.y)

for obj in obj_list:
obj = bpy.context.scene.objects.get(obj)
bpy.context.view_layer.objects.active = obj
if obj: obj.select_set(True)

maxIter = 5
placed = False

print("Object: {}".format(obj.name))
print( "origLocation: {}".format(obj.location) )

while(not placed):
print("Iteration: {}".format(maxIter))

if maxIter < 0:
print("gave up!!!")
break

# set object back to original location on each loop, to try again from that loc:
obj.location.x = bpy.data.objects['Floor'].location.x
obj.location.y = bpy.data.objects['Floor'].location.y

print( "startingLocation: {}".format(obj.location) )

# put object in new location
bpy.ops.object.randomize_transform( random_seed =random.randint(0,100), use_loc=True, loc=(bpy.data.objects['Floor'].dimensions.x/2, bpy.data.objects['Wall'].dimensions.y/2, 0.0), scale=(1, 1, 1))

print( "newLocation: {}".format(obj.location) )

# Check if object is out of wall boundary
rvalAry = are_inside(obj.bound_box, "Wall")
print(rvalAry)

if all(rvalAry):

# Check if object is colliding with other objects
for ob in obj_list:
ob = bpy.context.scene.objects.get(ob)
if obj == ob:
continue

rvalAry_ = are_inside(obj.bound_box, ob.name, 'outside')
print(rvalAry_)

if not any(rvalAry_):
print("Object placed!!!")
placed = True

maxIter -= 1
bpy.ops.object.select_all(action='DESELECT') # Deselect all objects


This seems to work perfectly for putting the objects within the wall boundaries in first place. However, for some reason it still gives a fail while the objects are within the wall boundary and not colliding to each other (for simplicity I just considered only two objects and set the maxIter=5 this should be enough to have an example showing up) which I do not understand why. What am I missing?

Update 3:

I've managed to solve the object overlapping with the following function:

def intersection_check(target_name, bool_name):

target_object = bpy.data.objects[target_name]
bool_object   = bpy.data.objects[bool_name]

#create mesh data
bm = bmesh.new()
bm.from_mesh(target_object.data)
bmesh.ops.transform(bm, matrix=target_object.matrix_world, verts=bm.verts) #local to global coord
bm.verts.ensure_lookup_table()
bm.edges.ensure_lookup_table()
bm.faces.ensure_lookup_table()
bvh = BVHTree.FromBMesh(bm, epsilon=0.0001)

#create mesh data
bm1 = bmesh.new()
bm1.from_mesh(bool_object.data)
bmesh.ops.transform(bm1, matrix=bool_object.matrix_world, verts=bm1.verts) #local to global coord
bm1.verts.ensure_lookup_table()
bm1.edges.ensure_lookup_table()
bm1.faces.ensure_lookup_table()
bvh1 = BVHTree.FromBMesh(bm1, epsilon=0.0001)

if bvh.overlap( bvh1 ):
return True
else:
return False


and then replacing the corresponding part from the previous update code snippet with the following:

            # Check if object is colliding with other objects
rvalAry_ = []
for ob in obj_list:
ob = bpy.context.scene.objects.get(ob)
if obj == ob:
continue

#                rvalAry_ = are_inside(obj.bound_box, ob.name, 'outside')
rvalAry_.append( intersection_check(obj.name, ob.name) )
print(rvalAry_)

if not any(rvalAry_):
print("Object placed!!!")
placed = True


so far it seems to work ok.

• And also adhere to the rules of feng shui ? Joking aside, this is pretty broad. Noticed people suggesting? please add something more substantial, links? Feb 18 '21 at 16:29
• Apologies for not linking the other threads that I found. Some of the links that I have shortlisted are the following blender.stackexchange.com/questions/3322/… blender.stackexchange.com/questions/33132/… blender.stackexchange.com/questions/75754/… stackoverflow.com/questions/60885338/… Feb 18 '21 at 22:43
• Is there any idea how I could check for intersections? For setting random location I could iterate over my objects and set it based on the dimensions of my "Wall" object: x = bpy.data.objects['Wall'].dimensions.x y = bpy.data.objects['Wall'].dimensions.y z = bpy.data.objects['Wall'].dimensions.z obj.location = (random.randrange(x),random.randrange(y) , random.randrange(z)) but then my concern is how to deal with the intersections. Feb 21 '21 at 20:21
• There is also the bpy.ops.object.randomize_transform() operator function but I couldn't figure how it works. Feb 22 '21 at 11:00
• Yup. After a little search and thinking perhaps blender.stackexchange.com/questions/31693/… offers a clue the ray_cast() methods let's you know if a point on the mesh is inside or outside, in terms of confirming whether two pieces of furniture overlap? Feb 25 '21 at 21:36

Here is perhaps a solution, using the closest_point_on_mesh operation. I just enhanced to test the extreme vertices (bound_box) on the object being placed to be sure that it is placed completely within the floor bounds. I tested with on odd shaped floor (not just a rectangle plane). Note that this solution assumes that the floor has many vertices (subdivide if not) so that the locality test (closest_point_on_mesh()) is accurate. One problem I could not solve was that

# set object back to original location on each loop, to try again from that loc:
obj.location = origLocation


was being ignored so I changed it to = floor.location.[xy] in the following code:

for obj in bpy.context.selected_objects:
maxIter = 50
placed = False
#origLocation = obj.location
#print( obj.location )
print( "obj.dimensions=" )
print( obj.dimensions )
origLocation = obj.location
print( "origLocation" )
print( origLocation )
while ( not placed ):
print( maxIter )
# set object back to original location on each loop, to try again from that loc:
obj.location.x = floor.location.x
obj.location.y = floor.location.y
print( "obj.location=" )
print( obj.location )
bpy.ops.object.randomize_transform( random_seed =random.randint(0,100), use_loc=True, loc=(0.5, 0.5, 0.0), scale=(1, 1, 1))
# check all boundary points:
locatn = obj.location
print( "new location=" )
print( locatn )
placed = True  # if any bounds are outside the floor plan, then reject (set to false)
for bb in obj.bound_box:
locatn.x = obj.location.x + bb[0]
locatn.y = obj.location.y + bb[1]
rvalAry = floor.closest_point_on_mesh( locatn, distance=0.1 )
if ( not rvalAry[0] ):
placed = False
maxIter -= 1
if ( (maxIter < 0) or (placed) ) :
placed = True
if ( maxIter < 0 ):
print( "gave up" )
obj.location = origLocation
else:
print( "placed" )
print( obj.location )
print( obj.location )

• Thanks @james_t, it seems interesting. I will test ASAP and give some feedback. Ideally skipping through your code I was thinking that possibly I could combine it with this solution blender.stackexchange.com/a/150047/106722 so that to address any possible overlapping at the same time. Feb 24 '21 at 22:52
• @james-t I tested your script but it is not always working. There are times that it is still putting part of the objects outside the wall object and it considers that it is inside. I've created an updated version in my initial question which works nicely for putting the objects within the wall boundaries but it fails when I have to check the collision with the other objects. Feb 25 '21 at 17:56
• Yes I did notice it fails sometimes and in fact I had to make "distance=0.1" as =0 was a problem. I thought perhaps it was because of the granularity of the floor mesh. It failed a lot when I had just a simple four-vertex plane, worked better as I sub-divided, and better still dependent on the spacing of the vectors. It would be nice if there was a closest_FACE_on_mesh() function; or one could calculate that if I weren't such a "lazy good enough" programmer, so to speak! Feb 25 '21 at 18:17
• I realized after posting that one should also build an array of placed objects and test against those also. Good catch! Feb 25 '21 at 18:19