Import, export, process, analyze and view triangular meshes.
Ray casting, nearest point queries, collision detection, and spatial acceleration structures for efficient geometric queries. These capabilities enable intersection testing, proximity analysis, and collision detection workflows.
Cast rays against mesh geometry to find intersections.
def ray_triangle(self, ray_origins, ray_directions, multiple_hits=True, **kwargs):
"""
Intersect rays with mesh triangles.
Parameters:
- ray_origins: (n, 3) ray starting points
- ray_directions: (n, 3) ray direction vectors
- multiple_hits: bool, return all intersections or just first
- **kwargs: additional ray casting options
Returns:
dict with keys:
- 'locations': (h, 3) intersection points
- 'index_ray': (h,) ray indices for each hit
- 'index_tri': (h,) triangle indices for each hit
- 't': (h,) parametric distance along rays
"""
def ray_pyembree(self, ray_origins, ray_directions, **kwargs):
"""
High-performance ray casting using Intel Embree.
Note: Requires pyembree optional dependency
Parameters:
- ray_origins: (n, 3) ray starting points
- ray_directions: (n, 3) ray direction vectors
- **kwargs: Embree-specific options
Returns:
Ray intersection results
"""
def intersects_ray(self, ray_origins, ray_directions) -> np.ndarray:
"""
Check if rays intersect mesh (boolean test).
Parameters:
- ray_origins: (n, 3) ray starting points
- ray_directions: (n, 3) ray direction vectors
Returns:
(n,) boolean array indicating intersections
"""Find nearest points, vertices, and faces on mesh surfaces.
@property
def nearest(self):
"""Nearest point query interface"""
def nearest_point(self, points) -> tuple:
"""
Find nearest points on mesh surface.
Parameters:
- points: (n, 3) query points
Returns:
tuple: (closest_points, distances, triangle_ids)
- closest_points: (n, 3) nearest surface points
- distances: (n,) distances to surface
- triangle_ids: (n,) triangle indices of closest points
"""
def nearest_vertex(self, points) -> tuple:
"""
Find nearest mesh vertices.
Parameters:
- points: (n, 3) query points
Returns:
tuple: (vertex_ids, distances)
- vertex_ids: (n,) indices of nearest vertices
- distances: (n,) distances to nearest vertices
"""
def nearest_face(self, points) -> tuple:
"""
Find nearest face centers.
Parameters:
- points: (n, 3) query points
Returns:
tuple: (face_ids, distances)
- face_ids: (n,) indices of nearest faces
- distances: (n,) distances to face centers
"""Test if points are inside or outside mesh volumes.
def contains(self, points) -> np.ndarray:
"""
Test if points are inside the mesh volume.
Parameters:
- points: (n, 3) points to test
Returns:
(n,) boolean array, True for points inside mesh
"""
def ray_cast_contains(self, points) -> np.ndarray:
"""
Point-in-mesh testing using ray casting.
Parameters:
- points: (n, 3) points to test
Returns:
(n,) boolean array indicating containment
"""
def signed_distance(self, points) -> np.ndarray:
"""
Signed distance to mesh surface.
Parameters:
- points: (n, 3) query points
Returns:
(n,) signed distances (negative inside, positive outside)
"""Detect collisions and compute contact information between meshes.
def collision(self, other_mesh) -> dict:
"""
Check collision with another mesh.
Parameters:
- other_mesh: Trimesh object to test collision with
Returns:
dict with collision information:
- 'collision': bool, True if meshes collide
- 'contact_points': (n, 3) contact points
- 'contact_normals': (n, 3) contact normal vectors
- 'penetration_depth': float, maximum penetration
"""
def is_collision(self, other_mesh) -> bool:
"""
Fast boolean collision test.
Parameters:
- other_mesh: Trimesh object
Returns:
bool, True if meshes collide
"""
def collision_manager(self, other_meshes) -> dict:
"""
Manage collisions with multiple meshes.
Parameters:
- other_meshes: list of Trimesh objects
Returns:
dict mapping mesh pairs to collision results
"""Compute intersections and overlapping regions between meshes.
def intersection_sphere(self, sphere_center, sphere_radius) -> 'Trimesh':
"""
Intersect mesh with sphere.
Parameters:
- sphere_center: (3,) center of sphere
- sphere_radius: float, sphere radius
Returns:
Trimesh containing intersection region
"""
def intersection_cylinder(self, cylinder_center, cylinder_axis, cylinder_radius, cylinder_height) -> 'Trimesh':
"""
Intersect mesh with cylinder.
Parameters:
- cylinder_center: (3,) center of cylinder
- cylinder_axis: (3,) cylinder axis direction
- cylinder_radius: float, cylinder radius
- cylinder_height: float, cylinder height
Returns:
Trimesh containing intersection region
"""
def overlap_volume(self, other_mesh) -> float:
"""
Volume of overlap with another mesh.
Parameters:
- other_mesh: Trimesh object
Returns:
float, overlapping volume
"""Access and configure spatial acceleration for faster queries.
@property
def kdtree(self):
"""KD-tree for vertex spatial queries"""
@property
def rtree(self):
"""R-tree for face bounding box queries"""
def build_kdtree(self) -> None:
"""Build KD-tree acceleration structure"""
def build_rtree(self) -> None:
"""Build R-tree acceleration structure"""
def query_ball_point(self, points, radius) -> list:
"""
Find all vertices within radius of query points.
Parameters:
- points: (n, 3) query points
- radius: float, search radius
Returns:
list of vertex index arrays for each query point
"""
def query_ball_tree(self, other_tree, radius) -> list:
"""
Find all vertex pairs within radius between meshes.
Parameters:
- other_tree: KD-tree of another mesh
- radius: float, search radius
Returns:
list of vertex index pairs
"""Compute various distance metrics and proximity measures.
def distance_to_mesh(self, other_mesh) -> dict:
"""
Comprehensive distance analysis to another mesh.
Parameters:
- other_mesh: Trimesh object
Returns:
dict with distance metrics:
- 'mean_distance': float, mean surface distance
- 'rms_distance': float, RMS distance
- 'hausdorff_distance': float, maximum distance
- 'min_distance': float, minimum distance
"""
def closest_point_cloud(self, point_cloud) -> tuple:
"""
Find closest points on mesh to point cloud.
Parameters:
- point_cloud: (n, 3) point coordinates
Returns:
tuple: (closest_points, distances, face_indices)
"""
def vertex_adjacency_graph(self) -> dict:
"""
Build vertex adjacency graph for mesh traversal.
Returns:
dict mapping vertex indices to adjacent vertex lists
"""import trimesh
import numpy as np
# Load mesh
mesh = trimesh.load('model.stl')
# Define rays (shooting downward from above)
ray_origins = np.array([
[0, 0, 5],
[1, 1, 5],
[-1, -1, 5]
])
ray_directions = np.array([
[0, 0, -1],
[0, 0, -1],
[0, 0, -1]
])
# Cast rays
intersections = mesh.ray_triangle(ray_origins, ray_directions)
print(f"Found {len(intersections['locations'])} intersections")
print(f"Intersection points:\n{intersections['locations']}")
print(f"Triangle indices: {intersections['index_tri']}")
print(f"Ray parameters: {intersections['t']}")
# Check if rays hit (boolean test)
hits = mesh.intersects_ray(ray_origins, ray_directions)
print(f"Ray hits: {hits}")# Define query points
query_points = np.random.uniform(-2, 2, (100, 3))
# Find nearest points on surface
closest_points, distances, triangle_ids = mesh.nearest_point(query_points)
print(f"Mean distance to surface: {distances.mean():.4f}")
print(f"Max distance to surface: {distances.max():.4f}")
print(f"Min distance to surface: {distances.min():.4f}")
# Find nearest vertices
vertex_ids, vertex_distances = mesh.nearest_vertex(query_points)
print(f"Mean distance to nearest vertex: {vertex_distances.mean():.4f}")
# Visualize results
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(12, 5))
# Plot distance histogram
ax1 = fig.add_subplot(121)
ax1.hist(distances, bins=20, alpha=0.7)
ax1.set_xlabel('Distance to Surface')
ax1.set_ylabel('Count')
ax1.set_title('Distance Distribution')
# Plot 3D points and nearest surface points
ax2 = fig.add_subplot(122, projection='3d')
ax2.scatter(query_points[:, 0], query_points[:, 1], query_points[:, 2],
c='red', alpha=0.6, label='Query Points')
ax2.scatter(closest_points[:, 0], closest_points[:, 1], closest_points[:, 2],
c='blue', alpha=0.6, label='Nearest Surface Points')
ax2.legend()
ax2.set_title('Query Points and Nearest Surface Points')
plt.tight_layout()
plt.show()# Generate test points
test_points = np.random.uniform(*mesh.bounds.T, (1000, 3))
# Test containment
inside = mesh.contains(test_points)
outside_points = test_points[~inside]
inside_points = test_points[inside]
print(f"Points inside mesh: {inside.sum()}")
print(f"Points outside mesh: {(~inside).sum()}")
print(f"Containment ratio: {inside.mean():.3f}")
# Compute signed distances
signed_distances = mesh.signed_distance(test_points)
print(f"Signed distance range: {signed_distances.min():.4f} to {signed_distances.max():.4f}")
# Visualize containment
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
if len(inside_points) > 0:
ax.scatter(inside_points[:, 0], inside_points[:, 1], inside_points[:, 2],
c='green', alpha=0.6, s=20, label=f'Inside ({len(inside_points)} points)')
if len(outside_points) > 0:
ax.scatter(outside_points[:, 0], outside_points[:, 1], outside_points[:, 2],
c='red', alpha=0.6, s=20, label=f'Outside ({len(outside_points)} points)')
ax.legend()
ax.set_title('Point Containment Test')
plt.show()# Create two meshes for collision testing
sphere1 = trimesh.primitives.Sphere(center=[0, 0, 0], radius=1.0)
sphere2 = trimesh.primitives.Sphere(center=[1.5, 0, 0], radius=1.0)
sphere3 = trimesh.primitives.Sphere(center=[0.5, 0, 0], radius=1.0)
# Test collisions
collision1 = sphere1.collision(sphere2) # Should not collide
collision2 = sphere1.collision(sphere3) # Should collide
print(f"Sphere1 vs Sphere2 collision: {collision1['collision']}")
print(f"Sphere1 vs Sphere3 collision: {collision2['collision']}")
if collision2['collision']:
print(f"Contact points:\n{collision2['contact_points']}")
print(f"Contact normals:\n{collision2['contact_normals']}")
print(f"Penetration depth: {collision2['penetration_depth']:.4f}")
# Fast boolean collision test
is_colliding = sphere1.is_collision(sphere3)
print(f"Fast collision test: {is_colliding}")
# Compute overlap volume
overlap_vol = sphere1.overlap_volume(sphere3)
print(f"Overlap volume: {overlap_vol:.6f}")# Load two meshes for comparison
mesh1 = trimesh.load('part1.stl')
mesh2 = trimesh.load('part2.stl')
# Comprehensive distance analysis
distance_info = mesh1.distance_to_mesh(mesh2)
print("Distance Analysis:")
print(f"Mean distance: {distance_info['mean_distance']:.6f}")
print(f"RMS distance: {distance_info['rms_distance']:.6f}")
print(f"Hausdorff distance: {distance_info['hausdorff_distance']:.6f}")
print(f"Minimum distance: {distance_info['min_distance']:.6f}")
# Sample points on mesh1 surface and find distances to mesh2
sample_points = mesh1.sample_surface(1000)
closest_points, distances, face_indices = mesh2.closest_point_cloud(sample_points)
# Analyze distance distribution
print(f"\nSurface sampling analysis:")
print(f"Mean distance: {distances.mean():.6f}")
print(f"Std deviation: {distances.std():.6f}")
print(f"95th percentile: {np.percentile(distances, 95):.6f}")
# Create distance color map
normalized_distances = (distances - distances.min()) / (distances.max() - distances.min())
colors = plt.cm.viridis(normalized_distances)
# Visualize distance-colored points
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
scatter = ax.scatter(sample_points[:, 0], sample_points[:, 1], sample_points[:, 2],
c=distances, cmap='viridis', s=20)
plt.colorbar(scatter, label='Distance')
ax.set_title('Distance-Colored Surface Points')
plt.show()# Build spatial acceleration structures
mesh.build_kdtree()
print("KD-tree built for vertex queries")
# Query points within radius
query_center = mesh.centroid
radius = 0.5
nearby_vertices = mesh.query_ball_point([query_center], radius)[0]
print(f"Found {len(nearby_vertices)} vertices within radius {radius}")
# Get coordinates of nearby vertices
nearby_coords = mesh.vertices[nearby_vertices]
print(f"Nearby vertex coordinates:\n{nearby_coords}")
# For large-scale proximity queries between meshes
other_mesh = trimesh.load('other_model.stl')
other_mesh.build_kdtree()
# Find vertex pairs within threshold distance
vertex_pairs = mesh.query_ball_tree(other_mesh.kdtree, radius=0.1)
print(f"Found {len(vertex_pairs)} vertex pairs within threshold")Install with Tessl CLI
npx tessl i tessl/pypi-trimesh