or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdanalysis.mdcore-operations.mdfile-io.mdindex.mdmesh-processing.mdpoint-clouds.mdspatial-queries.mdvisualization.md

spatial-queries.mddocs/

0

# Spatial Queries and Collision

1

2

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.

3

4

## Capabilities

5

6

### Ray Casting and Intersections

7

8

Cast rays against mesh geometry to find intersections.

9

10

```python { .api }

11

def ray_triangle(self, ray_origins, ray_directions, multiple_hits=True, **kwargs):

12

"""

13

Intersect rays with mesh triangles.

14

15

Parameters:

16

- ray_origins: (n, 3) ray starting points

17

- ray_directions: (n, 3) ray direction vectors

18

- multiple_hits: bool, return all intersections or just first

19

- **kwargs: additional ray casting options

20

21

Returns:

22

dict with keys:

23

- 'locations': (h, 3) intersection points

24

- 'index_ray': (h,) ray indices for each hit

25

- 'index_tri': (h,) triangle indices for each hit

26

- 't': (h,) parametric distance along rays

27

"""

28

29

def ray_pyembree(self, ray_origins, ray_directions, **kwargs):

30

"""

31

High-performance ray casting using Intel Embree.

32

33

Note: Requires pyembree optional dependency

34

35

Parameters:

36

- ray_origins: (n, 3) ray starting points

37

- ray_directions: (n, 3) ray direction vectors

38

- **kwargs: Embree-specific options

39

40

Returns:

41

Ray intersection results

42

"""

43

44

def intersects_ray(self, ray_origins, ray_directions) -> np.ndarray:

45

"""

46

Check if rays intersect mesh (boolean test).

47

48

Parameters:

49

- ray_origins: (n, 3) ray starting points

50

- ray_directions: (n, 3) ray direction vectors

51

52

Returns:

53

(n,) boolean array indicating intersections

54

"""

55

```

56

57

### Nearest Point Queries

58

59

Find nearest points, vertices, and faces on mesh surfaces.

60

61

```python { .api }

62

@property

63

def nearest(self):

64

"""Nearest point query interface"""

65

66

def nearest_point(self, points) -> tuple:

67

"""

68

Find nearest points on mesh surface.

69

70

Parameters:

71

- points: (n, 3) query points

72

73

Returns:

74

tuple: (closest_points, distances, triangle_ids)

75

- closest_points: (n, 3) nearest surface points

76

- distances: (n,) distances to surface

77

- triangle_ids: (n,) triangle indices of closest points

78

"""

79

80

def nearest_vertex(self, points) -> tuple:

81

"""

82

Find nearest mesh vertices.

83

84

Parameters:

85

- points: (n, 3) query points

86

87

Returns:

88

tuple: (vertex_ids, distances)

89

- vertex_ids: (n,) indices of nearest vertices

90

- distances: (n,) distances to nearest vertices

91

"""

92

93

def nearest_face(self, points) -> tuple:

94

"""

95

Find nearest face centers.

96

97

Parameters:

98

- points: (n, 3) query points

99

100

Returns:

101

tuple: (face_ids, distances)

102

- face_ids: (n,) indices of nearest faces

103

- distances: (n,) distances to face centers

104

"""

105

```

106

107

### Point Containment Testing

108

109

Test if points are inside or outside mesh volumes.

110

111

```python { .api }

112

def contains(self, points) -> np.ndarray:

113

"""

114

Test if points are inside the mesh volume.

115

116

Parameters:

117

- points: (n, 3) points to test

118

119

Returns:

120

(n,) boolean array, True for points inside mesh

121

"""

122

123

def ray_cast_contains(self, points) -> np.ndarray:

124

"""

125

Point-in-mesh testing using ray casting.

126

127

Parameters:

128

- points: (n, 3) points to test

129

130

Returns:

131

(n,) boolean array indicating containment

132

"""

133

134

def signed_distance(self, points) -> np.ndarray:

135

"""

136

Signed distance to mesh surface.

137

138

Parameters:

139

- points: (n, 3) query points

140

141

Returns:

142

(n,) signed distances (negative inside, positive outside)

143

"""

144

```

145

146

### Collision Detection

147

148

Detect collisions and compute contact information between meshes.

149

150

