Commit graph CultLib/src/GameCult.Geometry/CultGeometryQuadMesh.cs
Author SHA1 Message Date
Meta Vens
967142e413 Fix surface-nets mutation findings F1/F3/F4/F7/F8 (production code)
F1: Extract's locals (position, v0..v3) were assigned through pattern-match
and short-circuited out-var chains whose definite-assignment analysis breaks
under a single mutated operator, so Stryker's Safe Mode dropped all 98
mutants in Extract as compile errors. Restructured to plain null checks and
a for-loop over a uint[4] so every local is unconditionally assigned; no
mutation of a boolean operator can make it fail to compile.

F3: deleted the `<= 1e-20f` fallback in Interpolate. A straddling edge always
has delta > 0 (.NET preserves subnormals), so the guard only ever replaced a
correct interpolated value with a wrong 0.5 midpoint.

F4: deleted the per-quad geometric cross-product winding test. Orientation
now comes only from the topological inside/outside flag plus a fixed
per-axis handedness sign (OrientationSign; axis 1's (X, Z) perpendicular
pairing is the one left-handed case, X x Z == -Y). This is now determined
purely by which endpoint of the crossing edge is inside and the axis, never
by quad geometry, so degenerate (zero-area) quads orient consistently with
their neighbours instead of falling back to an unstable dot-product sign.

F7: Extract now rejects any non-finite sample (NaN or +-Infinity) with
ArgumentException, in the same style as the existing shape/cellSize checks.

F8: collapsed three duplicated (edge, axis) mappings - TryGetOtherEndpoint's
per-axis switch, the three Axis*EdgeStarts tables plus the axis==0?1:0
ternaries in AccumulateAxisEdges, and TryGetQuadCells' three axis-specific
corner blocks - into one PerpAxes/PerimeterLoop table pair, used by all
three. Replaced the three duplicated `<= isoValue` inside tests with one
IsInside predicate. Deleted the per-axis trailing `InRange(x, cellsX)` /
`InRange(y, cellsY)` / `InRange(z, cellsZ)` checks (provably always true,
since TryGetOtherEndpoint already guarantees the edge's own-axis coordinate
indexes a valid cell) and the explicit TryGetValue+throw invariant guard
(the four cells around a crossing edge are proven to always have a vertex;
a direct dictionary index now fails loudly via KeyNotFoundException if that
invariant is ever actually violated, with no reachable branch to maintain).

F6: deleted CultGeometryGridEdge's <, >, <=, >= operators (CultGeometryQuadMesh.cs).
Nothing in production or tests used them; ordering goes through CompareTo.
!= is kept only because C# requires it whenever == is defined (CS0216).

Builds clean; does not touch CultGeometryIsoSurface.cs, CultGeometryDocuments.cs,
or ISOSURFACE-PROVENANCE.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 19:29:45 +02:00
Meta Vens
7a656a7ec2 Add surface nets extraction and face-weighted normals to GameCult.Geometry
Implements CultGeometrySurfaceNets.Extract (welded CultGeometryQuadMesh, one
quad per interior crossing grid edge, outward-oriented winding) and
CultGeometryQuadNormals.FaceWeighted (unnormalized diagonal-cross-product
area weighting, matching CultGeometryIsoSurface's sign convention and
degenerate-normal rule). Fresh implementation per SURFACE-NETS-PROVENANCE.md;
no code or tables copied from the cited literature.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 18:06:29 +02:00