utils/mesh.py — target satellite surface geometry

Mesh + SurfacePath: the stateless geometry oracle — raycasting scene, kd-trees, area-uniform sampling, and the orbit→surface aim path.

Triangle area

For vertices a,b,c\bm{a}, \bm{b}, \bm{c} of triangle ii:

Ai=12(ba)×(ca)A_i = \tfrac{1}{2}\lVert(\bm{b} - \bm{a}) \times (\bm{c} - \bm{a})\rVert

Stored at construction. Total area =jAj= \sum_j A_j feeds the coverage denominator (eq 7.1).

Area coverage — eq 7.1

coverage=iSAijAj\text{coverage} = \frac{\displaystyle\sum_{i \in \mathcal{S}} A_i}{\displaystyle\sum_j A_j}

S\mathcal{S} = triangles seen 1\geq 1 time. Mesh owns the areas; EETargetFinder owns the counts.

Area-uniform surface sampling

Open3D samples each triangle with probability Ai\propto A_i, then a uniform barycentric point. The file delegates to sample_points_uniformly; the internal barycentric map is:

p=(1u1)a+u1(1u2)b+u1u2c\bm{p} = (1 - \sqrt{u_1})\bm{a} + \sqrt{u_1}(1 - u_2)\bm{b} + \sqrt{u_1} u_2 \bm{c}

u1,u2U[0,1]u_1, u_2 \sim \mathcal{U}[0,1]. Global RNG seeded via o3d.utility.random.seedbuilt lazily.

Orbit → surface projection

Each COM-orbit point r(s)\bm{r}(s) is projected inward onto the mesh:

xsurf(s)=r(s)+thitd^,d^=r(s)r(s)\bm{x}_{\text{surf}}(s) = \bm{r}(s) + t_{\text{hit}} \hat{\bm{d}}, \qquad \hat{\bm{d}} = -\frac{\bm{r}(s)}{\lVert\bm{r}(s)\rVert}

Miss-fills, Savitzky–Golay smooth (window 151, poly 3), then rate-limit: Δxδmax\lVert \Delta\bm{x}\rVert \leq \delta_{\max}.

Surface path derivatives

Arclength ss parameterises the smoothed path. Derivatives by finite differences:

dxds(s),d2xds2(s)\frac{d\bm{x}}{ds}(s), \qquad \frac{d^2\bm{x}}{ds^2}(s)

eval2(s) returns (x,dx/ds,d2x/ds2)(\bm{x}, d\bm{x}/ds, d^2\bm{x}/ds^2) — the analytic-feedforward velocity and centripetal acceleration for the EE aim point.