```python { .api }

151

def collision(self, other_mesh) -> dict:

152

"""

153

Check collision with another mesh.

154

155

Parameters:

156

- other_mesh: Trimesh object to test collision with

157

158

Returns:

159

dict with collision information:

160

- 'collision': bool, True if meshes collide

161

- 'contact_points': (n, 3) contact points

162

- 'contact_normals': (n, 3) contact normal vectors

163

- 'penetration_depth': float, maximum penetration

164

"""

165

166

def is_collision(self, other_mesh) -> bool:

167

"""

168

Fast boolean collision test.

169

170

Parameters:

171

- other_mesh: Trimesh object

172

173

Returns:

174

bool, True if meshes collide

175

"""

176

177

def collision_manager(self, other_meshes) -> dict:

178

"""

179

Manage collisions with multiple meshes.

180

181

Parameters:

182

- other_meshes: list of Trimesh objects

183

184

Returns:

185

dict mapping mesh pairs to collision results

186

"""

187

```

188

189

### Mesh Intersection and Overlap

190

191

Compute intersections and overlapping regions between meshes.

192

193

```python { .api }

194

def intersection_sphere(self, sphere_center, sphere_radius) -> 'Trimesh':

195

"""

196

Intersect mesh with sphere.

197

198

Parameters:

199

- sphere_center: (3,) center of sphere

200

- sphere_radius: float, sphere radius

201

202

Returns:

203

Trimesh containing intersection region

204

"""

205

206

def intersection_cylinder(self, cylinder_center, cylinder_axis, cylinder_radius, cylinder_height) -> 'Trimesh':

207

"""

208

Intersect mesh with cylinder.

209

210

Parameters:

211

- cylinder_center: (3,) center of cylinder

212

- cylinder_axis: (3,) cylinder axis direction

213

- cylinder_radius: float, cylinder radius

214

- cylinder_height: float, cylinder height

215

216

Returns:

217

Trimesh containing intersection region

218

"""

219

220

def overlap_volume(self, other_mesh) -> float:

221

"""

222

Volume of overlap with another mesh.

223

224

Parameters:

225

- other_mesh: Trimesh object

226

227

Returns:

228

float, overlapping volume

229

"""

230

```

231

232

### Spatial Acceleration Structures

233

234

Access and configure spatial acceleration for faster queries.

235

236

```python { .api }

237

@property

238

def kdtree(self):

239

"""KD-tree for vertex spatial queries"""

240

241

@property

242

def rtree(self):

243

"""R-tree for face bounding box queries"""

244

245

def build_kdtree(self) -> None:

246

"""Build KD-tree acceleration structure"""

247

248

def build_rtree(self) -> None:

249

"""Build R-tree acceleration structure"""

250

251

def query_ball_point(self, points, radius) -> list:

252

"""

253

Find all vertices within radius of query points.

254

255

Parameters:

256

- points: (n, 3) query points

257

- radius: float, search radius

258

259

Returns:

260

list of vertex index arrays for each query point

261

"""

262

263

def query_ball_tree(self, other_tree, radius) -> list:

264

"""

265

Find all vertex pairs within radius between meshes.

266

267

Parameters:

268

- other_tree: KD-tree of another mesh

269

- radius: float, search radius

270

271

Returns:

272

list of vertex index pairs

273

"""

274

```

275

276

### Distance and Proximity Analysis

277

278

Compute various distance metrics and proximity measures.

279

280

```python { .api }

281

def distance_to_mesh(self, other_mesh) -> dict:

282

"""

283

Comprehensive distance analysis to another mesh.

284

285

Parameters:

286

- other_mesh: Trimesh object

287

288

Returns:

289

dict with distance metrics:

290

- 'mean_distance': float, mean surface distance

291

- 'rms_distance': float, RMS distance

292

- 'hausdorff_distance': float, maximum distance

293

- 'min_distance': float, minimum distance

294

"""

295

296

def closest_point_cloud(self, point_cloud) -> tuple:

297

"""

298

Find closest points on mesh to point cloud.

299

300

Parameters:

301

- point_cloud: (n, 3) point coordinates

302

303

Returns:

304

tuple: (closest_points, distances, face_indices)

305

"""

306

307

def vertex_adjacency_graph(self) -> dict:

308

"""

309

Build vertex adjacency graph for mesh traversal.

310

311

Returns:

312

dict mapping vertex indices to adjacent vertex lists

313

"""

314

```

