mesh_manipulation — mesh preprocessing & sampling

Purpose

Stateless free functions over an Open3D TriangleMesh: watertight repair + normals, area-weighted
surface sampling, per-triangle areas, and a camera up-vector. No class, no state — the low-level
geometry primitives the guidance stack imports.

Role in the system

  • Consumed by target_finder (EETargetFinder): imports sample_points_on_mesh,
    compute_triangle_areas, calc_up_vector for area-uniform candidate sampling and camera up-vector
    construction (target_finder.py:7,79,104,209).
  • Geometry helper safe_normalize comes from geometry.
  • Sibling of mesh (Mesh), which owns the stateful raycasting scene + kd-tree; this module is
    the lower-level repair/sampling toolbox (no scene, no caches).

Inputs / Outputs

  • In: an Open3D TriangleMesh; a forward direction for the up-vector.
  • Out: repaired meshes, (points, normals) clouds, per-triangle area arrays, and an up-vector
    orthogonal to a forward direction.

Key functions

  • prep_mesh — load → watertight → orient → normals (the standard load path) — utils/mesh_manipulation.py:55
  • make_watertight — ordered Open3D degeneracy/duplicate removal, in place — utils/mesh_manipulation.py:64
  • sample_points_on_mesh — exactly n_samples surface points + normals — utils/mesh_manipulation.py:9
  • compute_triangle_areas — per-triangle area — utils/mesh_manipulation.py:37
  • calc_up_vector — up vector orthogonal to a forward direction — utils/mesh_manipulation.py:78

Footguns

make_watertight order is load-bearing

The Open3D cleanup runs in a specific ORDER: degenerate triangles → duplicated triangles →
duplicated vertices → non-manifold edges → unreferenced vertices → recompute normals. (utils/INSIGHTS.md [mesh])

mesh · target_finder · geometry · terminology