0
$\begingroup$

While in object mode, I would like to be able to select all the other objects in the scene that are touching or intersecting a given object. For example, if the active object was Suzanne, this hot key or technique would select all the yellow cubes in the scene instantly.

Is there such a technique? I know in this example it would be easy to select all the yellow cubes by hand, but in a more complex scene this becomes an issue.

Thanks for your help!

enter image description here

$\endgroup$
  • $\begingroup$ I'm not aware that such functionality existing in Blender, as far as I know. It might be possible to achieve this through python scripting, though I don't know enough about it to suggest anything. $\endgroup$ – Duarte Farrajota Ramos Apr 10 '17 at 23:51
1
$\begingroup$

An addon to do that:

enter image description here

It uses a BVH tree to check if meshes are overlapping. BVH trees are built from boundings at first step (presuming boundings are a box) then with bmesh (for the intersecting bounding objects).

Important though: the overlapping test will fail if meshes do not intersect. For instance a mesh which is entirely inside the active one will not be detected.

For information: using bmesh.transform to obtain object's coordinates in world is mush faster than a Python calculation.

bl_info = {
    "name": "Select intersect active",
    "category": "Object",
}

import bpy
from mathutils import Vector
from mathutils.bvhtree import BVHTree
import bmesh
import time

#In this context, utility/debug function to check if bounding test are ok
def BoundingsToMesh( obj, scene ):
    name = obj.name + "_bounds"
    meshData = bpy.data.meshes.new( name )
    meshObj = bpy.data.objects.new( name, meshData )
    meshObj.matrix_world = obj.matrix_world.copy()

    meshObj.data.from_pydata( *BoundingsGeometry( obj ) )

    scene.objects.link( meshObj )

    return meshObj

#Create bounding geometry from an object
def BoundingsGeometry( obj ):
    verts = [Vector(co) for co in obj.bound_box]
    edges = []
    faces = [ (0,1,2,3), (4,5,1,0), (7,6,5,4), (3,2,6,7), (6,2,1,5), (7,4,0,3) ]
    return verts, edges, faces

#Translates bounding geometry in world coordinates
def BoundingsGeometryInWorld( obj ):
    verts, edges, faces = BoundingsGeometry( obj )
    return [obj.matrix_world * v for v in verts], edges, faces

#Get vertices and polygons from an object in world coordinates
def MeshGeometryInWorld( obj ):
    return [obj.matrix_world * v.co for v in obj.data.vertices], [], [p.vertices for p in obj.data.polygons]

#Create a BVH tree from bounding (world co)
def BVHFromBoundings( obj ):
    verts, edges, faces = BoundingsGeometryInWorld( obj )
    return BVHTree.FromPolygons( verts, faces )

#Create a BVH tree from mesh (world co)
def BVHFromMesh( obj ):
    verts, edges, faces = MeshGeometryInWorld( obj )
    return BVHTree.FromPolygons( verts, faces )

#Create a BVH tree from bmesh (world co)
def BVHFromBMesh( obj ):
    bm = bmesh.new()
    bm.from_mesh( obj.data )
    bm.transform( obj.matrix_world )
    result = BVHTree.FromBMesh( bm )
    del bm
    return result

#Test if a bvh tree overlap an object
def IntersectBVHObj( bvh, obj, toBvh ):
    objBvh = toBvh( obj )
    result = bvh.overlap( objBvh )
    del objBvh
    return result

#Test if two objects overlap
def IntersectObjObj( obj, others, toBvh ):
    objBvh = toBvh( obj )
    result = [other for other in others if IntersectBVHObj( objBvh, other, toBvh )]
    del objBvh
    return result

#Test if two objects overlap using boundings method
def IntersectBoundings( obj, others ):
    return IntersectObjObj( obj, others, BVHFromBoundings )

#Test if two objects overlap using mesh method
def IntersectMesh( obj, others ):
    return IntersectObjObj( obj, others, BVHFromMesh )

#Test if two objects overlap using bmesh method
def IntersectBMesh( obj, others ):
    return IntersectObjObj( obj, others, BVHFromBMesh )

#Select objects which overlap another one
def SelectIntersect( obj, scene, others, intersectBounding ):
    result = IntersectBoundings( obj, others )

    if intersectBounding == False:
        #startTime = time.time()
        #for i in range( 1000 ):
            result = IntersectBMesh( obj, result )
        #print( "elapsed", time.time() - startTime )

    for o in result:
        o.select = True

class SelectIntersectActive(bpy.types.Operator):
    bl_idname = "object.select_intersect_active"
    bl_label = "Select intersect active"
    bl_options = {'REGISTER', 'UNDO'}

    intersectBounding = bpy.props.BoolProperty(name="Intersect bounding", default=False)

    @classmethod 
    def poll(cls, context):
        scene = context.scene
        obj = scene.objects.active
        return obj and obj.type == 'MESH' and obj.mode == 'OBJECT'

    def execute(self, context):
        scene = context.scene
        obj = scene.objects.active

        #Keep only non selected objects (cumulative selection)
        SelectIntersect( obj, scene, [o for o in scene.objects if o.select == False and o != obj], self.intersectBounding )

        return {'FINISHED'}

def menu_func(self, context):
    self.layout.operator(SelectIntersectActive.bl_idname)

def register():
    bpy.utils.register_class(SelectIntersectActive)
    bpy.types.VIEW3D_MT_select_object.append(menu_func)

def unregister():
    bpy.utils.unregister_class(ObjectCursorArray)
    bpy.types.VIEW3D_MT_select_object.remove(menu_func)


if __name__ == "__main__":
    register()

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.