315

316

## Usage Examples

317

318

### Ray Casting

319

320

```python

321

import trimesh

322

import numpy as np

323

324

# Load mesh

325

mesh = trimesh.load('model.stl')

326

327

# Define rays (shooting downward from above)

328

ray_origins = np.array([

329

[0, 0, 5],

330

[1, 1, 5],

331

[-1, -1, 5]

332

])

333

ray_directions = np.array([

334

[0, 0, -1],

335

[0, 0, -1],

336

[0, 0, -1]

337

])

338

339

# Cast rays

340

intersections = mesh.ray_triangle(ray_origins, ray_directions)

341

342

print(f"Found {len(intersections['locations'])} intersections")

343

print(f"Intersection points:\n{intersections['locations']}")

344

print(f"Triangle indices: {intersections['index_tri']}")

345

print(f"Ray parameters: {intersections['t']}")

346

347

# Check if rays hit (boolean test)

348

hits = mesh.intersects_ray(ray_origins, ray_directions)

349

print(f"Ray hits: {hits}")

350

```

351

352

### Nearest Point Queries

353

354

```python

355

# Define query points

356

query_points = np.random.uniform(-2, 2, (100, 3))

357

358

# Find nearest points on surface

359

closest_points, distances, triangle_ids = mesh.nearest_point(query_points)

360

361

print(f"Mean distance to surface: {distances.mean():.4f}")

362

print(f"Max distance to surface: {distances.max():.4f}")

363

print(f"Min distance to surface: {distances.min():.4f}")

364

365

# Find nearest vertices

366

vertex_ids, vertex_distances = mesh.nearest_vertex(query_points)

367

print(f"Mean distance to nearest vertex: {vertex_distances.mean():.4f}")

368

369

# Visualize results

370

import matplotlib.pyplot as plt

371

from mpl_toolkits.mplot3d import Axes3D

372

373

fig = plt.figure(figsize=(12, 5))

374

375

# Plot distance histogram

376

ax1 = fig.add_subplot(121)

377

ax1.hist(distances, bins=20, alpha=0.7)

378

ax1.set_xlabel('Distance to Surface')

379

ax1.set_ylabel('Count')

380

ax1.set_title('Distance Distribution')

381

382

# Plot 3D points and nearest surface points

383

ax2 = fig.add_subplot(122, projection='3d')

384

ax2.scatter(query_points[:, 0], query_points[:, 1], query_points[:, 2],

385

c='red', alpha=0.6, label='Query Points')

386

ax2.scatter(closest_points[:, 0], closest_points[:, 1], closest_points[:, 2],

387

c='blue', alpha=0.6, label='Nearest Surface Points')

388

ax2.legend()

389

ax2.set_title('Query Points and Nearest Surface Points')

390

391

plt.tight_layout()

392

plt.show()

393

```

394

395

### Point Containment Testing

396

397

```python

398

# Generate test points

399

test_points = np.random.uniform(*mesh.bounds.T, (1000, 3))

400

401

# Test containment

402

inside = mesh.contains(test_points)

403

outside_points = test_points[~inside]

404

inside_points = test_points[inside]

405

406

print(f"Points inside mesh: {inside.sum()}")

407

print(f"Points outside mesh: {(~inside).sum()}")

408

print(f"Containment ratio: {inside.mean():.3f}")

409

410

# Compute signed distances

411

signed_distances = mesh.signed_distance(test_points)

412

print(f"Signed distance range: {signed_distances.min():.4f} to {signed_distances.max():.4f}")

413

414

# Visualize containment

415

fig = plt.figure(figsize=(10, 8))

416

ax = fig.add_subplot(111, projection='3d')

417

418

if len(inside_points) > 0:

419

ax.scatter(inside_points[:, 0], inside_points[:, 1], inside_points[:, 2],

420

c='green', alpha=0.6, s=20, label=f'Inside ({len(inside_points)} points)')

421

422

if len(outside_points) > 0:

423

ax.scatter(outside_points[:, 0], outside_points[:, 1], outside_points[:, 2],

424

c='red', alpha=0.6, s=20, label=f'Outside ({len(outside_points)} points)')

425

426

ax.legend()

427

ax.set_title('Point Containment Test')

428

plt.show()

429

```

