pub fn refine_crossing<S: Scalar>(
curve: &NurbCurve<S, 4>,
surface: &NurbSurface<S, 4>,
t: S,
uv: Vector2<S>,
) -> (S, Vector2<S>)Expand description
Polish one isolated (t, uv) — as returned by curve_surface_intersect
— by Newton on C(t) - S(u, v) = 0, three equations in the three unknowns
t, u, v.
Subdivision and Newton divide the work: subdivision is the global method,
reliably finding and separating every solution and recognizing coincidence
even for a partial overlap, but converging only one bit per split; Newton
cannot find anything but polishes an isolated solution quadratically.
curve_surface_intersect deliberately does not apply this to everything
it returns — most callers only need to know where and how many crossings
there are, and refining changes results they already agree with. Call it
when the parameter is about to be used as a split point, where the width
genuinely matters: NurbCurve::split cannot absorb a
min_subdivision_size-wide parameter (Boehm insertion amplifies it without
bound), and a point evaluated at one is just as wide — which is how a wide
crossing becomes a fat vertex and a fat sub-curve.
Every iterate but the last is sharpened, which is legitimate: it is only a
seed for the next step. The final step is left unsharpened, so the returned
widths honestly state how well the crossing is determined (see “Sharpen
only where the value is a free choice” in AGENTS.md).
Infallible by construction: the incoming box is already a valid enclosure, so anything that stops Newton — a singular Jacobian at a tangential crossing or a pole, an iterate leaving the domain, a refined box disjoint from the one subdivision proved the solution lies in — just returns that box unchanged. Refinement can only tighten, never fail.