mesh — target satellite surface geometry
Purpose
Owns the target-satellite mesh: the Open3D raycasting scene, triangle area/centroid tables,
kd-tree nearest-surface queries, area-uniform surface sampling, and the orbit→surface aim path
(SurfacePath). The stateless geometry oracle the guidance stack queries.
Role in the system
- Consumed by ee_guidance (
EEGuidance): constructs aMesh, buildssurface_path(orbit), and
callsSurfacePath.eval2(s)each step for the analytic-FF aim point (ee_guidance.py:93,99,277). - Consumed by target_finder (
EETargetFinder): holds its ownMeshcopy and raycasts through
geometry.scenefor candidate scoring + per-triangle FOV coverage marking (target_finder.py:54,59). - Consumed by plotter3d:
sample,surface_path, andscenefor the standalone report figures. - Geometry helpers
safe_normalize/saturatecome from geometry; orbit input is an
orbitOrbitGenerator(uniform-arclengthpath+arclength_samples).
Inputs / Outputs
- In:
cfg(mesh path,scoring.sampling.n_targets); query points / ray origins+directions; an
orbitfor the surface path. - Out:
Packages of nearest surface points + normals + distances (query*), ray hits
(raycast:t_hit, points, finite-hit mask), area-uniform point clouds (sample), and a
SurfacePathexposingx_surf,dx_ds,d2x_ds2witheval(s)/eval2(s).
Key methods
query— closest surface point per query;exact=Trueuses the o3d scene (true closest-on-triangle, slow), else the sampled-surface kd-tree (fast) —utils/mesh.py:54query_surface/query_triangle— nearest sampled-surface point / nearest triangle centroid (kd-tree) —utils/mesh.py:80/:89raycast— cast rays, returnt_hit, hit points, finite-hit mask —utils/mesh.py:97sample— area-uniform surface sample; seeds open3d’s global RNG (its only hook) —utils/mesh.py:112surface_path— build theSurfacePathprojecting the COM orbit onto the mesh —utils/mesh.py:124SurfacePath.eval2—x, dx/ds, d²x/ds²at arclengthsfor the analytic feedforward —utils/mesh.py:175_ensure_surface_samples— lazily build the sampled-surface kd-tree on first use (the only RNG-touching path) —utils/mesh.py:47
Footguns
open3d sampling mutates a GLOBAL RNG — surface samples are built LAZILY
sample_points_uniformlyhonors only the global seedo3d.utility.random.seed. Sampling at
construction would perturb RNG state other components rely on, so the sampled-surface kd-tree is
built lazily on first use (_ensure_surface_samples,seed=0) — the only RNG-touching path.
(utils/INSIGHTS.md[footgun])
EETargetFinderkeeps its own redundant Mesh/scene copy (until Chain B)Promoted from the
sandbox/mesh_ooprototype (Jun 8) and reconciled against the live
OrbitSurfacePathalgorithm. Until Chain B unifies the finder onto this class, the finder loads
a second mesh/scene — one redundant load/run, accepted deliberately. (utils/INSIGHTS.md[history])
Raw orbit→surface projection is full of
inf/nanmisses and facet jumpsA bare inward ray produces
inf/nanat concavities and discontinuous jumps at facet crossings.
SurfacePathcleans this in three stages sodx/ds(the analytic-FF velocity) stays bounded —
see Pseudocode. If no ray hits the mesh it asserts. (utils/INSIGHTS.md[mesh])
Pseudocode (SurfacePath construction)
dirs = -path / |path| # inward ray from each COM-orbit point
t_hit = scene.cast_rays([path, dirs]) # project onto the mesh
x = path + t_hit * dirs # surface hit points
(1) fill misses (inf/nan) with nearest valid neighbour
(2) Savitzky-Golay smooth to C1 (window=151, poly=3)
(3) rate-limit residual jumps: x[i] = x[i-1] + saturate(x[i]-x[i-1], max_step)
dx_ds = gradient(x_surf, s) # arclength derivative (FF velocity)
d2x_ds2 = gradient(dx_ds, s) # 2nd derivative (FF acceleration)
Equations & references
- Surface aim path feeds the analytic feedforward:
ẍ_surf = (d²x/ds²)·v_des²— see
analytic_feedforward and the singularity/coverage sheet current_sota > 6.
Related
ee_guidance · target_finder · orbit · geometry · analytic_feedforward · plotter3d · robot · terminology