Skip to content

fix: marching triangles isovalue degeneracies#251

Open
liamnwhite1 wants to merge 2 commits into
nmwsharp:masterfrom
liamnwhite1:fix/marching-triangles-isovalue-degeneracies
Open

fix: marching triangles isovalue degeneracies#251
liamnwhite1 wants to merge 2 commits into
nmwsharp:masterfrom
liamnwhite1:fix/marching-triangles-isovalue-degeneracies

Conversation

@liamnwhite1

Copy link
Copy Markdown
Contributor

Summary

This PR fixes marchingTriangles() so contours that pass exactly through mesh vertices are emitted instead of being dropped as degenerate faces.

The implementation now classifies scalar samples as below, equal to, above, or invalid relative to the requested isovalue, deduplicates contour hits per face, and keeps strict edge crossings in canonical edge coordinates so adjacent faces stitch into the same contour curve.

Problem Addressed

Originally, marchingTriangles() detected contour intersections by checking each face edge independently. When the isovalue landed exactly on a vertex, both incident edges in the same triangle reported that same vertex as a crossing.

That meant a valid contour segment could produce three hits on one face:

  • the exact isovalue vertex from one incident edge
  • the same exact isovalue vertex again from the other incident edge
  • a normal crossing on the opposite edge

The existing code only emitted faces with exactly two hits, so these valid contour segments were skipped.

There was also a subtle stitching risk while fixing this: shared-edge crossings must be represented in canonical Edge coordinates. If neighboring faces compute the same crossing from opposite halfedge orientations, tiny floating-point differences can make exact SurfacePoint equality fail, fragmenting one contour into separate components.

What Changed

  • Added explicit isovalue classification for vertex samples:

    • Below
    • Equal
    • Above
    • Invalid
  • Added per-face hit deduplication so repeated exact vertex hits collapse to one SurfacePoint(Vertex).

  • Handles exact contour cases directly:

    • one exact endpoint emits that vertex once
    • a whole iso-valued edge emits its two endpoint vertices
    • strict crossings still emit an edge point
  • Preserves contour stitching by storing strict crossings as SurfacePoint(e, t) in canonical Edge orientation, rather than face-local halfedge orientation.

  • Keeps ambiguous degenerate cases explicit:

    • zero hits: no contour through the face
    • one hit: contour only touches the face at a vertex
    • three hits: fully iso-valued/ambiguous face, skipped intentionally

Why This Fix Works

A valid contour segment through a triangle should be emitted whenever there are exactly two unique contour hits on that face.

By classifying exact isovalue vertices before interpolation and deduplicating hits, a face with an exact isovalue vertex plus an opposite-edge crossing now produces the expected two unique hits instead of three raw edge hits.

For ordinary crossings, using canonical edge coordinates ensures both faces adjacent to an edge produce exactly the same SurfacePoint, so getCurveComponents() can stitch the segments into a single curve.

Tests

Added focused regression coverage for:

  • a contour passing through an exact isovalue vertex
  • strict crossings across a shared edge stitching into one curve
  • fully iso-valued faces being skipped as ambiguous

Classify scalar samples as below, equal, or above the isovalue before
collecting contour hits. Deduplicate hits so an exact isovalue vertex shared by
two incident edges does not produce a three-hit face and get skipped.

Also skip ambiguous degenerate cases explicitly when a face has anything other
than two unique contour hits.
Add regression coverage for a contour passing through an exact isovalue vertex,
ensuring the face still emits a segment. Also cover fully iso-valued faces,
which should be skipped because the one-dimensional contour is ambiguous.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant