I need to write a script that randomly distributes spheres (around 300) in a specific space and after the placement of the spheres I need to randomly distribute cylinders(5 times the number of spheres) with random orientation. All the spheres and cylinders should not overlap. After the spheres and cylinders I need to fill a percentage of the remaining space with ellipsoids. I managed to distribute the spheres without overlapping by generating random locations, but I still have problems with the cylinders mostly because of the random orientation. My question is if there is any way for Blender to return the volume coordinates of an object when it is created, so that I can check for overlaps or if you possibly know any other methods to avoid overlapping.
1 Answer
$\begingroup$
$\endgroup$
2
I have this script,
...
# Function to calculate the distance between two points
def distance(a, b) :
'''
list , list --> float
a = list with three element
b = list with three element
return the distance between two points in float
'''
return sqrt((a[0]-b[0])**2+(a[1]-b[1])**2+(a[2]-b[2])**2)
# How many Sphere you want to add
count = 50
# Cylinder properties
radius = 0.03
depth = 0.2
# The sphere will be created between -domain <--> domain
domain = 0.5
# Max time to try finding a new location before break the loop
maxTry = 50
# Variable to count how many try has been done
Try = 0
# list with three element to generate locations
location = [0, 0, 0]
# Variable to hold the distant between balls
dist = 0
# True == Won't collide , False == Will collide
State = True
# This tuple will hold centers of created spheres
locList = ()
while count > 0 :
# Calculate x, y, z position
location[0] = randint(-domain*10, domain*10)/10.0
location[1] = randint(-domain*10, domain*10)/10.0
location[2] = randint(-domain*10, domain*10)/10.0
# Start check if it will collide with other spheres
for x in locList :
# Calculate the distant
dist = distance(x, location)
# If it's too close make State = False
if dist < radius*2 + 0.1 :
State = False
break
# If it's in a good position State = True
else :
State = True
# The distant is too close , recalculate the location
if State == False :
Try += 1
continue
# After Try reach maxTry break the loop
if Try > maxTry :
break
# Successfully found a New location
# Add this point
locList += (location[:],)
# Smooth the faces
bpy.ops.object.shade_smooth()
#Create a new sphere at the same location, and resize it to an cylinder
bpy.ops.mesh.primitive_cylinder_add(radius = 0.1, location = location)
#Give the cylinder a random orientation
bpy.ops.transform.rotate(value=(2*pi*random()-1), axis=((2*pi*random()-1), (2*pi*random()-1), (2*pi*random()-1)))
#Smooth the faces
bpy.ops.object.shade_smooth()
# reset Try
Try = 0
# Decrease the counter
count -= 1
The problem of this script is in the condition of overlap between two cylinder, someone can solve this problem of overlap?
-
$\begingroup$ The issue with the test
if dist < radius*2 + 0.1
is that the radius for a cylinder or cube is the distance from the center of the object to the center of the face not the edge or in the case of a cube the corner (furthest point from center). The test for a cube would be 2 * r * sqrt (3) or approximately 3.5x radius to avoid corners overlapping. This however essentially just tests against a larger sphere rejecting some possible solutions cubeA adjacent to cubeB along axis. $\endgroup$– RattCommented Dec 25, 2018 at 20:10 -
$\begingroup$ The condition: if dist <radius * 2 + 0.1, it is for the case of two spheres, but for the case of cylinders, there is a condition of non-overlapping between the bases between two cylinders and the condition between the distance between the two two centers of the two cylinders. about what you have written: cubeA adjacent to cubeB, I do not understand this, the problem is that we have a cube that contains objects (i.e: cylinders as an example). $\endgroup$– sadedCommented Dec 30, 2018 at 17:53