I have a problem with some files I've received. I have two sets of models, compartment bounding files (just empty boxes that represent a space) and some geometry that will go into those spaces. Worth mentioning I'm not very experiences with python or blender.
I am trying to write a script to loop through each bound file, and within that loop also loop through every piece of internal geometry to check whether or not the geometry is inside the current bound file. If a model is inside the bound, I want to write the bounding box name and the model name to a CSV, which I have figured out. I need to also account for bounding shapes such as L and H, and I'm not sure BVH can do this or not.
Here is what I have so far, based on what I found in another thread. The problem is this currently only checks for intersecting meshes on faces, verts, or edges I believe, and is not returning any models that are inside the bound box, but not touching the bound box.
import bpy
import mathutils
import bmesh
import csv
scene = bpy.context.scene
BVHTree = mathutils.bvhtree.BVHTree
componentList = [obj for obj in bpy.data.collections['Collection'].objects]
boundsList = [obj for obj in bpy.data.collections['Bounds'].objects]
#show objects that are intersecting
def intersection_check():
#create and open a csv
csvfile = open(outputCSV, 'w')
wr = csv.writer(csvfile, quoting=csv.QUOTE_ALL)
#check every bounds object for intersection with every component object
for bound in boundsList:
for component in componentList:
print()
if bound == component:
continue
#create bmesh objects
bm1 = bmesh.new()
bm2 = bmesh.new()
#fill bmesh data from objects
bm1.from_mesh(scene.objects[bound.name].data)
bm2.from_mesh(scene.objects[component.name].data)
#applying location to the bmeshes
bm1.transform(scene.objects[bound.name].matrix_world)
bm2.transform(scene.objects[component.name].matrix_world)
#make BVH tree from BMesh of objects
bound_BVHtree = BVHTree.FromBMesh(bm1)
component_BVHtree = BVHTree.FromBMesh(bm2)
#get intersecting pairs
inter = bound_BVHtree.overlap(component_BVHtree)
#if list is empty, no objects are touching
if inter != []:
print(bound.name + " and " + component.name + " are touching!")
wr.writerow([bound.name, component.name])
# close the csv
csvfile.close()
Update 7/21/2021:
I've found a method that works on a smaller subset of geometry but not my entire set, for some reason. I've also reduced runtime significantly with a few tweaks to the loops and how the component points are grabbed. Unfortunately I'm unable to share the files I'm working with, so I apologize for that.
Can anyone see any reason I'd be getting false positives with this? I grabbed the are_inside function from another post and I'm not completely sure how it works.
New code:
import bpy
import os
import mathutils
from mathutils import Vector
import bmesh
import csv
context = bpy.context
scene = context.scene
BVHTree = mathutils.bvhtree.BVHTree
componentList = [obj for obj in bpy.data.collections['Collection'].objects]
boundList = [obj for obj in bpy.data.collections['Bounds'].objects]
def are_inside(points, bm):
"""
input:
points
- a list of vectors (can also be tuples/lists)
bm
- a manifold bmesh with verts and (edge/faces) for which the
normals are calculated already. (add bm.normal_update() otherwise)
returns:
a list
- a mask lists with True if the point is inside the bmesh, False otherwise
"""
rpoints = []
addp = rpoints.append
bvh = BVHTree.FromBMesh(bm, epsilon=0.00001)
# return points on polygons
for point in points:
fco, normal, _, _ = bvh.find_nearest(point)
p2 = fco - Vector(point)
v = p2.dot(normal)
addp(not v < 0.0) # addp(v >= 0.0) ?
return rpoints
def intersection_check(boundList, componentList):
#create and open a csv
csvfile = open(outputCSV, 'w', newline='')
wr = csv.writer(csvfile, quoting=csv.QUOTE_ALL)
#check every bound for intersection with every other object
for bound in boundList:
#create bmesh objects
bm1 = bmesh.new()
#fill bmesh data from objects
bm1.from_mesh(scene.objects[bound.name].data)
#applying location to the bmeshes
bm1.transform(scene.objects[bound.name].matrix_world)
bm1.normal_update()
for component in componentList:
#print()
if bound == component:
continue
p = [scene.objects[component.name].location]
if True in are_inside(p, bm1):
print(component.name + " is inside " + bound.name + "!")
wr.writerow([bound.name, component.name])
print('Intersection Check Complete')
csvfile.close()