Surface::clone stands for the copy constructor, whose sm_FixupKnotVector
moves near-coincident knots. Two places copied a surface that upstream
keeps using as is:
- SmBSplineSurface::IsDegenerateCurve passes the call along on the object
itself; the SmSurface wrapper is now an exact copy (clone_exact).
- SmSurfaceIntersector::DoIntersection runs FindBoundaryStartPoints on its
own surface caches; the boundary copies are now exact
(SurfaceCache::clone_for_evaluation).
Difftest cases with near-coincident knots: nurbs.b_spline_surface_p1
(borrowed NURB, degen_curve) and intersect.surface_intersector_p5 (new
raw_knots input: the shim writes the given knots back after the
constructor's fix-up; Rust uses a borrowed NURB). Both disagree with the
old copies and agree now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
Guard common and handwritten entrypoints through native cleanup and callback restoration. Add exclusion, recursive forwarding and exception-unwind probes; p2 adds its concurrent cross-wrapper regression with the port.
Co-Authored-By: GPT-6.1-Sol <noreply@openai.com>
SmSurfaceIntersector::DoIntersection on AdvSurfaceIntersector (every upstream
caller runs it there), GrazingBoxProcess, the shim/ffi/runner (hand-built
trees swapped into the real C++ caches) and unit tests. Wires
base_global_surface_intersect (surface_p2, via plane_p2 and
surf_of_revolution_p2) and ports the rest of CreateParallelProjectionCurves
(surface_p7).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BY8UpXKuMci15rAWGXsbsm