mikedh / trimesh

Python library for loading and using triangular meshes.
https://trimesh.org
MIT License
3.02k stars 583 forks source link

Efficient way to check if a list of meshes contains points closer to their surfaces #2244

Closed amdshameer closed 4 months ago

amdshameer commented 4 months ago

@mikedh Thank you so much for a wonderful package! I need your suggestion on the following:

Currently, I am looping through all the meshes, and check if a distance threshold is reached for every point(obtained from some other process) that is closer to the mesh surface using RayMeshIntersector. I have 100 meshes, and the number points closer to the surface varies between (30,3) to (50,3). Is there any better and efficient way to do it instead of the code below?

trimesh version: 3.23.5 and python2.7


from scipy.spatial import distance

dist_threshold = 0.00005

# rows: number of meshes, cols: number of surface points
points_present_on_meshes = np.empty(( len(meshes), surface_points.shape[0] ))

for mesh_id, mesh in enumerate(meshes):
    # create RayMeshIntersector
    ray_mesh_intersector = trimesh.ray.ray_triangle.RayMeshIntersector(mesh)

    temp_on_surface = [False]*len( surface_points )

    for surface_id, surface_point in enumerate(surface_points):

        ray_direction = surface_point.reshape(1,3) - mesh.center_mass.reshape(1,3)
        ray_direction /= np.linalg.norm(ray_direction)

        # find where the point intersects on a mesh surface
        intersections_on_mesh_surface, _1, _2 = ray_mesh_intersector.intersects_location(mesh.center_mass.reshape(1,3), ray_direction)

        dist = distance.cdist(surface_point, intersections_on_mesh_surface)[0][0]
        if dist <= dist_threshold:
            temp_on_surface[surface_id] = True

    points_present_on_meshes[mesh_id,:] = temp_on_surface
Kiord commented 4 months ago

Hello,

This line bothers me :

ray_direction = surface_point.reshape(1,3) - mesh.center_mass.reshape(1,3)

This ray has no reason to be the shortest path to the mesh (especially if it is not smooth).

I think you should look into trimesh.proximity.closest_point instead of this ray-based approach. I also suggest to batch the surface_points to improve the performances.

This would reduce your code to these three lines:

for mesh_idx, mesh in enumerate(meshes): 
    _, dist, _ = trimesh.proximity.closest_point(mesh, surface_points)
    points_present_on_meshes[mesh_idx, dist < dist_threshold] = True
amdshameer commented 4 months ago

@Kiord Thank you for that suggestion!