Skip to main content

predictor_corrector_step

Function predictor_corrector_step 

Source
pub fn predictor_corrector_step(
    surf_a: &NurbSurface3D,
    surf_b: &NurbSurface3D,
    point: Vector3,
    dir: Vector3,
    u_a: Scalar,
    v_a: Scalar,
    u_b: Scalar,
    v_b: Scalar,
    step_size: Scalar,
) -> GeopResult<(Vector3, Scalar, Scalar, Scalar, Scalar)>
Expand description

One predictor-corrector step from point (with known (u_a, v_a) / (u_b, v_b) on surf_a/surf_b) along dir: predicts point + dir * step_size, then solves for the point that lies on both surfaces at once by damped Newton, returning the union of the two surfaces’ enclosures of it plus each surface’s own resulting (u, v).

The corrector solves one system in the four unknowns (u_a, v_a, u_b, v_b) rather than projecting onto each surface separately. Separate projections each enforce their own surface’s constraint while ignoring the other’s, so they land a full prediction-error apart and stay there no matter how good the predictor is — and that error is not small: the marching point inherits the start vertex’s own interval width (a vertex found by curve_surface_intersect is located only to within min_subdivision_size), which sharpen turns into a concrete offset.

Three of the four residuals are S_a(u_a, v_a) - S_b(u_b, v_b) = 0. Those alone are underdetermined by exactly one degree of freedom — the intersection curve is a curve, so sliding along it satisfies them equally well — and that free direction is what the damper has to pin down. It pins it biased to the last direction: the fourth residual holds the solution on the plane through the prediction with normal dir, so the corrector may move freely onto the curve but not drift along it, and the step stays the one the predictor asked for.

A step that would leave a patch is not rejected: project clamps into the domain, so such a step lands exactly on the patch boundary — which is precisely where an intersection curve ends, and therefore where the vertex it must connect to lives. Refusing it instead stops the march a full step_size short of that vertex, which is how a trace ends up never reaching anything. Deciding whether a direction is viable at all is face_contains’ job on the first step (see a trace’s), not something for every step to re-litigate via raw domain bounds.