430

431

### Collision Detection

432

433

```python

434

# Create two meshes for collision testing

435

sphere1 = trimesh.primitives.Sphere(center=[0, 0, 0], radius=1.0)

436

sphere2 = trimesh.primitives.Sphere(center=[1.5, 0, 0], radius=1.0)

437

sphere3 = trimesh.primitives.Sphere(center=[0.5, 0, 0], radius=1.0)

438

439

# Test collisions

440

collision1 = sphere1.collision(sphere2) # Should not collide

441

collision2 = sphere1.collision(sphere3) # Should collide

442

443

print(f"Sphere1 vs Sphere2 collision: {collision1['collision']}")

444

print(f"Sphere1 vs Sphere3 collision: {collision2['collision']}")

445

446

if collision2['collision']:

447

print(f"Contact points:\n{collision2['contact_points']}")

448

print(f"Contact normals:\n{collision2['contact_normals']}")

449

print(f"Penetration depth: {collision2['penetration_depth']:.4f}")

450

451

# Fast boolean collision test

452

is_colliding = sphere1.is_collision(sphere3)

453

print(f"Fast collision test: {is_colliding}")

454

455

# Compute overlap volume

456

overlap_vol = sphere1.overlap_volume(sphere3)

457

print(f"Overlap volume: {overlap_vol:.6f}")

458

```

459

460

### Distance Analysis

461

462

```python

463

# Load two meshes for comparison

464

mesh1 = trimesh.load('part1.stl')

465

mesh2 = trimesh.load('part2.stl')

466

467

# Comprehensive distance analysis

468

distance_info = mesh1.distance_to_mesh(mesh2)

469

470

print("Distance Analysis:")

471

print(f"Mean distance: {distance_info['mean_distance']:.6f}")

472

print(f"RMS distance: {distance_info['rms_distance']:.6f}")

473

print(f"Hausdorff distance: {distance_info['hausdorff_distance']:.6f}")

474

print(f"Minimum distance: {distance_info['min_distance']:.6f}")

475

476

# Sample points on mesh1 surface and find distances to mesh2

477

sample_points = mesh1.sample_surface(1000)

478

closest_points, distances, face_indices = mesh2.closest_point_cloud(sample_points)

479

480

# Analyze distance distribution

481

print(f"\nSurface sampling analysis:")

482

print(f"Mean distance: {distances.mean():.6f}")

483

print(f"Std deviation: {distances.std():.6f}")

484

print(f"95th percentile: {np.percentile(distances, 95):.6f}")

485

486

# Create distance color map

487

normalized_distances = (distances - distances.min()) / (distances.max() - distances.min())

488

colors = plt.cm.viridis(normalized_distances)

489

490

# Visualize distance-colored points

491

fig = plt.figure(figsize=(10, 8))

492

ax = fig.add_subplot(111, projection='3d')

493

scatter = ax.scatter(sample_points[:, 0], sample_points[:, 1], sample_points[:, 2],

494

c=distances, cmap='viridis', s=20)

495

plt.colorbar(scatter, label='Distance')

496

ax.set_title('Distance-Colored Surface Points')

497

plt.show()

498

```

499

500

### Spatial Acceleration

501

502

```python

503

# Build spatial acceleration structures

504

mesh.build_kdtree()

505

print("KD-tree built for vertex queries")

506

507

# Query points within radius

508

query_center = mesh.centroid

509

radius = 0.5

510

511

nearby_vertices = mesh.query_ball_point([query_center], radius)[0]

512

print(f"Found {len(nearby_vertices)} vertices within radius {radius}")

513

514

# Get coordinates of nearby vertices

515

nearby_coords = mesh.vertices[nearby_vertices]

516

print(f"Nearby vertex coordinates:\n{nearby_coords}")

517

518

# For large-scale proximity queries between meshes

519

other_mesh = trimesh.load('other_model.stl')

520

other_mesh.build_kdtree()

521

522

# Find vertex pairs within threshold distance

523

vertex_pairs = mesh.query_ball_tree(other_mesh.kdtree, radius=0.1)

524

print(f"Found {len(vertex_pairs)} vertex pairs within threshold")

525

```