Select vertices within another object

Hi !

I’m trying to build a script that allows me to select the vertices of an object (objA) that are within another mesh object (objB).

For now, my idea is to go through the vertices of objA and test if each is within objB. I haven’t found any script that does this kind of test, so I tried to build my own. I calculate the number of intersection of objB with a line build from the current vertex and a “far enough” point : if the number of intersection is odd, the vertex is within objB. I wanted to use the ray_cast function, but it only gives the first intersection with objB. So, the only way I can think of is to go through every face of objB and test if the line intersects it to gather all the intersections.

So here is my question : is there a script that already does a selection of vertices within another mesh, or a more convenient python function to test intersections ?

Many thanks !

Your question is a little bit imprecise:
Are your objects planar? Are they 3D and with or without holes? Are they convex? Are they …?!
Is your mesh ONLY vertices? Or if not ‘only’ some, and the same edges without faces?

Meaning the question of ‘inside’ depends …

Thanks for the thread liero, I missed this one and it seems pretty interesting, I’ll dig into it.

PKHG : In fact, I want to build vertex groups for a mesh from its intersections with other meshes. So I’m really only interested with vertices for the first mesh, therefore its topology can be anything, but for the other meshes, I try to keep them hole free and convex (and if it has to be mandatory for the script to work, I can deal with it).

EDIT : It appears that Dynamic Paint with Weight surface type gives me exactly what I need (thanks to its vertex group output). But for the info, the “closest_point_on_mesh” technique gave me good results too.

EDIT 2 : I’ve adapted the point in mesh script found here for Blender 2.6 :


def pointInsideMesh(pt, ob):
    Intersect = mathutils.geometry.intersect_ray_tri # less dict lookups.
        
    def ptInFaceXYBounds(f, pt):
        co= obvert[f.vertices[0]].co
        xmax= xmin= co.x
        ymax= ymin= co.y
                
        co= obvert[f.vertices[1]].co
        xmax= max(xmax, co.x)
        xmin= min(xmin, co.x)
        ymax= max(ymax, co.y)
        ymin= min(ymin, co.y)
                
        co= obvert[f.vertices[2]].co
        xmax= max(xmax, co.x)
        xmin= min(xmin, co.x)
        ymax= max(ymax, co.y)
        ymin= min(ymin, co.y)
                
        if len(f.vertices)==4: 
            co= obvert[f.vertices[3]].co
            xmax= max(xmax, co.x)
            xmin= min(xmin, co.x)
            ymax= max(ymax, co.y)
            ymin= min(ymin, co.y)
        
        # Now we have the bounds, see if the point is in it.
        return xmin <= pt.x <= xmax and ymin <= pt.y <= ymax
        
    def faceIntersect(f):
        isect = Intersect(obvert[f.vertices[0]].co, obvert[f.vertices[1]].co, obvert[f.vertices[2]].co, ray, obSpacePt, 1) # Clipped.
        if not isect and len(f.vertices) == 4:
            isect = Intersect(obvert[f.vertices[0]].co, obvert[f.vertices[2]].co, obvert[f.vertices[3]].co, ray, obSpacePt, 1) # Clipped.
                            
        return bool(isect and isect.z > obSpacePt.z) # This is so the ray only counts if its above the point. 
        
        
    obImvMat = mathutils.Matrix(ob.matrix_world)
    obImvMat.invert()
    pt.resize_4d()
    obSpacePt = obImvMat * pt
    pt.resize_3d()
    obSpacePt.resize_3d()
    ray = mathutils.Vector()
    ray.x = 0
    ray.y = 0
    ray.z = 1
    me= ob.data
    obvert = ob.data.vertices
        
    # Here we find the number on intersecting faces, return true if an odd number (inside), false (outside) if its true.
    return len([None for f in me.faces if ptInFaceXYBounds(f, obSpacePt) if faceIntersect(f)]) % 2

From my tests, it gives a more robust result but is slower. Hope it helps !