I know that the closest_point_on_mesh
function in BPY can be used to find the closest point on any mesh to an arbitrary point in space. However, I am working on a project for which I need to take a vertex on a mesh object, and find the closest point on any other mesh object. Is there a method that can be used to do that? Thanks.
3 Answers
Using closest point on mesh.
Similarly to the answer here https://blender.stackexchange.com/a/40979/15543 code hacked together to find the closest point on mesh of all other mesh objects in the scene to vertex[0] of the active mesh object. Adds an Empty on the hit point.
import bpy
import bmesh
context = bpy.context
scene = context.scene
edit_obj = context.active_object
me = edit_obj.data
mesh_objects = [o for o in scene.objects if o.type == 'MESH']
bm = bmesh.new()
for sphere in mesh_objects:
if sphere == edit_obj:
continue
smwi = sphere.matrix_world.inverted()
bm.from_mesh(me)
bm.verts.ensure_lookup_table()
vert = bm.verts[0]
v1 = edit_obj.matrix_world * vert.co # global face median
local_pos = smwi * v1 # face cent in sphere local space
(hit, loc, norm, face_index) = sphere.closest_point_on_mesh(local_pos)
if hit:
v2 = sphere.matrix_world * loc
bpy.ops.object.empty_add(location=v2)
print(sphere.name, (v2 - v1).length)
bm.clear()
A base to do that by simply going through all objects vertices (so not really optimized if many vertices/objects) :
The result is a list of tuples [object, nearest vertice, distance].
import bpy
from mathutils import Vector
max = 100000 #max distance
point = Vector([0, 0, 0]) #reference point from which we seek the distances (set your reference vertex in global coordinates here)
result = [] #stores the results
for obj in bpy.data.objects:
pos = obj.matrix_world.inverted() * point #converts the reference to local space
shortest = None
shortestDist = max
for v in obj.data.vertices: #go throught all vertices
dist = (Vector( v.co ) - pos).length #calculate the distance
if dist < shortestDist : #test if better so far
shortest = v
shortestDist = dist
result.append( [obj, shortest, shortestDist] ) #append the result
print( result )
mathutils supports KDTrees, which can also be helpful in this scenario: https://docs.blender.org/api/current/mathutils.kdtree.html
from mathutils.kdtree import KDTree
def createKdTreeForObject(blenderObject):
mesh = blenderObject.data
size = len(mesh.vertices)
kd = KDTree(size)
for i, v in enumerate(mesh.vertices):
kd.insert(v.co, i)
kd.balance()
return kd
vertex = (1,0,1)
blenderObject = D.objects['Cube']
kdTree = createKdTreeForObject(blenderObject)
matrixWorld = blenderObject.matrix_world
invertedMatrixWorld = matrixWorld.inverted()
vertexInverted = invertedMatrixWorld @ Vector(vertex)
print("Closest 10 points")
for (co, index, dist) in kdTree.find_n(vertexInverted, 10):
print(" ", co, index, dist)
```