feat(extract): NURBS curve + patch surface tessellation#29
Merged
Conversation
First-party NurbsEval math unit + two MeshBuilder arms (curve→lines, patch→triangles with analytic normals), full periodic closed handling, convex-hull bounds. Closes NRB-1 for curve+patch; trimmed/swept/swung, interpolators, and 2D geometry deferred to follow-ups. Includes the 'why not a seam' rationale (I/O-free + spec-prescribed ⇒ no genericity payoff; externalGeometryResolver stays as the override).
Math-unit-first: open/closed curves -> open/closed surfaces with analytic normals (all formulas machine-verified) -> MeshBuilder arms -> bounds -> specimen swap -> docs -> CI. Each task ships verified golden values.
…ot double) Caught by adversarial workflow execution: the golden asserted |x^2+y^2-1|<1e-9 on float-stored points whose achievable error is ~1 ulp (6e-8). Math is exact (double accumulation, float output); only the test bound was impossible.
Caught by adversarial workflow execution: comparing the chord leaving the seam to the chord arriving caps the dot at ~0.923 (chords straddle the true tangent by the curvature), so >0.99 is impossible even for a correct C1 curve. Replaced with: seam chord-turning == diametrically-opposite vertex's (verified == 1e-16); a C0 kink would break that equality. Curve is genuinely C1.
- ci-preset -Werror=narrowing: finite-difference test used double h -> float brace-init; make h float (blocking; dev preset does not -Werror). - review (medium): prepareSurface wrapped closed surfaces unconditionally while prepareCurve guards on endsDiffer. Add the coincident-boundary guard so an already-closed control net is not duplicated into zero-area sliver triangles; + regression test (already-closed net + uClosed == unwrapped result). - review (low): guard the rational denominator in tessellateCurve/evalSurface so a degenerate/zero weight set emits a finite point, not NaN (which would poison the AABB).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements first-party tessellation for
NurbsCurveandNurbsPatchSurface, closing NRB-1 for curve + patch. Previously both were generated stubs that the extractor silently dropped.What's in it
runtime/extract/NurbsEval.hpp— node-free NURBS math: Cox–de Boor basis + first-derivative basis, rational (weighted) curve/surface evaluation, clamped + periodic knot defaulting, fullclosed/uClosed/vClosedhandling, and analytic normals via the quotient rule(A' − w'C)/w.MeshBuilderarms —NurbsCurve→Topology::Lines;NurbsPatchSurface→Triangles+ analytic normals + implicit (u,v) texcoords. Registered inrecognizedGeometryType().GeometryBounds.hpp.externalGeometryResolverstays the unrecognized-fallback for the deferred surfaces), conformance NRB-1 → fixed (NRB-3 tracks deferred swept/swung/trimmed), extract subsystem page, v1-capabilities.Scope
Curve + patch only. Deferred to follow-ups:
NurbsTrimmedSurface, swept/swung, NURBS interpolators, authoredNurbsTextureCoordinate, 2D geometry.Verification
nurbs_eval_test) + integration (mesh_builder_nurbs_test);recognizedGeometryTypeoracle; unrecognized-specimen moved toNurbsTrimmedSurface.mise run cigreen (ci-preset build 111/111 with-Werror+ per-header isolation; Python suite 305 passed/1 skipped; golden/conformance/coverage/cli gates pass).Spec:
docs/superpowers/specs/2026-06-27-nurbs-curve-patch-design.md. Plan:docs/superpowers/plans/2026-06-27-nurbs-curve-patch.md.Note: the headless renderer needed an unrelated ADR-0039 namespace fix to build (it's out-of-CI); that's a separate PR (#28).