Skip to content

fix(tessellation): small holes in curved faces at coarse deflections; trim runs off by rounding - #37

Open
Basnederveen wants to merge 1 commit into
OpenGeometry-io:mainfrom
Bas-Automation-Services:fix/curved-trim-tessellation
Open

Basnederveen wants to merge 1 commit into
OpenGeometry-io:mainfrom
Bas-Automation-Services:fix/curved-trim-tessellation

Conversation

@Basnederveen

Copy link
Copy Markdown

What

Two failures when tessellating a curved face whose trim is not a UV rectangle (the earcut + refinement path):

  1. A small hole at a coarse deflection: "curved trim loop requires at least four samples". A hole through a curved wall is bounded by intersection curves. At a deflection on the order of the hole's size, each of them gets one segment, so the hole's loop has two samples. Circles and ellipses already get a floor (12 per turn); intersection curves don't.
    raise_short_planar_loops becomes raise_short_loops. Planar loops keep exactly the old rule (at least three points, raising circles and ellipses). A curved face's trim loop is now raised to at least four samples, raising any curved edge, intersection curves included. Only loops that used to fail change.

  2. A trim run off its corner vertex by rounding: "triangle orientation could not be resolved". The samples along an axis-parallel pcurve can differ by a few ulps from the corner vertex next to them, whose UV comes from the neighbouring pcurve (e.g. a run at v = 100 + 2 ulp ending at a corner at v = 100). The run is then not quite straight. Earcut cuts a near-zero-area ear along it, whose three 3D points lie on the edge (a circle in a plane normal to the axis), so the triangle's normal is perpendicular to the surface normal and the orientation dot product is exactly 0.
    In general_curved_trimmed_face, a ring coordinate within 64 ε (times the ring's magnitude) of the previous sample's is snapped to it. That is the same order as the 128 ε all_axis_aligned already uses. 3D sample points are unchanged.

Also, the orientation error and the refinement-triangle limit now name the face. The refinement-depth error already did.

Tests

  • New tessellation/tests/curved_trims.rs, on a quarter of a thick-walled tube (cylinder faces 100 long) with a radial hole of radius 0.4 through both walls:
    • a_small_hole_in_a_curved_face_tessellates_at_a_coarse_deflection: deflections 2 and 5, every face gets triangles. Before: "curved trim loop requires at least four samples".
    • a_trim_run_off_its_corner_vertex_by_rounding_tessellates: the outer wall's run at v = 100 is moved 1, 2 and 4 rounding steps outward, as a pcurve evaluated at a corner can be. Before: "triangle orientation could not be resolved".
  • cargo fmt --check, cargo clippy --all-targets -D warnings, and cargo test --all-targets (with CI=true) all pass, matching main.
  • npm run check:source, check:duplicates and check:cycles pass. check:api needs a built SDK and wasn't run (no public API changes).

Files

  • main/opengeometry/src/tessellation/loop_minimum.rs
  • main/opengeometry/src/tessellation/tessellate.rs
  • main/opengeometry/src/tessellation/trimmed_face.rs
  • main/opengeometry/src/tessellation/mesh.rs
  • main/opengeometry/src/tessellation/tests/curved_trims.rs (new), tests/mod.rs

🤖 Generated with Claude Code

… trim runs off by rounding

A hole through a curved wall is bounded by intersection curves; at a
deflection on the order of the hole each got one segment, a two-sample
trim loop: "curved trim loop requires at least four samples". The short
loop raise (planar loops only) now also raises a curved face's trim loop
to four samples through its curved edges, intersection curves included.
Planar loops keep the old rule.

Samples along an axis-parallel pcurve can differ by a few ulps from the
corner vertex next to them, whose UV comes from the neighbouring pcurve.
Earcut then cuts a near-zero-area ear along the run whose 3D points lie
on the edge, so its normal is perpendicular to the surface: "triangle
orientation could not be resolved". Ring coordinates within 64 eps of
the previous sample's are snapped to it; 3D points are unchanged.

The orientation error and the refinement-triangle limit name the face.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFZvqx1RmXzPtbL9VXP4H7
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