Skip to main content

brep_kernel/geometry/
pcurve.rs

1use crate::{
2    interpolate_curve, project_point_to_surface, project_point_to_surface_seeded, AnalyticSurface,
3    DiagnosticSeverity, KernelDiagnostics, KernelStage, KnotVector, NurbsCurve, NurbsSurface, Vec3,
4    Vec4, KNOT_IDENTITY_TOL,
5};
6
7const EPSILON: f64 = 1e-12;
8const LINEAR_TOLERANCE: f64 = 1e-7;
9
10/// Coarse clocks only: no per-station timing overhead in a measured fit.
11struct PcurvePhaseClock {
12    started: Option<web_time::Instant>,
13    phase: &'static str,
14    samples: usize,
15    tracking: bool,
16}
17impl PcurvePhaseClock {
18    fn new(phase: &'static str, samples: usize, tracking: bool) -> Self {
19        Self { started: std::env::var_os("BREP_PROFILE").is_some().then(web_time::Instant::now), phase, samples, tracking }
20    }
21}
22impl Drop for PcurvePhaseClock {
23    fn drop(&mut self) {
24        if let Some(started) = self.started {
25            eprintln!("pcurve.phase_time phase={} initial_samples={} tracking={} ms={:.3}", self.phase, self.samples, self.tracking, started.elapsed().as_secs_f64()*1000.0);
26        }
27    }
28}
29
30fn surface_domains(surface: &NurbsSurface) -> Result<([f64; 2], [f64; 2]), String> {
31    Ok((
32        KnotVector::new(surface.knots_u.clone(), surface.degree_u)?.domain(),
33        KnotVector::new(surface.knots_v.clone(), surface.degree_v)?.domain(),
34    ))
35}
36
37/// The carrier's closed directions, as [`NurbsSurface::closed_directions`]
38/// reads them (cached on the surface, seam tolerance 1e-6, and a sliver patch
39/// whose rows coincide without the surface travelling between them is OPEN).
40/// Until 2026-09-26 this was a second reading with its own tolerance; the
41/// unwrap in [`build_interpolant`] and the wrap in `evaluate_extended` must
42/// agree on what a seam is, or a trim across a sliver reads a period wide.
43fn surface_closedness(surface: &NurbsSurface) -> Result<(bool, bool), String> {
44    surface.closed_directions()
45}
46
47thread_local! {
48    static PCURVE_REJECT_BOUNDS: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
49}
50struct PcurveRejectScope(bool);
51impl PcurveRejectScope {
52    fn open(enabled: bool) -> Self {
53        Self(PCURVE_REJECT_BOUNDS.with(|state| state.replace(enabled)))
54    }
55}
56impl Drop for PcurveRejectScope {
57    fn drop(&mut self) { PCURVE_REJECT_BOUNDS.with(|state| state.set(self.0)); }
58}
59
60thread_local! {
61    static PCURVE_STACK_POINT: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
62}
63struct PcurveStackPointScope(bool);
64impl PcurveStackPointScope {
65    fn open(enabled: bool) -> Self { Self(PCURVE_STACK_POINT.with(|state| state.replace(enabled))) }
66}
67impl Drop for PcurveStackPointScope {
68    fn drop(&mut self) { PCURVE_STACK_POINT.with(|state| state.set(self.0)); }
69}
70
71/// The count-zero basis recurrence has the same operations as the value
72/// basis recurrence. Its homogeneous sum uses the same row/column order.
73/// Preserve derivative dehomogenization (multiply by reciprocal, not divide)
74/// while avoiding both the derivative grids and their allocation. Other
75/// degrees and open-direction extension keep the original API. Periodic
76/// wrap retains the original parameter arithmetic before value evaluation.
77fn section_extended_point(surface: &NurbsSurface, u: f64, v: f64, enabled: bool) -> Result<Vec3, String> {
78    if enabled && u.is_finite() && v.is_finite()
79        && surface.degree_u <= crate::curve::MAX_STACK_DEGREE
80        && surface.degree_v <= crate::curve::MAX_STACK_DEGREE {
81        let [u0,u1] = surface.domain_u()?;
82        let [v0,v1] = surface.domain_v()?;
83        let mut uu = u;
84        let mut vv = v;
85        if u < u0 || u > u1 || v < v0 || v > v1 {
86            let (closed_u, closed_v) = surface_closedness(surface)?;
87            // Identical to derivatives_extended: keep the original add,
88            // subtract and remainder order before taking the count-zero path.
89            if closed_u && (u < u0 || u > u1) { uu = u0 + (u - u0).rem_euclid(u1 - u0); }
90            if closed_v && (v < v0 || v > v1) { vv = v0 + (v - v0).rem_euclid(v1 - v0); }
91        }
92        if uu >= u0 && uu <= u1 && vv >= v0 && vv <= v1 {
93            let point = surface.evaluate_homogeneous(uu, vv)?;
94            if point.w.abs() <= EPSILON {
95                return Err("NurbsSurface: zero evaluated weight".into());
96            }
97            return Ok(Vec3::new(point.x, point.y, point.z).scale(1.0 / point.w));
98        }
99    }
100    surface.evaluate_extended(u,v)
101}
102
103/// One immutable sphere/section pair; nested fits own separate maps. Keys
104/// preserve all parameter bits, and failed evaluations are never retained.
105struct PcurveSampleCache {
106    surface: usize,
107    curve: usize,
108    curves: rustc_hash::FxHashMap<u64, Vec3>,
109    surfaces: rustc_hash::FxHashMap<(u64, u64, bool), Vec3>,
110    inversions: rustc_hash::FxHashMap<[u64; 3], ([f64; 2], f64)>,
111    requests: [usize; 4],
112    hits: [usize; 4],
113    speeds: rustc_hash::FxHashMap<(u64, u64), f64>,
114}
115thread_local! {
116    static PCURVE_SAMPLES: std::cell::RefCell<Vec<Option<PcurveSampleCache>>> = const { std::cell::RefCell::new(Vec::new()) };
117}
118struct PcurveSampleScope;
119impl PcurveSampleScope {
120    fn open(surface: &NurbsSurface, curve: &NurbsCurve, enabled: bool) -> Self {
121        let cache = (enabled && matches!(surface.analytic(), Some(AnalyticSurface::Sphere { .. })))
122            .then(|| PcurveSampleCache { surface: surface as *const _ as usize,
123                curve: curve as *const _ as usize, curves: Default::default(),
124                surfaces: Default::default(), inversions: Default::default(), requests: [0; 4], hits: [0; 4], speeds: Default::default() });
125        PCURVE_SAMPLES.with(|stack| stack.borrow_mut().push(cache));
126        Self
127    }
128}
129impl Drop for PcurveSampleScope {
130    fn drop(&mut self) {
131        PCURVE_SAMPLES.with(|stack| {
132            if let Some(Some(cache)) = stack.borrow_mut().pop() {
133                if std::env::var_os("BREP_PROFILE").is_some() {
134                    eprintln!("pcurve.samples requests={:?} hits={:?} retained={:?}", cache.requests,
135                        cache.hits, [cache.curves.len(), cache.surfaces.len(), cache.inversions.len(), cache.speeds.len()]);
136                }
137            }
138        });
139    }
140}
141const PCURVE_SAMPLE_CACHE_LIMIT: usize = 16384;
142fn section_u_speed(surface: &NurbsSurface, u: f64, v: f64) -> Result<f64, String> {
143    let key = (u.to_bits(), v.to_bits());
144    let (active, hit) = PCURVE_SAMPLES.with(|stack| {
145        let mut stack = stack.borrow_mut();
146        let Some(Some(cache)) = stack.last_mut() else { return (false, None) };
147        if cache.surface != surface as *const _ as usize { return (false, None) }
148        cache.requests[3] += 1;
149        let hit = cache.speeds.get(&key).copied();
150        cache.hits[3] += usize::from(hit.is_some());
151        (true, hit)
152    });
153    if let Some(hit) = hit { return Ok(hit) }
154    let speed = surface.deriv1(u, v)?.1.length();
155    if active { PCURVE_SAMPLES.with(|stack| {
156        let mut stack = stack.borrow_mut();
157        let cache = stack.last_mut().unwrap().as_mut().unwrap();
158        if cache.speeds.len() < PCURVE_SAMPLE_CACHE_LIMIT { cache.speeds.insert(key, speed); }
159    }); }
160    Ok(speed)
161}
162
163fn section_curve_point(curve: &NurbsCurve, parameter: f64) -> Result<Vec3, String> {
164    let key = parameter.to_bits();
165    let (active, hit) = PCURVE_SAMPLES.with(|stack| {
166        let mut stack = stack.borrow_mut();
167        let Some(Some(cache)) = stack.last_mut() else { return (false, None) };
168        if cache.curve != curve as *const _ as usize { return (false, None) }
169        cache.requests[0] += 1;
170        let hit = cache.curves.get(&key).copied();
171        cache.hits[0] += usize::from(hit.is_some());
172        (true, hit)
173    });
174    if let Some(hit) = hit { return Ok(hit) }
175    let point = curve.evaluate(parameter)?;
176    if active { PCURVE_SAMPLES.with(|stack| {
177        let mut stack = stack.borrow_mut();
178        let cache = stack.last_mut().unwrap().as_mut().unwrap();
179        if cache.curves.len() < PCURVE_SAMPLE_CACHE_LIMIT { cache.curves.insert(key, point); }
180    }); }
181    Ok(point)
182}
183fn section_surface_point(surface: &NurbsSurface, u: f64, v: f64, extended: bool) -> Result<Vec3, String> {
184    let key = (u.to_bits(), v.to_bits(), extended);
185    let (active, hit) = PCURVE_SAMPLES.with(|stack| {
186        let mut stack = stack.borrow_mut();
187        let Some(Some(cache)) = stack.last_mut() else { return (false, None) };
188        if cache.surface != surface as *const _ as usize { return (false, None) }
189        cache.requests[1] += 1;
190        let hit = cache.surfaces.get(&key).copied();
191        cache.hits[1] += usize::from(hit.is_some());
192        (true, hit)
193    });
194    if let Some(hit) = hit { return Ok(hit) }
195    let point = if extended { section_extended_point(surface, u, v, PCURVE_STACK_POINT.with(|state| state.get()))? } else { surface.evaluate(u, v)? };
196    if active { PCURVE_SAMPLES.with(|stack| {
197        let mut stack = stack.borrow_mut();
198        let cache = stack.last_mut().unwrap().as_mut().unwrap();
199        if cache.surfaces.len() < PCURVE_SAMPLE_CACHE_LIMIT { cache.surfaces.insert(key, point); }
200    }); }
201    Ok(point)
202}
203fn invert_checked(surface: &NurbsSurface, point: Vec3) -> Result<([f64; 2], f64), String> {
204    let key = [point.x.to_bits(), point.y.to_bits(), point.z.to_bits()];
205    let (active, hit) = PCURVE_SAMPLES.with(|stack| {
206        let mut stack = stack.borrow_mut();
207        let Some(Some(cache)) = stack.last_mut() else { return (false, None) };
208        if cache.surface != surface as *const _ as usize { return (false, None) }
209        cache.requests[2] += 1;
210        let hit = cache.inversions.get(&key).copied();
211        cache.hits[2] += usize::from(hit.is_some());
212        (true, hit)
213    });
214    if let Some(hit) = hit { return Ok(hit) }
215    let projection = invert_checked_uncached(surface, point)?;
216    if active { PCURVE_SAMPLES.with(|stack| {
217        let mut stack = stack.borrow_mut();
218        let cache = stack.last_mut().unwrap().as_mut().unwrap();
219        if cache.inversions.len() < PCURVE_SAMPLE_CACHE_LIMIT { cache.inversions.insert(key, projection); }
220    }); }
221    Ok(projection)
222}
223
224fn invert_checked_uncached(surface: &NurbsSurface, point: Vec3) -> Result<([f64; 2], f64), String> {
225    if surface.is_affine()? {
226        let ([u0, _], [v0, _]) = surface_domains(surface)?;
227        let (origin, du, dv) = surface.deriv1(u0, v0)?;
228        let delta = point.sub(origin);
229        let uu = du.dot(du);
230        let uv = du.dot(dv);
231        let vv = dv.dot(dv);
232        let along_u = delta.dot(du);
233        let along_v = delta.dot(dv);
234        let determinant = uu * vv - uv * uv;
235        if determinant.abs() > EPSILON {
236            let parameter = [
237                u0 + (along_u * vv - along_v * uv) / determinant,
238                v0 + (along_v * uu - along_u * uv) / determinant,
239            ];
240            // The standoff is a MEASUREMENT here as on every other carrier:
241            // until 2026-09-26 this returned 0.0 for "affine, not measured",
242            // and a curve 1e-2 off its plane read as lying on it.
243            let foot = origin.add(du.scale(parameter[0] - u0)).add(dv.scale(parameter[1] - v0));
244            return Ok((parameter, point.sub(foot).length()));
245        }
246    }
247    let projection = project_point_to_surface(surface, point)?;
248    Ok(([projection.u, projection.v], projection.distance))
249}
250
251/// Whether an end station at a cone's apex takes its nearest regular
252/// station's u (`true`), as in `build_interpolant`, or the projector's
253/// arbitrary u there as before 2026-09-27. `BREP_PCURVE_CONE_APEX_U=0`
254/// restores the projector's u, for a same-binary A/B.
255fn cone_apex_u() -> bool {
256    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
257    *ON.get_or_init(|| std::env::var_os("BREP_PCURVE_CONE_APEX_U").is_none_or(|value| value != "0"))
258}
259
260/// Whether a round with more candidates than the cap has room for keeps its
261/// WORST probes (`true`), or the first in span order as before 2026-09-27.
262/// `BREP_PCURVE_WORST_FIRST=0` restores span order, for a same-binary A/B.
263fn worst_first() -> bool {
264    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
265    *ON.get_or_init(|| std::env::var_os("BREP_PCURVE_WORST_FIRST").is_none_or(|value| value != "0"))
266}
267
268/// `BREP_PCURVE_C0_JOIN=0` builds one C2 interpolant through the stations as
269/// before 2026-10-03 (the C0 joins at the curve's corners off), for a
270/// same-binary A/B. Read once per process.
271fn c0_joins() -> bool {
272    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
273    *ON.get_or_init(|| std::env::var_os("BREP_PCURVE_C0_JOIN").is_none_or(|value| value != "0"))
274}
275
276fn seeded_inserts() -> bool {
277    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
278    *ON.get_or_init(|| std::env::var_os("BREP_PCURVE_SEEDED_INSERTS").is_none_or(|value| value != "0"))
279}
280
281/// [`invert_checked`] for a station inserted between two whose feet are known:
282/// Newton from the pcurve's own `(u, v)` at that fraction, which already lies
283/// between the neighbours' feet on their branch, and the global search only
284/// when that local foot stands off further than the neighbours do (plus the
285/// refinement floor) — a local minimum the curve does not sit at. The global
286/// search was 30 s of a 54 s `abc_00000011` import (732k calls, 41 µs each,
287/// measured 2026-09-26). Planes and analytic carriers keep their closed forms.
288/// `BREP_PCURVE_SEEDED_INSERTS=0` restores the global search at every insert,
289/// for a same-binary A/B.
290fn invert_near(
291    surface: &NurbsSurface,
292    point: Vec3,
293    seed: [f64; 2],
294    neighbour_gap: f64,
295) -> Result<([f64; 2], f64), String> {
296    if !seeded_inserts() || surface.is_affine()? || surface.analytic().is_some() {
297        return invert_checked(surface, point);
298    }
299    let seeded = project_point_to_surface_seeded(surface, point, seed[0], seed[1])?;
300    if seeded.distance <= neighbour_gap + PCURVE_REFINEMENT_TOLERANCE {
301        return Ok(([seeded.u, seeded.v], seeded.distance));
302    }
303    invert_checked(surface, point)
304}
305
306fn unwrap_periodic(values: &mut [f64], minimum: f64, maximum: f64) {
307    let period = maximum - minimum;
308    for index in 1..values.len() {
309        while values[index] - values[index - 1] > period / 2.0 {
310            values[index] -= period;
311        }
312        while values[index] - values[index - 1] < -period / 2.0 {
313            values[index] += period;
314        }
315    }
316    if values.len() > 1 {
317        while values[0] - values[1] > period / 2.0 {
318            values[0] -= period;
319        }
320        while values[0] - values[1] < -period / 2.0 {
321            values[0] += period;
322        }
323    }
324    // Recenter the whole (now continuous) sequence into the domain by the
325    // whole-period shift that leaves the LEAST parameter outside [minimum,
326    // maximum]. A single middle/mean sample is NOT representative of a curve
327    // that bulges out to touch — or straddle — the periodic seam: when that
328    // sample is a boundary-kissing point (the at-seam projection unwraps a hair
329    // past the boundary), a single-sample test misfires and shoves the entire
330    // curve a full period out of range (ABC helmet 00000011/12 side channels:
331    // a touching edge's parameter run snapped a whole period off its true
332    // interior, tearing the loop open in parameter space).
333    if values.len() > 1 {
334        let excursion = |shift: f64| -> f64 {
335            values
336                .iter()
337                .map(|value| {
338                    let v = value + shift;
339                    (minimum - v).max(0.0) + (v - maximum).max(0.0)
340                })
341                .sum::<f64>()
342        };
343        let mean = values.iter().copied().sum::<f64>() / values.len() as f64;
344        let center = 0.5 * (minimum + maximum);
345        let base_k = ((center - mean) / period).round() as i64;
346        let mut best_shift = 0.0;
347        let mut best_excursion = f64::INFINITY;
348        for k in (base_k - 1)..=(base_k + 1) {
349            let shift = k as f64 * period;
350            let value = excursion(shift);
351            if value < best_excursion {
352                best_excursion = value;
353                best_shift = shift;
354            }
355        }
356        if best_shift != 0.0 {
357            for value in values.iter_mut() {
358                *value += best_shift;
359            }
360        }
361    }
362}
363
364/// The interpolant through `raw_parameters`, and what building it CLAMPED:
365/// the largest parameter distance a sample was pulled back into an open
366/// direction's domain, and the 3D distance between the extended surface at
367/// the raw parameter and the clamped foot. Both zero when nothing was pulled.
368/// A closed direction wraps and is never clamped.
369fn build_interpolant(
370    surface: &NurbsSurface,
371    raw_parameters: &[[f64; 2]],
372    curve_parameters: &[f64],
373) -> Result<(NurbsCurve, f64, f64), String> {
374    build_interpolant_joined(surface, raw_parameters, curve_parameters, &[])
375}
376
377/// [`build_interpolant`] with C0 JOINS: `joins` are values of
378/// `curve_parameters` at which the edge curve itself has a corner (a knot of
379/// multiplicity ≥ its degree, `range_breaks`). One cubic through all the
380/// stations is C2 everywhere, so across a corner it overshoots on both sides
381/// by a first-order amount however many stations are inserted: `abc_00000011`
382/// face #585 edge 179 (79 such knots on a 241-point curve) read 2.055e-4 off
383/// at 153 stations with the file's curve 2.1e-7 off the carrier (measured
384/// 2026-10-03). The stations have been planted at those knots since
385/// 2026-09-26; what was missing was the interpolant honouring them. Each
386/// piece between joins is interpolated on its own and the pieces are
387/// concatenated at knots of multiplicity 3 — the join `blend/track_fit.rs`
388/// makes for a blend track. A piece shorter than four stations cannot carry
389/// a cubic, so its join is dropped and it merges with its neighbour.
390fn build_interpolant_joined(
391    surface: &NurbsSurface,
392    raw_parameters: &[[f64; 2]],
393    curve_parameters: &[f64],
394    joins: &[f64],
395) -> Result<(NurbsCurve, f64, f64), String> {
396    let _clock = PcurvePhaseClock::new("interpolant", raw_parameters.len(), false);
397    let ([u0, u1], [v0, v1]) = surface_domains(surface)?;
398    let (closed_u, closed_v) = surface_closedness(surface)?;
399    let mut parameters = raw_parameters.to_vec();
400    // A cone's apex has no longitude either: every u there is the same point,
401    // and the projector answers one arbitrarily (0, which unwraps to 1). A trim
402    // that ENDS at the apex then turns sideways in its last span —
403    // `abc 00008080` face #163 edge 476, a generatrix at u = 0.80255 whose
404    // apex station read u = 1.0 (2026-09-27). An apex station at either end of
405    // the run takes the u of its nearest regular station, so a generatrix's
406    // pcurve is the straight u = const it is. Interior apex crossings are left
407    // to the branch logic below. `BREP_PCURVE_CONE_APEX_U=0` switches this off,
408    // for a same-binary A/B.
409    if cone_apex_u() && matches!(surface.analytic(), Some(AnalyticSurface::RuledRevolution { .. })) && parameters.len() >= 2 {
410        let speeds = parameters
411            .iter()
412            .map(|parameter| section_u_speed(surface, parameter[0], parameter[1]))
413            .collect::<Result<Vec<_>, _>>()?;
414        let reference = speeds.iter().copied().fold(0.0_f64, f64::max);
415        let singular = |index: usize| speeds[index] <= reference * 1e-2;
416        if let (Some(first), Some(last)) = (
417            (0..parameters.len()).find(|&index| !singular(index)),
418            (0..parameters.len()).rfind(|&index| !singular(index)),
419        ) {
420            for index in 0..first {
421                parameters[index][0] = parameters[first][0];
422            }
423            for index in last + 1..parameters.len() {
424                parameters[index][0] = parameters[last][0];
425            }
426        }
427    }
428    // Longitude is undefined at a sphere pole: the surface's u tangent
429    // vanishes there, and closest-point inversion is free to return any u.
430    // Letting that arbitrary value participate in periodic unwrapping can move
431    // the first real meridian by a whole period (e.g. 0.75 -> -0.25). Analytic
432    // carriers are subsequently clamped, collapsing that meridian onto u=0.
433    //
434    // Keep this deliberately sphere- and singularity-gated. Split the u values
435    // into maximal non-pole runs, unwrap each run independently, and leave the
436    // pole samples untouched. The existing interpolant degree stays unchanged;
437    // lowering it here would also change endpoint-tangent decisions made later
438    // while stitching the face loop.
439    let sphere_u_singular = if matches!(surface.analytic(), Some(AnalyticSurface::Sphere { .. })) {
440        let speeds = parameters
441            .iter()
442            .map(|parameter| {
443                section_u_speed(surface, parameter[0], parameter[1])
444            })
445            .collect::<Result<Vec<_>, _>>()?;
446        let reference = speeds.iter().copied().fold(0.0_f64, f64::max);
447        speeds
448            .into_iter()
449            // Uniform edge stations need not hit the pole exactly (ABC 5360
450            // bottoms out at v=5.5e-4). In this small conditioning band,
451            // longitude is already numerically arbitrary and must not connect
452            // the two meridian runs across the pole.
453            .map(|speed| speed <= reference * 1e-2)
454            .collect::<Vec<_>>()
455    } else {
456        vec![false; parameters.len()]
457    };
458    // Do not perturb ordinary pole-touching trims. The special path is needed
459    // only when a pole band is bracketed by nonsingular samples and its raw
460    // longitude changes by at least half a period: a true through-pole branch
461    // reset whose two meridian runs must be unwrapped independently.
462    // Prefix/suffix pole samples on normal sphere caps retain the legacy
463    // interpolation byte-for-byte. Include the exactly-half-period case so
464    // floating-point noise cannot decide which entire run is lifted (ABC 5603).
465    let has_interior_pole_crossing = sphere_u_singular
466        .iter()
467        .position(|singular| !singular)
468        .zip(sphere_u_singular.iter().rposition(|singular| !singular))
469        .is_some_and(|(first, last)| sphere_u_singular[first..=last].iter().any(|value| *value));
470    let period = (u1 - u0).abs();
471    let interior_pole_branch_reset = closed_u
472        && has_interior_pole_crossing
473        && parameters.windows(2).zip(sphere_u_singular.windows(2)).any(
474            |(parameter_pair, singular_pair)| {
475                (singular_pair[0] || singular_pair[1])
476                    && (parameter_pair[1][0] - parameter_pair[0][0]).abs()
477                        >= 0.5 * period - 1e-12 * period.max(1.0)
478            },
479        );
480    if closed_u {
481        let mut values = parameters.iter().map(|value| value[0]).collect::<Vec<_>>();
482        if interior_pole_branch_reset {
483            let mut start = 0;
484            while start < values.len() {
485                while start < values.len() && sphere_u_singular[start] {
486                    start += 1;
487                }
488                let mut end = start;
489                while end < values.len() && !sphere_u_singular[end] {
490                    end += 1;
491                }
492                unwrap_periodic(&mut values[start..end], u0, u1);
493                start = end;
494            }
495        } else {
496            unwrap_periodic(&mut values, u0, u1);
497        }
498        for (parameter, value) in parameters.iter_mut().zip(values) {
499            parameter[0] = value;
500        }
501    }
502    if closed_v {
503        let mut values = parameters.iter().map(|value| value[1]).collect::<Vec<_>>();
504        unwrap_periodic(&mut values, v0, v1);
505        for (parameter, value) in parameters.iter_mut().zip(values) {
506            parameter[1] = value;
507        }
508    }
509    // A closed direction WRAPS: an edge that straddles the seam has no single
510    // in-domain parameter run, so keep the unwrapped (possibly slightly
511    // out-of-domain) values and let the periodic evaluator wrap them — clamping
512    // them onto the seam boundary would collapse the straddling geometry (and,
513    // via the interpolant, spike neighbouring stations). This applies to
514    // analytic carriers too: a refitted cylinder can have stepped rims that
515    // cross its seam. evaluate_extended wraps every closed direction.
516    // Open directions must stay in-domain; their extension is a ruling.
517    //
518    // The clamp is MEASURED, not silent: a sample pulled back into the domain
519    // is reported as the parameter distance it moved and the 3D distance
520    // between the extended surface at its raw parameter and the clamped foot
521    // ([`PcurveFitReport::clamped_excursion`]). Until 2026-09-30 a trim that
522    // ran past its chart came back folded onto the chart's boundary with
523    // nothing in the report to say so; on the rib-base document that was
524    // 3.03e-2 of volume on a body `validate()` passes.
525    let mut excursion = 0.0_f64;
526    let mut distance = 0.0_f64;
527    let mut points = Vec::with_capacity(parameters.len());
528    for parameter in parameters {
529        let u = if closed_u {
530            parameter[0]
531        } else {
532            parameter[0].clamp(u0, u1)
533        };
534        let v = if closed_v {
535            parameter[1]
536        } else {
537            parameter[1].clamp(v0, v1)
538        };
539        let pulled = ((parameter[0] - u).powi(2) + (parameter[1] - v).powi(2)).sqrt();
540        if pulled > 0.0 {
541            excursion = excursion.max(pulled);
542            let extended = surface.evaluate_extended(parameter[0], parameter[1])?;
543            distance = distance.max(extended.sub(surface.evaluate(u, v)?).length());
544        }
545        points.push(Vec3::new(u, v, 0.0));
546    }
547    let degree = 3usize.min(points.len() - 1);
548    let mut bounds: Vec<usize> = joins
549        .iter()
550        .filter_map(|join| curve_parameters.iter().position(|parameter| parameter == join))
551        .filter(|&index| index > 0 && index + 1 < curve_parameters.len())
552        .collect();
553    bounds.sort_unstable();
554    bounds.dedup();
555    if degree < 3 || bounds.is_empty() || !c0_joins() {
556        let curve = interpolate_curve(&points, degree, curve_parameters)?;
557        return Ok((curve, excursion, distance));
558    }
559    // Every piece needs four stations for a cubic: drop the join that
560    // closes a shorter piece, from the left, until all pieces carry one.
561    let mut pieces = vec![0usize];
562    for bound in bounds {
563        if bound + 1 - pieces[pieces.len() - 1] >= 4 {
564            pieces.push(bound);
565        }
566    }
567    if curve_parameters.len() - pieces[pieces.len() - 1] < 4 {
568        pieces.pop();
569    }
570    pieces.push(curve_parameters.len() - 1);
571    if pieces.len() < 3 {
572        let curve = interpolate_curve(&points, degree, curve_parameters)?;
573        return Ok((curve, excursion, distance));
574    }
575    let mut knots: Vec<f64> = Vec::with_capacity(curve_parameters.len() + 4);
576    let mut control: Vec<Vec4> = Vec::with_capacity(curve_parameters.len());
577    let last_piece = pieces.len() - 2;
578    for piece in 0..=last_piece {
579        let (from, to) = (pieces[piece], pieces[piece + 1]);
580        let fitted = interpolate_curve(&points[from..=to], 3, &curve_parameters[from..=to])?;
581        if piece == 0 {
582            knots.extend(fitted.knots[..4].iter().copied());
583        }
584        knots.extend(fitted.knots[4..fitted.knots.len() - 4].iter().copied());
585        let multiplicity = if piece == last_piece { 4 } else { 3 };
586        knots.extend(std::iter::repeat(curve_parameters[to]).take(multiplicity));
587        control.extend(fitted.control_points.iter().skip(usize::from(piece > 0)).copied());
588    }
589    let curve = NurbsCurve::new(3, knots, control)?;
590    Ok((curve, excursion, distance))
591}
592
593/// The 3D residual a pcurve's image must reach before `build_pcurve_on_surface`
594/// accepts it, and the sample ceiling it refines up to.
595///
596/// A trimmed face's boundary is only ever as accurate as these two numbers, and
597/// every mass property is an integral over that boundary — so this is the floor
598/// under area, volume and centroid for every curved trim in the kernel.
599///
600/// These were `min(1e-3, 1e-4 * scale)` and 160, where `scale` is
601/// `1 + ||curve midpoint||` — the DISTANCE FROM THE WORLD ORIGIN of the curve's
602/// midpoint, not the part's size. That expression pinned to an absolute 1e-3
603/// once the midpoint sat more than about nine units from the origin, so on an
604/// ordinary part the bar was 1e-3 and tracked nothing.
605///
606/// Measured on `offset-shell-box-bore-dished-face`, whose dished wall is a
607/// closed-form identity at 2468.431782123 (three independent routes agree). The
608/// floor is one of TWO errors there; the other is the refitted sphere carrier
609/// that `sphere_offset_surface` now builds in closed form, and before both moved
610/// they partly CANCELLED — which is why either alone reads as a regression:
611///
612/// ```text
613/// floor     Box_O.S2            abs err     relative   gate total  worst case
614/// 1e-3   2468.442270355      +1.049e-02     4.25e-06        (old)
615/// 1e-6   2468.431785429      +3.306e-06     1.34e-09       181.4 s     31.2 s
616/// 1e-7   2468.431782170      +4.746e-08     1.92e-11       218.5 s     32.1 s
617/// 1e-9   2468.431782103      -2.037e-08    -8.25e-12       305.5 s     46.8 s
618/// ```
619///
620/// 1e-7 is chosen: 70x the accuracy of 1e-6 for +20% gate time, where 1e-9 costs
621/// a further +40% for a 2.3x residual no oracle in this corpus could resolve.
622/// All four cells are one session on one binary, so the times are comparable to
623/// each other. Every case carrying a closed-form oracle moves TOWARD it and none
624/// away (`PushFaceTest` 339x, `PushFaceTest2` 275x); no case changes class at
625/// any floor.
626///
627/// A flat ABSOLUTE is what was measured, not what was designed. This codebase
628/// otherwise keys identity bands to part size (`KernelTolerances::heal_band`,
629/// the `1e-11*(1+scale)` blend family), and on a 3000 mm part 1e-7 is 3e-11
630/// relative — refinement will exhaust `MAX_PCURVE_SAMPLES` and return whatever
631/// it reached. Until 2026-09-12 it did so SILENTLY; now the fit's
632/// [`PcurveFitReport`] carries the residual actually achieved and a
633/// [`PcurveFitExit::SampleCeiling`] exit, and the owning operation's
634/// diagnostics count it (`pcurve.unmet_floor`). That is far better than the
635/// 1e-3 it replaces but it is not a size-aware bar; deriving one from the
636/// surface's own extent is separate, unmeasured work. Being absolute does remove this gate's dependence on
637/// distance from the origin as a side effect — a real translation-VARIANCE
638/// defect, the same anti-pattern `tolerance::merge_scale` records being removed
639/// elsewhere. `drop_tolerance` and `endpoint_tolerance` below still carry it.
640pub const PCURVE_REFINEMENT_TOLERANCE: f64 = 1e-7;
641
642/// Sample ceiling for a fit's FIRST refinement pass. 160 could not reach
643/// [`PCURVE_REFINEMENT_TOLERANCE`] on a curved trim of any length; 600 is the
644/// value every cell of the table above was measured at.
645///
646/// It BINDS. On `boolean_fuzz_corpus/25_cube_pierce_solid` the fitter stopped
647/// here 1.65e-3 of volume short of the converged answer (2000 and 4000 samples
648/// agree exactly). Raising it globally to 2000 was costed and rejected: +23%
649/// case-gate time, concentrated in three offset/fillet cases, and one case
650/// (`inbox-20260910-offset-shell-collapsed-fillet`) driven 26x outside its
651/// volume band. So it is not raised here: a fit that stops at this ceiling
652/// with a residual still worse than its edge curve's own distance from the
653/// surface re-enters refinement with [`PCURVE_RAISED_SAMPLES`]
654/// ([`refine_pcurve`]); one whose residual is already that gap stops here and
655/// says so ([`PcurveFitReport::off_surface`]), because no sample count can
656/// close it.
657const MAX_PCURVE_SAMPLES: usize = 600;
658
659/// Sample ceiling for the ONE raised pass a fit may take past
660/// [`MAX_PCURVE_SAMPLES`]. 2000 is the ceiling the convergence sweep measured
661/// on `25_cube_pierce_solid`: its 2000 and 4000 cells agree to every printed
662/// digit because refinement there stops itself near 1540 samples, so the cap
663/// is not what binds.
664const PCURVE_RAISED_SAMPLES: usize = 2000;
665
666/// What a pcurve fit ACHIEVED, returned beside the curve so a ceiling exit can
667/// never be mistaken for a met floor.
668///
669/// [`fit_pcurve_on_surface`] asks for [`PCURVE_REFINEMENT_TOLERANCE`] and stops
670/// at [`MAX_PCURVE_SAMPLES`] — or, where that ceiling bound and the floor is
671/// reachable, at [`PCURVE_RAISED_SAMPLES`]. Until 2026-09-12 a trim that ran
672/// out of samples came back exactly like one that met the floor; on
673/// `boolean_fuzz_corpus/25_cube_pierce_solid` that silence hid a 1.65e-3 volume
674/// error. Now every fit says which it was: `residual` is measured on the curve
675/// that is actually returned and `exit` names why refinement stopped.
676///
677/// This is a MEASUREMENT taken at a construction, not a band.
678#[derive(Clone, Copy, Debug, PartialEq)]
679pub struct PcurveFitReport {
680    /// Largest 3D distance between the returned pcurve's image on the surface
681    /// and the edge curve. On a [`PcurveFitExit::Converged`] exit whose final
682    /// round probed every span this is that round's maximum — the refinement's
683    /// own acceptance test. On every other exit, including a converged round
684    /// that skipped spans narrower than 1e-3 of the parameter range, it is a
685    /// sweep over EVERY span of the returned curve.
686    pub residual: f64,
687    /// The residual the refinement was asked to reach.
688    pub floor: f64,
689    /// Interpolation samples in the returned curve.
690    pub samples: usize,
691    /// Why refinement stopped.
692    pub exit: PcurveFitExit,
693    /// Largest distance from the edge curve to the surface at every station
694    /// the fit inverted — the part of `residual` no pcurve can remove, since a
695    /// pcurve's image lies ON the surface. Zero for an affine carrier. A value
696    /// above `floor` says the floor is unreachable for this input; a ceiling
697    /// exit is retried only while `residual` exceeds it by more than the floor,
698    /// i.e. while the returned curve is worse than its input.
699    pub off_surface: f64,
700    /// Whether the fit re-entered refinement with [`PCURVE_RAISED_SAMPLES`]
701    /// after [`MAX_PCURVE_SAMPLES`] bound with the floor unmet.
702    pub raised: bool,
703    /// Largest parameter distance a station's inversion was pulled back into
704    /// an OPEN direction's domain when the returned curve was interpolated: a
705    /// trim asked for outside its chart is folded onto the chart's boundary,
706    /// the edge stays right and the face becomes the wrong region on a body
707    /// `validate()` passes (3.03e-2 of volume on the rib-base document). Zero
708    /// when nothing was pulled. A REPORT, not a bar: nothing here refuses on
709    /// it. Its coverage is the clamp in `build_interpolant`, which is the only
710    /// place a raw out-of-domain parameter reaches today — an affine carrier's
711    /// inversion is unclamped, so an affine plane fitted through the station
712    /// lane reads here. It does NOT see a clamp the projector applied before
713    /// the fit: the analytic `Plane` closed form (a non-affine net) clamps to
714    /// its domain, `RuledRevolution` clamps its axial parameter to `[0, 1]`
715    /// and the general Newton clamps through `fit_parameter`; those stations
716    /// arrive in-domain and read as `off_surface` instead. The exact affine
717    /// lanes (`fit_pcurve_on_surface` on an affine carrier,
718    /// `affine_pcurve_on_range`) never clamp and read zero by construction.
719    pub clamped_excursion: f64,
720    /// The 3D distance the clamp corresponds to: between the extended surface
721    /// at the raw parameter and the clamped foot, at the station of the
722    /// largest such distance. Zero when nothing was pulled.
723    pub clamped_distance: f64,
724}
725
726impl PcurveFitReport {
727    /// Whether the returned curve reaches the floor it was asked for.
728    pub fn met_floor(&self) -> bool {
729        self.residual <= self.floor
730    }
731
732    /// Whether the returned curve is on the ACCEPTANCE BAR: the floor it was
733    /// asked for, plus the stations' own standoff from the carrier.
734    ///
735    /// A pcurve's image lies on the carrier, so at a station standing `g` off
736    /// it no image can come closer than `g`; a fit whose residual is within
737    /// the floor of `off_surface` is as good as the input allows, and one over
738    /// it is worse than its input — the same condition [`refine_pcurve`] uses
739    /// to decide that a raise can still buy accuracy. This is the bar every
740    /// station builder refuses over ([`build_pcurve_on_surface_stations`]).
741    /// It is blind to sideways error quadratically (a station tracked `d`
742    /// aside of the projection of a point `g` off the surface reads only
743    /// `d²/(2g)` further away), which is stated rather than hidden: on the
744    /// import corpus the stations that stand off their carriers are the
745    /// FILE's curves, and the bar there is the file's own number.
746    pub fn on_bar(&self) -> bool {
747        self.residual <= self.floor + self.off_surface
748    }
749}
750
751/// Why a pcurve refinement stopped. Only [`PcurveFitExit::Converged`] means the
752/// floor was met; every other variant is a BUDGET exit, and the report's
753/// residual was measured on the returned curve rather than assumed.
754#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
755pub enum PcurveFitExit {
756    /// A probe round found every station within the floor. An affine carrier
757    /// maps exactly and reports this with a zero residual.
758    Converged,
759    /// The sample ceiling bound before the floor was met: [`MAX_PCURVE_SAMPLES`]
760    /// when the raise was declined (the residual is already explained by
761    /// [`PcurveFitReport::off_surface`]), [`PCURVE_RAISED_SAMPLES`] when it was
762    /// taken and bound too.
763    SampleCeiling,
764    /// Every refinement round was spent and the last one still inserted
765    /// samples, so the curve it built was never re-checked by the loop.
766    RoundBudget,
767    /// A round found stations over the floor but could improve none of them:
768    /// the edge point could not be inverted inside the drop band, or (in the
769    /// raised pass) the pcurve already tracks the surface's nearest point to
770    /// within the floor. Either way the edge curve itself sits off the surface
771    /// there and no pcurve can close that gap; the residual reports how far.
772    /// The range lane's end-span challenger (its station fitter's TRACKING
773    /// mode) also exits here when a round's probes all track their feet
774    /// within the floor while the deviation residual, which includes the
775    /// edge's standoff, stays over it.
776    Stalled,
777    /// The last probe round found every span it PROBED within the floor, but
778    /// skipped spans narrower than the loop's own resolution floor — 1e-3 of
779    /// the parameter range in [`refine_pcurve`], [`SPAN_FLOOR`] (1e-6) in
780    /// [`fit_pcurve_on_surface_stations`] — and a sweep over those found the
781    /// floor unmet.
782    /// Until 2026-09-12 this exit was reported as `Converged` with the probed
783    /// spans' maximum: on `25_cube_pierce_solid` a 1539-sample fit with 1537
784    /// narrow spans read 7e-8 that way while every span read 1.9e-4.
785    SpanFloor,
786}
787
788/// A fitted pcurve with what the fit achieved.
789#[derive(Clone, Debug)]
790pub struct PcurveFit {
791    pub curve: NurbsCurve,
792    pub report: PcurveFitReport,
793}
794
795/// Per-operation tally of pcurve fits and how many missed their floor.
796///
797/// [`build_pcurve_on_surface`] and its marched twin are called from some forty
798/// sites, most of which have no diagnostics record to write into. Rather than
799/// thread one through every layer, an operation that returns
800/// [`KernelDiagnostics`] opens a [`PcurveFitScope`]; every fit made on that
801/// thread while the scope is open is tallied here, and closing the scope hands
802/// the tally back for [`PcurveFitLedger::report_into`]. This is the shape the
803/// boolean's `CONFORMANCE_REPAIRS` counter already uses. With no scope open,
804/// recording is a no-op.
805///
806/// Scopes nest: CLOSING a child folds it into its parent, so an offset shell
807/// sees the fits of the booleans it ran. A scope that is DROPPED without being
808/// closed is discarded, not folded — a boolean attempt that refused (and may be
809/// retried under perturbation) must not leave its fits on the caller's tally.
810///
811/// Thread-local by construction: a fit made on a rayon worker (the `parallel`
812/// feature's STEP body import) is not seen by a scope on the calling thread. No
813/// diagnostics-returning operation builds pcurves off-thread today.
814#[derive(Clone, Copy, Debug, Default, PartialEq)]
815pub struct PcurveFitLedger {
816    /// Fits recorded, exact affine ones included.
817    pub fits: u64,
818    /// Fits whose returned curve did not reach its floor.
819    pub unmet: u64,
820    /// Unmet fits that stopped at a sample ceiling.
821    pub sample_ceiling: u64,
822    /// Unmet fits that spent every refinement round.
823    pub round_budget: u64,
824    /// Unmet fits that could insert nothing.
825    pub stalled: u64,
826    /// Unmet fits whose remaining over-floor spans were all below the loop's
827    /// 1e-3 span floor.
828    pub span_floor: u64,
829    /// Largest residual among the unmet fits; zero when there are none.
830    pub worst_unmet_residual: f64,
831    /// Fits that re-entered refinement with [`PCURVE_RAISED_SAMPLES`], met or
832    /// not.
833    pub raised: u64,
834    /// Unmet ceiling exits that were NOT raised because the residual is
835    /// already within the floor of the edge curve's own gap from the surface.
836    pub raise_declined: u64,
837    /// Largest [`PcurveFitReport::off_surface`] over every fit.
838    pub worst_off_surface: f64,
839    /// Fits whose interpolant was clamped into an open direction's domain
840    /// ([`PcurveFitReport::clamped_excursion`] above zero), met or not.
841    pub clamped: u64,
842    /// Largest [`PcurveFitReport::clamped_excursion`] over every fit.
843    pub worst_clamped_excursion: f64,
844    /// Largest [`PcurveFitReport::clamped_distance`] over every fit.
845    pub worst_clamped_distance: f64,
846}
847
848impl PcurveFitLedger {
849    fn record(&mut self, report: &PcurveFitReport) {
850        self.fits += 1;
851        if report.raised {
852            self.raised += 1;
853        }
854        self.worst_off_surface = self.worst_off_surface.max(report.off_surface);
855        if report.clamped_excursion > 0.0 {
856            self.clamped += 1;
857            self.worst_clamped_excursion = self.worst_clamped_excursion.max(report.clamped_excursion);
858            self.worst_clamped_distance = self.worst_clamped_distance.max(report.clamped_distance);
859        }
860        if report.met_floor() {
861            return;
862        }
863        self.unmet += 1;
864        match report.exit {
865            PcurveFitExit::Converged => {}
866            PcurveFitExit::SampleCeiling => {
867                self.sample_ceiling += 1;
868                if !report.raised {
869                    self.raise_declined += 1;
870                }
871            }
872            PcurveFitExit::RoundBudget => self.round_budget += 1,
873            PcurveFitExit::Stalled => self.stalled += 1,
874            PcurveFitExit::SpanFloor => self.span_floor += 1,
875        }
876        self.worst_unmet_residual = self.worst_unmet_residual.max(report.residual);
877    }
878
879    fn fold(&mut self, child: &PcurveFitLedger) {
880        self.fits += child.fits;
881        self.unmet += child.unmet;
882        self.sample_ceiling += child.sample_ceiling;
883        self.round_budget += child.round_budget;
884        self.stalled += child.stalled;
885        self.span_floor += child.span_floor;
886        self.worst_unmet_residual = self.worst_unmet_residual.max(child.worst_unmet_residual);
887        self.raised += child.raised;
888        self.raise_declined += child.raise_declined;
889        self.worst_off_surface = self.worst_off_surface.max(child.worst_off_surface);
890        self.clamped += child.clamped;
891        self.worst_clamped_excursion = self.worst_clamped_excursion.max(child.worst_clamped_excursion);
892        self.worst_clamped_distance = self.worst_clamped_distance.max(child.worst_clamped_distance);
893    }
894
895    /// Write the tally into an operation's diagnostics: the `pcurve.*`
896    /// counters and measurements always, plus one `pcurve.unmet_floor` event at
897    /// [`DiagnosticSeverity::Degraded`] when any fit missed its floor. Degraded,
898    /// not Error: the result is still the kernel's best construction and stays
899    /// shippable, but it no longer claims the accuracy its floor states.
900    pub fn report_into(&self, diagnostics: &mut KernelDiagnostics) {
901        diagnostics.count_n("pcurve.fits", self.fits);
902        diagnostics.count_n("pcurve.unmet_floor", self.unmet);
903        diagnostics.count_n("pcurve.exit.sample_ceiling", self.sample_ceiling);
904        diagnostics.count_n("pcurve.exit.round_budget", self.round_budget);
905        diagnostics.count_n("pcurve.exit.stalled", self.stalled);
906        diagnostics.count_n("pcurve.exit.span_floor", self.span_floor);
907        diagnostics.count_n("pcurve.budget_raised", self.raised);
908        diagnostics.count_n("pcurve.budget_raise_declined", self.raise_declined);
909        diagnostics.measure_max("pcurve.worst_unmet_residual", self.worst_unmet_residual);
910        diagnostics.measure_max("pcurve.worst_off_surface", self.worst_off_surface);
911        diagnostics.count_n("pcurve.clamped", self.clamped);
912        diagnostics.measure_max("pcurve.worst_clamped_excursion", self.worst_clamped_excursion);
913        diagnostics.measure_max("pcurve.worst_clamped_distance", self.worst_clamped_distance);
914        if self.unmet > 0 {
915            diagnostics.event(
916                DiagnosticSeverity::Degraded,
917                KernelStage::Refine,
918                "pcurve.unmet_floor",
919                format!(
920                    "{} of {} pcurve fits did not reach the {:.0e} floor \
921                     (sample ceiling {}, round budget {}, stalled {}, span floor {}); \
922                     worst residual {:.3e}; budget raised on {}, declined on {}; \
923                     edge curves sit off their surfaces by up to {:.3e}{}",
924                    self.unmet,
925                    self.fits,
926                    PCURVE_REFINEMENT_TOLERANCE,
927                    self.sample_ceiling,
928                    self.round_budget,
929                    self.stalled,
930                    self.span_floor,
931                    self.worst_unmet_residual,
932                    self.raised,
933                    self.raise_declined,
934                    self.worst_off_surface,
935                    if self.clamped > 0 {
936                        format!(
937                            "; {} fit(s) clamped into their chart by up to {:.3e} in parameter, {:.3e} in 3D",
938                            self.clamped, self.worst_clamped_excursion, self.worst_clamped_distance
939                        )
940                    } else {
941                        String::new()
942                    },
943                ),
944            );
945        }
946    }
947}
948
949thread_local! {
950    /// The open [`FootMemo`] on this thread, if any ([`FootMemoScope`]).
951    static FOOT_MEMO: std::cell::RefCell<Option<FootMemo>> = const { std::cell::RefCell::new(None) };
952}
953
954/// Exact-input memo of the common reader's projections on ONE surface: the
955/// global foot of an edge point and the foot seeded at a (u, v), keyed by the
956/// bit patterns of their inputs. Both projectors are pure functions of
957/// (surface, point[, seed]), so a hit returns the value a fresh call would:
958/// the readings, decisions and fits are bit-identical with or without it.
959/// It exists for cost: within one coedge the same edge points are read by
960/// the trigger read, every tracking-mode verification round, the
961/// challenger's final read and the importer's keep read, each of which
962/// projected them again (`importTestWorking`, 2026-10-05: about 10k probes
963/// read 3-5 times on each of nine off-carrier refits, 3-5 s apiece).
964struct FootMemo {
965    surface: *const NurbsSurface,
966    global: rustc_hash::FxHashMap<[u64; 3], Option<crate::SurfaceProjection>>,
967    seeded: rustc_hash::FxHashMap<[u64; 5], Option<crate::SurfaceProjection>>,
968}
969
970/// Opens a [`FootMemo`] for `surface` on this thread until dropped. Opening
971/// one where a memo for the SAME surface is already open reuses it (an inner
972/// scope, e.g. the range challenger inside an importer coedge); a memo for
973/// another surface is set aside and restored on drop. The borrow of `surface`
974/// keeps it alive and unmodified for the scope, so the pointer key cannot be
975/// reused by another surface while the memo answers for it.
976pub(crate) struct FootMemoScope<'a> {
977    previous: Option<Option<FootMemo>>,
978    _surface: std::marker::PhantomData<&'a NurbsSurface>,
979    /// Not `Send`: the scope must close on the thread that opened it.
980    _thread_bound: std::marker::PhantomData<*const ()>,
981}
982
983impl<'a> FootMemoScope<'a> {
984    pub(crate) fn open(surface: &'a NurbsSurface) -> Self {
985        let key = surface as *const NurbsSurface;
986        let previous = FOOT_MEMO.with(|memo| {
987            let mut memo = memo.borrow_mut();
988            if memo.as_ref().is_some_and(|open| std::ptr::eq(open.surface, key)) {
989                None
990            } else {
991                Some(memo.replace(FootMemo { surface: key, global: Default::default(), seeded: Default::default() }))
992            }
993        });
994        Self { previous, _surface: std::marker::PhantomData, _thread_bound: std::marker::PhantomData }
995    }
996}
997
998impl Drop for FootMemoScope<'_> {
999    fn drop(&mut self) {
1000        if let Some(previous) = self.previous.take() {
1001            FOOT_MEMO.with(|memo| *memo.borrow_mut() = previous);
1002        }
1003    }
1004}
1005
1006fn point_bits(point: Vec3) -> [u64; 3] {
1007    [point.x.to_bits(), point.y.to_bits(), point.z.to_bits()]
1008}
1009
1010/// [`project_point_to_surface`] as `.ok()`, through the open memo for this
1011/// surface when there is one. `#[track_caller]`: the projector still sees the
1012/// reader's own call site. Under a `BREP_PROJECTION_GLOBAL_SITES`/`_EXCEPT`
1013/// filter the projector's answer depends on that site, so the memo is not
1014/// consulted then.
1015#[track_caller]
1016fn memo_global_foot(surface: &NurbsSurface, point: Vec3) -> Option<crate::SurfaceProjection> {
1017    if crate::projection::global_site_filter_active() {
1018        return project_point_to_surface(surface, point).ok();
1019    }
1020    let key = point_bits(point);
1021    let hit = FOOT_MEMO.with(|memo| {
1022        memo.borrow().as_ref().filter(|open| std::ptr::eq(open.surface, surface)).map(|open| open.global.get(&key).copied())
1023    });
1024    match hit {
1025        Some(Some(foot)) => foot,
1026        Some(None) => {
1027            let foot = project_point_to_surface(surface, point).ok();
1028            FOOT_MEMO.with(|memo| {
1029                if let Some(open) = memo.borrow_mut().as_mut().filter(|open| std::ptr::eq(open.surface, surface)) {
1030                    open.global.insert(key, foot);
1031                }
1032            });
1033            foot
1034        }
1035        None => project_point_to_surface(surface, point).ok(),
1036    }
1037}
1038
1039/// [`project_point_to_surface_seeded`] as `.ok()`, through the open memo for
1040/// this surface when there is one.
1041fn memo_seeded_foot(surface: &NurbsSurface, point: Vec3, seed_u: f64, seed_v: f64) -> Option<crate::SurfaceProjection> {
1042    let [x, y, z] = point_bits(point);
1043    let key = [x, y, z, seed_u.to_bits(), seed_v.to_bits()];
1044    let hit = FOOT_MEMO.with(|memo| {
1045        memo.borrow().as_ref().filter(|open| std::ptr::eq(open.surface, surface)).map(|open| open.seeded.get(&key).copied())
1046    });
1047    match hit {
1048        Some(Some(foot)) => foot,
1049        Some(None) => {
1050            let foot = project_point_to_surface_seeded(surface, point, seed_u, seed_v).ok();
1051            FOOT_MEMO.with(|memo| {
1052                if let Some(open) = memo.borrow_mut().as_mut().filter(|open| std::ptr::eq(open.surface, surface)) {
1053                    open.seeded.insert(key, foot);
1054                }
1055            });
1056            foot
1057        }
1058        None => project_point_to_surface_seeded(surface, point, seed_u, seed_v).ok(),
1059    }
1060}
1061
1062thread_local! {
1063    /// The open [`PcurveFitScope`]s on this thread, innermost last.
1064    static PCURVE_FIT_SCOPES: std::cell::RefCell<Vec<PcurveFitLedger>> =
1065        const { std::cell::RefCell::new(Vec::new()) };
1066}
1067
1068/// `BREP_DEBUG_PCURVE_FIT` only: a process-wide id per [`refine_pcurve`]
1069/// call, so its first-pass and candidate `PCURVE-TRACK` lines pair up even
1070/// when fits run on several threads.
1071static PCURVE_TRACK_CALL: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
1072
1073/// An open tally of the pcurve fits made on this thread — see
1074/// [`PcurveFitLedger`]. Open it where an operation starts, [`close`] it where
1075/// the operation returns its diagnostics; a `?` that unwinds past it drops the
1076/// tally.
1077///
1078/// [`close`]: PcurveFitScope::close
1079pub struct PcurveFitScope {
1080    /// Not `Send`: the scope must close on the thread that opened it.
1081    _thread_bound: std::marker::PhantomData<*const ()>,
1082}
1083
1084impl PcurveFitScope {
1085    pub fn open() -> Self {
1086        PCURVE_FIT_SCOPES.with(|scopes| scopes.borrow_mut().push(PcurveFitLedger::default()));
1087        Self {
1088            _thread_bound: std::marker::PhantomData,
1089        }
1090    }
1091
1092    /// Take the tally, folding it into the enclosing scope if there is one.
1093    pub fn close(self) -> PcurveFitLedger {
1094        let ledger = PCURVE_FIT_SCOPES.with(|scopes| {
1095            let mut scopes = scopes.borrow_mut();
1096            let ledger = scopes.pop().unwrap_or_default();
1097            if let Some(parent) = scopes.last_mut() {
1098                parent.fold(&ledger);
1099            }
1100            ledger
1101        });
1102        std::mem::forget(self);
1103        ledger
1104    }
1105}
1106
1107impl Drop for PcurveFitScope {
1108    fn drop(&mut self) {
1109        PCURVE_FIT_SCOPES.with(|scopes| {
1110            scopes.borrow_mut().pop();
1111        });
1112    }
1113}
1114
1115pub(crate) fn record_fit(report: &PcurveFitReport) {
1116    // Per-fit trace for the convergence probes (`trim_floor_sweep_probe` and
1117    // its offset-shell sibling): one line per fit with the whole report, the
1118    // way `BREP_DEBUG_PCURVE` traces an endpoint failure.
1119    if std::env::var_os("BREP_DEBUG_PCURVE_FIT").is_some() {
1120        eprintln!("PCURVE-FIT {report:?}");
1121    }
1122    PCURVE_FIT_SCOPES.with(|scopes| {
1123        if let Some(open) = scopes.borrow_mut().last_mut() {
1124            open.record(report);
1125        }
1126    });
1127}
1128
1129/// Largest 3D distance between `pcurve`'s image and `curve` at the
1130/// quarter-points of every span of `parameters` — the stations refinement
1131/// probes, over EVERY span. Evaluations only; nothing is inverted. The sweep
1132/// measures, it does not decide.
1133fn probe_residual(
1134    surface: &NurbsSurface,
1135    curve: &NurbsCurve,
1136    pcurve: &NurbsCurve,
1137    parameters: &[f64],
1138    domain: [f64; 2],
1139    _u_domain: [f64; 2],
1140    _v_domain: [f64; 2],
1141) -> Result<f64, String> {
1142    probe_residual_at(surface, curve, pcurve, parameters, domain, &[0.25, 0.5, 0.75])
1143}
1144
1145/// Extra interior points per sample span, at `j/17` for `j = 1..=16`, that
1146/// [`tracking_acceptance_residual`] reads IN ADDITION to [`probe_residual`]'s
1147/// quarter, mid and three-quarter points (nineteen fractions per span in
1148/// all), so it can never read below the three-point maximum on the same
1149/// curve. The three quarter-points under-read the sixteen-point maximum by
1150/// 3.3–6.5 % on the constructed-cylinder union's imprint pcurves, and sixteen
1151/// sit within 0.4 % of sixty-four there (2026-10-04); the Converged path keeps
1152/// its own read.
1153const TRACKING_ACCEPTANCE_POINTS: usize = 16;
1154
1155/// The same-parameter image-vs-edge distance of `pcurve` at `locals` (span
1156/// fractions) inside every span of `parameters`: the largest, or an error if
1157/// any is not finite.
1158fn probe_residual_at(
1159    surface: &NurbsSurface,
1160    curve: &NurbsCurve,
1161    pcurve: &NurbsCurve,
1162    parameters: &[f64],
1163    [t0, t1]: [f64; 2],
1164    locals: &[f64],
1165) -> Result<f64, String> {
1166    let mut worst = 0.0_f64;
1167    for span in parameters.windows(2) {
1168        for &local in locals {
1169            let fraction = span[0] + (span[1] - span[0]) * local;
1170            let parameter = pcurve.evaluate(fraction)?;
1171            let on_surface =
1172                section_surface_point(surface, parameter.x, parameter.y, true)?;
1173            let on_curve = section_curve_point(curve, t0 + (t1 - t0) * fraction)?;
1174            // `f64::max` drops a NaN operand, so a non-finite distance would
1175            // leave `worst` reading the finite stations only. A residual that
1176            // can accept a curve must have measured every station: fail
1177            // closed instead.
1178            let distance = on_surface.sub(on_curve).length();
1179            if !distance.is_finite() {
1180                return Err(format!(
1181                    "probe_residual: non-finite image distance {distance} at fraction {fraction}"
1182                ));
1183            }
1184            worst = worst.max(distance);
1185        }
1186    }
1187    Ok(worst)
1188}
1189
1190/// The probe fractions a native read takes for the given pcurves: both
1191/// domain ENDPOINTS, and the quarter points plus 16 interior points of every
1192/// span between each curve's OWN distinct knots (the installed interpolant's
1193/// spans, not the construction stations). Merged over all the curves, sorted
1194/// and deduplicated, so a standing fit and a candidate are read at the SAME
1195/// fractions.
1196pub(crate) fn native_probe_fractions(curves: &[&NurbsCurve]) -> Result<Vec<f64>, String> {
1197    let locals: Vec<f64> = [0.25, 0.5, 0.75]
1198        .into_iter()
1199        .chain((1..=TRACKING_ACCEPTANCE_POINTS).map(|index| index as f64 / (TRACKING_ACCEPTANCE_POINTS + 1) as f64))
1200        .collect();
1201    let mut fractions = Vec::new();
1202    for curve in curves {
1203        let [q0, q1] = curve.domain()?;
1204        fractions.push(q0);
1205        fractions.push(q1);
1206        let mut knots: Vec<f64> = curve.knots.iter().copied().filter(|k| *k >= q0 && *k <= q1).collect();
1207        knots.dedup();
1208        for span in knots.windows(2).filter(|w| w[1] > w[0]) {
1209            for &local in &locals {
1210                fractions.push(span[0] + (span[1] - span[0]) * local);
1211            }
1212        }
1213    }
1214    fractions.sort_by(f64::total_cmp);
1215    fractions.dedup();
1216    Ok(fractions)
1217}
1218
1219/// One pcurve read at given probe fractions against the edge curve (whose
1220/// parameter is t0 + (t1 - t0) x fraction): the image's distance from the
1221/// edge point's FOOT on the carrier (its TRACKING, the part a pcurve can
1222/// improve; the foot is seeded at the pcurve's own uv, closed form on an
1223/// analytic carrier), the image's distance from the edge point itself (the
1224/// same-parameter DEVIATION), and the edge point's distance from the carrier
1225/// (its INHERITED STANDOFF). Maxima over the probes; fails closed on any
1226/// non-finite point or distance.
1227#[derive(Clone, Copy, Debug, PartialEq)]
1228struct NativeRead {
1229    tracking: f64,
1230    deviation: f64,
1231    standoff: f64,
1232}
1233
1234fn native_read(surface: &NurbsSurface, curve: &NurbsCurve, pcurve: &NurbsCurve, [t0, t1]: [f64; 2], fractions: &[f64]) -> Result<NativeRead, String> {
1235    let mut read = NativeRead { tracking: 0.0, deviation: 0.0, standoff: 0.0 };
1236    for &fraction in fractions {
1237        let parameter = pcurve.evaluate(fraction)?;
1238        let image = section_surface_point(surface, parameter.x, parameter.y, true)?;
1239        let on_curve = section_curve_point(curve, t0 + (t1 - t0) * fraction)?;
1240        let foot = crate::projection::project_point_to_surface_from_seed(surface, on_curve, [parameter.x, parameter.y])?;
1241        let tracking = image.sub(foot.point).length();
1242        let deviation = image.sub(on_curve).length();
1243        if !(tracking.is_finite() && deviation.is_finite() && foot.distance.is_finite()) {
1244            return Err(format!("native read: non-finite reading at fraction {fraction}"));
1245        }
1246        read.tracking = read.tracking.max(tracking);
1247        read.deviation = read.deviation.max(deviation);
1248        read.standoff = read.standoff.max(foot.distance);
1249    }
1250    Ok(read)
1251}
1252
1253/// Whether an off-carrier tracking candidate replaces the standing fit, both
1254/// read at the SAME probes ([`native_probe_fractions`] of both curves): its
1255/// tracking finite, within the unchanged floor and strictly lower, AND its
1256/// same-parameter deviation no worse (the reported total, inherited standoff
1257/// included, must not grow), AND its own refinement fields finite.
1258fn standoff_candidate_accepted(standing: NativeRead, candidate: NativeRead, candidate_fields_finite: bool, floor: f64) -> bool {
1259    candidate_fields_finite
1260        && candidate.tracking.is_finite()
1261        && candidate.deviation.is_finite()
1262        && candidate.tracking <= floor
1263        && candidate.tracking < standing.tracking
1264        && candidate.deviation <= standing.deviation
1265}
1266
1267/// [`probe_residual_at`] at [`probe_residual`]'s three quarter-points plus
1268/// [`TRACKING_ACCEPTANCE_POINTS`] evenly spaced interior points of every span
1269/// (nineteen per span): the maximum of the old three-point reading and the
1270/// sixteen-point one. It is the reading a budget-exit tracking candidate is
1271/// accepted on, and the residual it is then reported with.
1272fn tracking_acceptance_residual(
1273    surface: &NurbsSurface,
1274    curve: &NurbsCurve,
1275    pcurve: &NurbsCurve,
1276    parameters: &[f64],
1277    domain: [f64; 2],
1278) -> Result<f64, String> {
1279    let locals: Vec<f64> = [0.25, 0.5, 0.75]
1280        .into_iter()
1281        .chain((1..=TRACKING_ACCEPTANCE_POINTS).map(|index| index as f64 / (TRACKING_ACCEPTANCE_POINTS + 1) as f64))
1282        .collect();
1283    probe_residual_at(surface, curve, pcurve, parameters, domain, &locals)
1284}
1285
1286/// Whether a projection-tracking candidate replaces the fit standing in
1287/// [`refine_pcurve`], given the `reading` it is judged on (see
1288/// [`judge_tracking_candidate`]). `standing_dense` says the standing fit's
1289/// reading is itself a nineteen-point one: a budget-exit candidate was taken.
1290///
1291/// While the standing reading is the fitter's own, a `Converged` candidate is
1292/// taken exactly as before (within the floor, better). A BUDGET exit
1293/// (`SampleCeiling`, `RoundBudget`, `Stalled`, `SpanFloor`) is taken only to
1294/// repair a standing fit that MISSES the floor, and only when its
1295/// nineteen-point reading is finite, within the unchanged floor and strictly
1296/// better. Once the standing reading is a nineteen-point one, every later
1297/// candidate is compared nineteen against nineteen: a Converged one must read
1298/// finite, within the floor and strictly better on the same stencil, and a
1299/// budget exit is never taken (the standing fit is then within the floor).
1300/// The exit label says how the loop stopped, not whether the curve is good: on
1301/// the 15° constructed-cylinder union all six imprint pcurves that shipped
1302/// 1.3e-7..7.0e-6 off had a tracking candidate reading 1.4e-8..9.95e-8 at
1303/// three points per span, discarded for its label (2026-10-04). A standing
1304/// fit already within the floor is never replaced by a budget exit, so every
1305/// in-floor fit is unchanged; a taken candidate keeps its own exit, samples
1306/// and raise, and reports the reading it was taken on.
1307fn tracking_candidate_accepted(standing: f64, standing_dense: bool, floor: f64, exit: PcurveFitExit, reading: f64) -> bool {
1308    if exit == PcurveFitExit::Converged && !standing_dense {
1309        return reading <= floor && reading < standing;
1310    }
1311    if exit != PcurveFitExit::Converged && !(standing > floor) {
1312        return false;
1313    }
1314    reading.is_finite() && reading <= floor && reading < standing
1315}
1316
1317/// The reading a tracking candidate is judged on, and whether it replaces the
1318/// standing fit: `own` (the candidate's own residual) for a Converged
1319/// candidate while the standing reading is the fitter's own; otherwise
1320/// `dense` ([`tracking_acceptance_residual`]'s nineteen points per span), read
1321/// only when the candidate could be taken. An error from `dense` declines.
1322/// [`refine_pcurve`] decides and traces through this one function.
1323fn judge_tracking_candidate(
1324    standing: f64,
1325    standing_dense: bool,
1326    floor: f64,
1327    exit: PcurveFitExit,
1328    own: f64,
1329    dense: impl FnOnce() -> Result<f64, String>,
1330) -> (Result<Option<f64>, String>, bool) {
1331    judge_tracking_candidate_with_bounds(standing, standing_dense, floor, exit, own, dense, false)
1332}
1333
1334fn judge_tracking_candidate_with_bounds(
1335    standing: f64,
1336    standing_dense: bool,
1337    floor: f64,
1338    exit: PcurveFitExit,
1339    own: f64,
1340    dense: impl FnOnce() -> Result<f64, String>,
1341    bounds: bool,
1342) -> (Result<Option<f64>, String>, bool) {
1343    // A budget exit's own residual probes the quarter points of every
1344    // returned span. They are a subset of the nineteen-point stencil, so its
1345    // maximum cannot fall below this already over-floor lower bound.
1346    if bounds && exit != PcurveFitExit::Converged && own > floor {
1347        if std::env::var_os("BREP_PROFILE").is_some() { eprintln!("pcurve.reject_bound kind=quarter_residual"); }
1348        return (Ok(Some(own)), false);
1349    }
1350    let reading = if exit == PcurveFitExit::Converged && !standing_dense {
1351        Ok(Some(own))
1352    } else if exit == PcurveFitExit::Converged || standing > floor {
1353        dense().map(Some)
1354    } else {
1355        Ok(None)
1356    };
1357    let accepted = matches!(
1358        reading,
1359        Ok(Some(value)) if tracking_candidate_accepted(standing, standing_dense, floor, exit, value)
1360    );
1361    (reading, accepted)
1362}
1363
1364/// What one call to [`refine_pcurve`] achieved, beside the curve it left in
1365/// place.
1366struct Refinement {
1367    exit: PcurveFitExit,
1368    residual: f64,
1369    off_surface: f64,
1370    raised: bool,
1371    /// [`PcurveFitReport::clamped_excursion`] and
1372    /// [`PcurveFitReport::clamped_distance`] of the curve left in place.
1373    clamped: [f64; 2],
1374}
1375
1376/// Adaptive 3D-residual refinement of an interpolant, with the PER-TRIM sample
1377/// budget. Shared by [`fit_pcurve_on_surface`] (global inversion) and
1378/// [`fit_pcurve_on_surface_marched`] (seeded projection); `insert` is the one
1379/// step that differs — given a probe station's fraction, the current pcurve's
1380/// parameter there and the edge point, it returns the surface parameter to
1381/// interpolate through (or `None` to decline the station) and the distance
1382/// from the edge point to the surface at that station, its GAP.
1383///
1384/// **First pass.** Four rounds at [`MAX_PCURVE_SAMPLES`], each probing the
1385/// quarter-points of every span wider than 1e-3 of the parameter range and
1386/// inserting the stations over `floor`. Byte-for-byte the pre-2026-09-12
1387/// loop; every exit is classified ([`PcurveFitExit`]) and the residual is
1388/// measured on the RETURNED curve — over every span, unless the final round
1389/// probed every span, in which case that round's maximum already is.
1390///
1391/// **The raise.** A [`PcurveFitExit::SampleCeiling`] exit re-enters the four
1392/// rounds ONCE with [`PCURVE_RAISED_SAMPLES`], continuing from the samples it
1393/// has, when the residual exceeds `off_surface` by more than the floor — the
1394/// returned curve is worse than the edge curve's own distance from the
1395/// surface, so more samples CAN improve it. Measured on `25_cube_pierce_solid`
1396/// (2026-09-12): the edge curves there sit off their surfaces by up to 1.9e-4,
1397/// four of the eight ceiling exits already read their gap to four digits, and
1398/// raising those spent 900 inversions each for no change in the swept
1399/// residual. The raised pass therefore inserts only where the pcurve's surface
1400/// point is further than the floor from the PROJECTION of the edge point — its
1401/// tracking error, which the inversion just computed: it stops when the pcurve
1402/// tracks the surface's nearest point to the floor, which is the best any
1403/// pcurve can do, and reports [`PcurveFitExit::Stalled`] with the deviation it
1404/// actually reached when that is still over the floor. The limit of that pass
1405/// as the floor tightens is the projected edge curve itself, so a volume built
1406/// on it can be shown to converge; the deviation test alone cannot say that on
1407/// off-surface input. Grow-once, capped, deterministic.
1408#[allow(clippy::too_many_arguments)]
1409fn refine_pcurve(
1410    surface: &NurbsSurface,
1411    curve: &NurbsCurve,
1412    domain: [f64; 2],
1413    u_domain: [f64; 2],
1414    v_domain: [f64; 2],
1415    floor: f64,
1416    joins: &[f64],
1417    parameters: &mut Vec<f64>,
1418    raw: &mut Vec<[f64; 2]>,
1419    pcurve: &mut NurbsCurve,
1420    off_surface: f64,
1421    clamped: [f64; 2],
1422    mut insert: impl FnMut(f64, Vec3, Vec3) -> Result<(Option<[f64; 2]>, f64), String>,
1423) -> Result<Refinement, String> {
1424    // Trace only (`BREP_DEBUG_PCURVE_FIT`): reads values the passes already
1425    // computed and decides nothing.
1426    let trace = std::env::var_os("BREP_DEBUG_PCURVE_FIT").is_some();
1427    let call = if trace {
1428        PCURVE_TRACK_CALL.fetch_add(1, std::sync::atomic::Ordering::Relaxed) + 1
1429    } else {
1430        0
1431    };
1432    let reject_bounds = PCURVE_REJECT_BOUNDS.with(|state| state.get());
1433    let mut best = refine_pcurve_pass(surface, curve, domain, u_domain, v_domain,
1434        floor, joins, parameters, raw, pcurve, off_surface, clamped, false, 1.0, false, &mut insert, false)?;
1435    if trace {
1436        eprintln!(
1437            "PCURVE-TRACK call={call} first-pass exit={:?} residual={:e} floor={floor:e} off_surface={:e} samples={} raised={} tracking={}",
1438            best.exit,
1439            best.residual,
1440            best.off_surface,
1441            parameters.len(),
1442            best.raised,
1443            if best.off_surface <= floor { "eligible" } else { "standoff-tracking" }
1444        );
1445    }
1446    if best.off_surface > floor {
1447        // The edge curve itself stands off the carrier by more than the floor
1448        // (its INHERITED standoff), so no pcurve can bring the image within the
1449        // floor of the edge point. What a pcurve CAN improve is its tracking
1450        // error: the image's distance from the edge point's foot. Measured
1451        // 2026-10-04 (a2b401d4d, 15-degree crossing, turn 295): a first pass
1452        // ended RoundBudget at 6.726e-6 over a 1.316e-7 standoff and every
1453        // tracking pass was skipped. No candidate refinement when the ACTUAL
1454        // tracking request is met: the first pass's own tracking, read on its
1455        // native spans and endpoints (a diagnostic read; it adds no station),
1456        // within the floor ([`standoff_tracking_rungs`]). A total residual
1457        // under standoff + floor does not prove that: a tangential slip t over
1458        // a standoff g reads sqrt(g^2 + t^2) < g + t.
1459        // `BREP_PCURVE_STANDOFF_TRACKING=0`: diagnostic A/B hatch, not a
1460        // policy. It restores the pre-lane answer (35c8610a1's parent: an
1461        // off-carrier first pass is returned as it stands) for a same-binary
1462        // attribution of a volume or census delta to this lane. Default (unset
1463        // or any other value) is unchanged. It does not touch the in-floor
1464        // tracking rungs or their raise rule, nor the range lane's end-span
1465        // challenger.
1466        if !standoff_tracking_enabled() {
1467            return Ok(best);
1468        }
1469        return standoff_tracking_rungs(surface, curve, domain, u_domain, v_domain, floor, joins,
1470            parameters, raw, pcurve, best, trace, call, &mut insert);
1471    }
1472    // Each target starts from the same baseline station set: retaining the
1473    // coarser target's inserts can exhaust the cap before the finer target
1474    // places its own error-directed stations. Keep the best rung
1475    // [`tracking_candidate_accepted`] takes.
1476    let baseline_parameters = parameters.clone();
1477    let baseline_raw = raw.clone();
1478    let baseline_curve = pcurve.clone();
1479    let baseline_off_surface = best.off_surface;
1480    let baseline_clamped = best.clamped;
1481    // Whether the first pass MISSED the floor: only then may a tracking
1482    // candidate that reaches the sample ceiling still missing its request take
1483    // the existing one-time raise (2026-10-04, 20-degree crossing, turn 295:
1484    // a 1.964e-6 first pass, a candidate at 600 samples reading 1.068e-7,
1485    // declined; the raise needed residual > off_surface + floor). A first pass
1486    // within the floor keeps exactly the work it did before.
1487    // (On this path the edge stands within the floor of the carrier, so a
1488    // first pass over the floor is a tracking miss, not inherited standoff.)
1489    let standing_misses = best.residual > floor;
1490    Ok(tracking_rungs(
1491        best,
1492        floor,
1493        trace,
1494        call,
1495        true,
1496        |fraction| {
1497            let mut refined_parameters = baseline_parameters.clone();
1498            let mut refined_raw = baseline_raw.clone();
1499            let mut refined_curve = baseline_curve.clone();
1500            let candidate = refine_pcurve_pass(surface, curve, domain, u_domain, v_domain,
1501                floor, joins, &mut refined_parameters, &mut refined_raw, &mut refined_curve,
1502                baseline_off_surface, baseline_clamped, true, fraction, standing_misses, &mut insert, reject_bounds && !standing_misses);
1503            (candidate, (refined_parameters, refined_raw, refined_curve))
1504        },
1505        |state: &RungState| tracking_acceptance_residual(surface, curve, &state.2, &state.0, domain),
1506        |state: &RungState| state.0.len(),
1507        |(refined_parameters, refined_raw, refined_curve): RungState| {
1508            *parameters = refined_parameters;
1509            *raw = refined_raw;
1510            *pcurve = refined_curve;
1511        },
1512    ))
1513}
1514
1515/// A tracking candidate's station parameters, raw surface parameters and
1516/// pcurve, as [`refine_pcurve`] hands them to [`tracking_rungs`].
1517type RungState = (Vec<f64>, Vec<[f64; 2]>, NurbsCurve);
1518
1519/// The tracking rungs of [`refine_pcurve`] after an eligible first pass: for
1520/// each tracking fraction, skip it if the standing fit is already that far
1521/// inside the floor, otherwise run the candidate pass (`run_pass`), judge it
1522/// ([`judge_tracking_candidate`], reading `dense` only when needed), trace
1523/// it, and either take it (`adopt` its state; it becomes the standing fit) or
1524/// stop. `samples` is the candidate's station count, for the trace. Separated
1525/// so the accepted-budget state can be driven with scripted passes;
1526/// `thread_dense` is `true` in production and `false` only to show, in a
1527/// test, what dropping the nineteen-point standing flag would take.
1528#[allow(clippy::too_many_arguments)]
1529fn tracking_rungs<S>(
1530    mut best: Refinement,
1531    floor: f64,
1532    trace: bool,
1533    call: u64,
1534    thread_dense: bool,
1535    mut run_pass: impl FnMut(f64) -> (Result<Refinement, String>, S),
1536    mut dense: impl FnMut(&S) -> Result<f64, String>,
1537    samples: impl Fn(&S) -> usize,
1538    mut adopt: impl FnMut(S),
1539) -> Refinement {
1540    // Whether the standing reading is a nineteen-point one (a budget-exit
1541    // candidate was taken); every later candidate is then judged on it.
1542    let mut standing_dense = false;
1543    let reject_bounds = PCURVE_REJECT_BOUNDS.with(|state| state.get());
1544    for fraction in [0.1, 0.01] {
1545        if best.residual <= floor * fraction {
1546            if trace {
1547                eprintln!(
1548                    "PCURVE-TRACK call={call} candidate fraction={fraction} skipped best_residual={:e} <= {:e}",
1549                    best.residual,
1550                    floor * fraction
1551                );
1552            }
1553            continue;
1554        }
1555        let (candidate, state) = run_pass(fraction);
1556        // The reading the candidate is judged on and the decision (see
1557        // judge_tracking_candidate); an unreadable read declines like a
1558        // failed pass.
1559        let judged_dense = matches!(&candidate, Ok(seen) if seen.exit != PcurveFitExit::Converged || standing_dense);
1560        let (effective, accepted) = match &candidate {
1561            Ok(seen) => judge_tracking_candidate_with_bounds(best.residual, standing_dense, floor, seen.exit, seen.residual, || {
1562                dense(&state)
1563            }, reject_bounds),
1564            Err(_) => (Ok(None), false),
1565        };
1566        if trace {
1567            let judged_on = match &effective {
1568                Ok(Some(reading)) => format!("{reading:e}"),
1569                Ok(None) => "-".to_string(),
1570                Err(message) => format!("error:{message:?}"),
1571            };
1572            match &candidate {
1573                Ok(seen) => eprintln!(
1574                    "PCURVE-TRACK call={call} candidate fraction={fraction} exit={:?} residual={:e} judged_on={judged_on} standing_dense={standing_dense} floor={floor:e} off_surface={:e} samples={} raised={} residual_meets_floor={} decision={}",
1575                    seen.exit,
1576                    seen.residual,
1577                    seen.off_surface,
1578                    samples(&state),
1579                    seen.raised,
1580                    seen.residual <= floor,
1581                    if accepted { "accept" } else { "decline-stop" }
1582                ),
1583                Err(message) => eprintln!(
1584                    "PCURVE-TRACK call={call} candidate fraction={fraction} error={message:?} decision=decline-stop"
1585                ),
1586            }
1587        }
1588        match candidate {
1589            Ok(mut candidate) if accepted => {
1590                // Report the reading it was taken on (its own, if Converged).
1591                if let Ok(Some(reading)) = effective {
1592                    candidate.residual = reading;
1593                }
1594                // From here on the standing reading is a nineteen-point one.
1595                if thread_dense {
1596                    standing_dense |= judged_dense;
1597                }
1598                adopt(state);
1599                best = candidate;
1600            }
1601            _ => break,
1602        }
1603    }
1604    best
1605}
1606
1607/// Whether [`refine_pcurve`] takes [`standoff_tracking_rungs`] for an
1608/// off-carrier first pass: true unless `BREP_PCURVE_STANDOFF_TRACKING=0`
1609/// (diagnostic A/B hatch, read once per process).
1610fn standoff_tracking_enabled() -> bool {
1611    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
1612    *ON.get_or_init(|| std::env::var_os("BREP_PCURVE_STANDOFF_TRACKING").is_none_or(|value| value != "0"))
1613}
1614
1615/// The tracking rungs for an edge curve that stands OFF its carrier by more
1616/// than the floor ([`refine_pcurve`]). The first pass is read natively
1617/// ([`native_read`] on its own knot spans and endpoints); when its tracking is
1618/// within the floor, or the read fails, nothing more is done. Otherwise each
1619/// candidate pass (fractions 0.1 then 0.01 of the floor, from the same
1620/// baseline stations, taking the one-time raise when its own tracking target
1621/// is cut short by the ceiling) is read with the standing fit at the SAME
1622/// probes (both curves' native spans and endpoints) and taken only per
1623/// [`standoff_candidate_accepted`]: tracking finite, within the unchanged
1624/// floor and strictly lower, same-parameter deviation no worse, refinement
1625/// fields finite. A taken fit is REPORTED with its same-probe deviation
1626/// (inherited standoff included, so still over the floor) and with an
1627/// `off_surface` that is the larger of its station reading and the probes'
1628/// standoff. Any error, or a candidate that does not qualify, stops the loop
1629/// and keeps the standing curve and report.
1630#[allow(clippy::too_many_arguments)]
1631fn standoff_tracking_rungs(
1632    surface: &NurbsSurface,
1633    curve: &NurbsCurve,
1634    domain: [f64; 2],
1635    u_domain: [f64; 2],
1636    v_domain: [f64; 2],
1637    floor: f64,
1638    joins: &[f64],
1639    parameters: &mut Vec<f64>,
1640    raw: &mut Vec<[f64; 2]>,
1641    pcurve: &mut NurbsCurve,
1642    mut best: Refinement,
1643    trace: bool,
1644    call: u64,
1645    insert: &mut impl FnMut(f64, Vec3, Vec3) -> Result<(Option<[f64; 2]>, f64), String>,
1646) -> Result<Refinement, String> {
1647    let first = native_probe_fractions(&[&*pcurve]).and_then(|probes| native_read(surface, curve, pcurve, domain, &probes));
1648    if trace {
1649        eprintln!("PCURVE-TRACK call={call} standoff-tracking first-pass native={first:?} floor={floor:e}");
1650    }
1651    let Ok(first) = first else { return Ok(best) };
1652    if first.tracking <= floor {
1653        return Ok(best);
1654    }
1655    let baseline_parameters = parameters.clone();
1656    let baseline_raw = raw.clone();
1657    let baseline_curve = pcurve.clone();
1658    for fraction in [0.1, 0.01] {
1659        let mut refined_parameters = baseline_parameters.clone();
1660        let mut refined_raw = baseline_raw.clone();
1661        let mut refined_curve = baseline_curve.clone();
1662        let candidate = refine_pcurve_pass(surface, curve, domain, u_domain, v_domain, floor, joins,
1663            &mut refined_parameters, &mut refined_raw, &mut refined_curve, best.off_surface, best.clamped,
1664            true, fraction, true, &mut *insert, false);
1665        let reads = candidate.as_ref().ok().map(|_| {
1666            native_probe_fractions(&[&*pcurve, &refined_curve]).and_then(|probes| {
1667                Ok((native_read(surface, curve, pcurve, domain, &probes)?, native_read(surface, curve, &refined_curve, domain, &probes)?))
1668            })
1669        });
1670        let fields_finite = matches!(&candidate, Ok(seen) if seen.residual.is_finite() && seen.off_surface.is_finite());
1671        let decision = match &reads {
1672            Some(Ok((standing, read))) => standoff_rung_decision(*standing, *read, fields_finite, floor),
1673            _ => RungDecision::Stop,
1674        };
1675        if trace {
1676            eprintln!(
1677                "PCURVE-TRACK call={call} standoff-tracking fraction={fraction} candidate={} reads={reads:?} decision={}",
1678                match &candidate { Ok(seen) => format!("{:?}/{:e}/raised={}", seen.exit, seen.residual, seen.raised), Err(message) => format!("error:{message:?}") },
1679                match decision { RungDecision::Accept => "accept", RungDecision::Continue => "decline-continue", RungDecision::Stop => "decline-stop" }
1680            );
1681        }
1682        let (Ok(mut taken), Some(Ok((_, read))), RungDecision::Accept) = (candidate, reads, decision) else {
1683            if decision == RungDecision::Continue {
1684                continue;
1685            }
1686            break;
1687        };
1688        taken.residual = read.deviation;
1689        taken.off_surface = taken.off_surface.max(read.standoff);
1690        *parameters = refined_parameters;
1691        *raw = refined_raw;
1692        *pcurve = refined_curve;
1693        best = taken;
1694        if read.tracking <= floor * 0.01 {
1695            break;
1696        }
1697    }
1698    Ok(best)
1699}
1700
1701/// What one off-carrier tracking rung does with its candidate
1702/// ([`standoff_tracking_rungs`]).
1703#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1704enum RungDecision {
1705    /// Taken ([`standoff_candidate_accepted`]).
1706    Accept,
1707    /// Not taken, but it read finite and LOWER tracking than the standing fit
1708    /// while over the floor: the finer fraction is still tried from the same
1709    /// baseline (fixture 25 on e90c30c94: one use read 2.33e-7 at 0.1 and
1710    /// stopped while its partner was taken at 9.0e-9).
1711    Continue,
1712    /// Not taken and not improving (or unreadable): the rungs end.
1713    Stop,
1714}
1715
1716fn standoff_rung_decision(standing: NativeRead, candidate: NativeRead, fields_finite: bool, floor: f64) -> RungDecision {
1717    if standoff_candidate_accepted(standing, candidate, fields_finite, floor) {
1718        RungDecision::Accept
1719    } else if candidate.tracking.is_finite() && candidate.tracking < standing.tracking {
1720        RungDecision::Continue
1721    } else {
1722        RungDecision::Stop
1723    }
1724}
1725
1726/// The one-time raise decision of [`refine_pcurve_pass`]: a ceiling exit not
1727/// yet raised, when the returned curve is worse than the edge's own gap by
1728/// more than the floor (the original rule), or when a tracking pass for an
1729/// unmet first pass returned a curve whose own tracking still misses the
1730/// pass's target (`unmet_tracking`, read on the returned curve). Nothing else
1731/// raises.
1732fn takes_raise(exit: PcurveFitExit, raised: bool, residual: f64, off_surface: f64, floor: f64, unmet_tracking: bool) -> bool {
1733    exit == PcurveFitExit::SampleCeiling && !raised && (residual > off_surface + floor || unmet_tracking)
1734}
1735
1736fn refine_pcurve_pass(
1737    surface: &NurbsSurface,
1738    curve: &NurbsCurve,
1739    [t0, t1]: [f64; 2],
1740    [u0, u1]: [f64; 2],
1741    [v0, v1]: [f64; 2],
1742    floor: f64,
1743    joins: &[f64],
1744    parameters: &mut Vec<f64>,
1745    raw: &mut Vec<[f64; 2]>,
1746    pcurve: &mut NurbsCurve,
1747    mut off_surface: f64,
1748    mut clamped: [f64; 2],
1749    track_projection: bool,
1750    tracking_fraction: f64,
1751    raise_unmet_tracking: bool,
1752    mut insert: impl FnMut(f64, Vec3, Vec3) -> Result<(Option<[f64; 2]>, f64), String>,
1753    reject_budget: bool,
1754) -> Result<Refinement, String> {
1755    let _clock = PcurvePhaseClock::new("refinement", parameters.len(), track_projection);
1756    let tracking_floor = if track_projection { floor * tracking_fraction } else { floor };
1757    let mut max_samples = MAX_PCURVE_SAMPLES;
1758    let mut raised = false;
1759    loop {
1760        // Every way out of this loop is CLASSIFIED (`PcurveFitExit`); a budget
1761        // exit returns the curve it built, but says so. Falling off the end
1762        // after a fourth round of inserts is the round-budget exit.
1763        let mut exit = PcurveFitExit::RoundBudget;
1764        let mut residual = None;
1765        for round in 0..4 {
1766            if parameters.len() >= max_samples {
1767                exit = PcurveFitExit::SampleCeiling;
1768                break;
1769            }
1770            let mut inserts = Vec::new();
1771            let mut round_max = 0.0_f64;
1772            let mut truncated = false;
1773            let mut skipped_narrow = false;
1774            for index in 0..parameters.len() - 1 {
1775                if parameters.len() + inserts.len() >= max_samples {
1776                    truncated = true;
1777                    break;
1778                }
1779                let start = parameters[index];
1780                let end = parameters[index + 1];
1781                // Keep construction's existing first-pass policy. Extended
1782                // residual probes must not silently change its station ladder;
1783                // projection tracking retains its established finer floor.
1784                if end - start < if track_projection { SPAN_FLOOR } else { 1e-3 } {
1785                    skipped_narrow = true;
1786                    continue;
1787                }
1788                for local_fraction in [0.25, 0.5, 0.75] {
1789                    if parameters.len() + inserts.len() >= max_samples {
1790                        truncated = true;
1791                        break;
1792                    }
1793                    let fraction = start + (end - start) * local_fraction;
1794                    let parameter = pcurve.evaluate(fraction)?;
1795                    let on_surface =
1796                        section_surface_point(surface, parameter.x, parameter.y, true)?;
1797                    let on_curve = section_curve_point(curve, t0 + (t1 - t0) * fraction)?;
1798                    let deviation = on_surface.sub(on_curve).length();
1799                    // A non-finite distance must not reach `f64::max` (which
1800                    // drops NaN) or the classification below, where a round
1801                    // with an unreadable station could still exit Converged on
1802                    // its readable ones. Fail closed: a first pass's error
1803                    // goes to its caller, a tracking candidate's declines it.
1804                    if !deviation.is_finite() {
1805                        return Err(format!(
1806                            "refine_pcurve_pass: non-finite station distance {deviation} at fraction {fraction}"
1807                        ));
1808                    }
1809                    round_max = round_max.max(deviation);
1810                    if deviation <= tracking_floor {
1811                        continue;
1812                    }
1813                    let (surface_parameter, gap) = insert(fraction, parameter, on_curve)?;
1814                    off_surface = off_surface.max(gap);
1815                    if let Some(surface_parameter) = surface_parameter {
1816                        // The raised pass stops where the pcurve TRACKS the
1817                        // edge curve's projection to the floor — the best any
1818                        // pcurve can do at this station. Not `deviation - gap`:
1819                        // a surface point at tangential distance d from the
1820                        // projection of a point g off the surface is only
1821                        // d^2/(2g) further from it, so the deviation test is
1822                        // quadratically blind to sideways error on off-surface
1823                        // input (6e-6 of slop at g = 1.9e-4, floor 1e-7).
1824                        if raised || track_projection {
1825                            let projected =
1826                                section_surface_point(surface, surface_parameter[0], surface_parameter[1], false)?;
1827                            if on_surface.sub(projected).length() <= tracking_floor {
1828                                continue;
1829                            }
1830                        }
1831                        inserts.push((index + 1, fraction, surface_parameter));
1832                    }
1833                }
1834            }
1835            if inserts.is_empty() {
1836                // Nothing to insert: every probed station is within the floor
1837                // (converged — unless a narrow span was skipped, in which case
1838                // the sweep below decides), or the ones over it could not be
1839                // improved (stalled — the edge curve is off the surface there).
1840                exit = if truncated {
1841                    PcurveFitExit::SampleCeiling
1842                } else if round_max > floor {
1843                    PcurveFitExit::Stalled
1844                } else if skipped_narrow {
1845                    PcurveFitExit::SpanFloor
1846                } else {
1847                    residual = Some(round_max);
1848                    PcurveFitExit::Converged
1849                };
1850                break;
1851            }
1852            // With inserts still needed after the fourth non-truncated
1853            // round, this exit is RoundBudget. An in-floor standing fit
1854            // never adopts any budget exit; rebuilding and probing this
1855            // discarded candidate cannot affect its curve or report.
1856            if reject_budget && round == 3 && !truncated {
1857                if std::env::var_os("BREP_PROFILE").is_some() { eprintln!("pcurve.reject_bound kind=fifth_round"); }
1858                return Err("pcurve tracking candidate requires a fifth round".into());
1859            }
1860            for (at, fraction, surface_parameter) in inserts.into_iter().rev() {
1861                parameters.insert(at, fraction);
1862                raw.insert(at, surface_parameter);
1863            }
1864            let (rebuilt, excursion, distance) = build_interpolant_joined(surface, raw, parameters, joins)?;
1865            *pcurve = rebuilt;
1866            clamped = [excursion, distance];
1867            if truncated {
1868                exit = PcurveFitExit::SampleCeiling;
1869                break;
1870            }
1871        }
1872        let residual = match residual {
1873            Some(measured) => measured,
1874            // A budget exit never re-checked the curve it is returning, and a
1875            // converged round that skipped narrow spans never checked those:
1876            // measure every span.
1877            None => probe_residual(
1878                surface,
1879                curve,
1880                pcurve,
1881                parameters,
1882                [t0, t1],
1883                [u0, u1],
1884                [v0, v1],
1885            )?,
1886        };
1887        if exit == PcurveFitExit::SpanFloor && residual <= floor {
1888            exit = PcurveFitExit::Converged;
1889        }
1890        // The per-trim budget decision. Deterministic, grow-once, capped (I3):
1891        // the ceiling bound and the returned curve is worse than the edge
1892        // curve's own gap from the surface by more than the floor, so samples
1893        // can still buy accuracy. A curve already at its gap stops here —
1894        // reported, not retried.
1895        // A TRACKING pass for a standing fit that missed the floor (and only
1896        // then) also takes the same one-time raise when it hits the ceiling
1897        // still over the floor: its request is the projection's tracking, and
1898        // the ceiling cut it short. The raised maximum itself is unchanged.
1899        // The added raise serves a TRACKING pass for an unmet first pass whose
1900        // RETURNED curve still misses the pass's own target: its tracking (the
1901        // image against the projected foot, read natively on its own knot spans
1902        // and endpoints) over the tracking floor (floor x fraction). Reaching
1903        // the ceiling alone is exhaustion, not a miss, and the inherited
1904        // standoff never triggers it. Read only at a ceiling exit not yet
1905        // raised; an unreadable read does not raise.
1906        let unmet_tracking = track_projection
1907            && raise_unmet_tracking
1908            && exit == PcurveFitExit::SampleCeiling
1909            && !raised
1910            && native_probe_fractions(&[&*pcurve])
1911                .and_then(|probes| native_read(surface, curve, pcurve, [t0, t1], &probes))
1912                .is_ok_and(|read| read.tracking > tracking_floor);
1913        if takes_raise(exit, raised, residual, off_surface, floor, unmet_tracking) {
1914            raised = true;
1915            max_samples = PCURVE_RAISED_SAMPLES;
1916            continue;
1917        }
1918        return Ok(Refinement {
1919            exit,
1920            residual,
1921            off_surface,
1922            raised,
1923            clamped,
1924        });
1925    }
1926}
1927
1928/// The exact inverse of an affine carrier's parameterization.
1929///
1930/// An affine patch (2x2 net, degree 1 both ways, equal weights) maps `uv` to 3D
1931/// by an affine map, so the inverse — a 3D point to the `uv` of its orthogonal
1932/// projection — is affine too. An affine map commutes with the rational basis:
1933/// sending a curve's control points through it and keeping the weights
1934/// produces the EXACT image of that curve in parameter space, not a fit of it.
1935struct AffineInversion {
1936    origin: Vec3,
1937    du: Vec3,
1938    dv: Vec3,
1939    u0: f64,
1940    v0: f64,
1941    uu: f64,
1942    uv: f64,
1943    vv: f64,
1944    determinant: f64,
1945}
1946
1947impl AffineInversion {
1948    /// `None` when `surface` is not affine, or when its two directions are
1949    /// parallel enough that the inverse is not determined. The caller decides
1950    /// what that means: a refusal on the whole-curve lane, the sampled lane on
1951    /// the range lane.
1952    fn of(surface: &NurbsSurface) -> Result<Option<Self>, String> {
1953        if !surface.is_affine()? {
1954            return Ok(None);
1955        }
1956        let ([u0, _], [v0, _]) = surface_domains(surface)?;
1957        let (origin, du, dv) = surface.deriv1(u0, v0)?;
1958        let uu = du.dot(du);
1959        let uv = du.dot(dv);
1960        let vv = dv.dot(dv);
1961        let determinant = uu * vv - uv * uv;
1962        if determinant.abs() <= 1e-18 {
1963            return Ok(None);
1964        }
1965        Ok(Some(Self {
1966            origin,
1967            du,
1968            dv,
1969            u0,
1970            v0,
1971            uu,
1972            uv,
1973            vv,
1974            determinant,
1975        }))
1976    }
1977
1978    fn uv_of(&self, point: Vec3) -> [f64; 2] {
1979        let delta = point.sub(self.origin);
1980        let along_u = delta.dot(self.du);
1981        let along_v = delta.dot(self.dv);
1982        [
1983            self.u0 + (along_u * self.vv - along_v * self.uv) / self.determinant,
1984            self.v0 + (along_v * self.uu - along_u * self.uv) / self.determinant,
1985        ]
1986    }
1987
1988    /// The exact image of `curve` in this carrier's parameter space, with the
1989    /// curve's own degree, knots and weights.
1990    fn image_of(&self, curve: &NurbsCurve) -> Result<NurbsCurve, String> {
1991        let control_points = curve
1992            .control_points
1993            .iter()
1994            .map(|control| {
1995                let [u, v] = self.uv_of(control.point()?);
1996                Ok(Vec4::from_point(Vec3::new(u, v, 0.0), control.w))
1997            })
1998            .collect::<Result<Vec<_>, String>>()?;
1999        NurbsCurve::new(curve.degree, curve.knots.clone(), control_points)
2000    }
2001}
2002
2003/// Build a parameter-space curve for a 3D curve lying on a surface, and say
2004/// what the fit achieved.
2005///
2006/// This mirrors the reference imprint implementation: affine patches map
2007/// homogeneous control points exactly; general patches use sampled inversion,
2008/// periodic seam unwrapping, and adaptive 3D residual refinement. The report
2009/// beside the curve carries the residual the RETURNED curve reaches and why
2010/// refinement stopped ([`PcurveFitReport`]); the curve itself is what
2011/// [`build_pcurve_on_surface`] has always returned.
2012pub fn fit_pcurve_on_surface(
2013    surface: &NurbsSurface,
2014    curve: &NurbsCurve,
2015) -> Result<PcurveFit, String> {
2016    let mode = std::env::var("BREP_PCURVE_EVAL_CACHE").unwrap_or_default();
2017    let bounds = std::env::var("BREP_PCURVE_REJECT_BOUNDS").unwrap_or_else(|_| "on".into());
2018    let stack = std::env::var("BREP_PCURVE_STACK_POINT").unwrap_or_else(|_| "on".into());
2019    if mode == "check" || bounds == "check" || stack == "check" {
2020        let old = fit_pcurve_on_surface_cached(surface, curve, false, false, false)?;
2021        if matches!(surface.analytic(), Some(AnalyticSurface::Sphere { .. })) {
2022            let candidate = fit_pcurve_on_surface_cached(surface, curve, mode == "check" || mode == "on" || mode == "1", bounds == "check" || bounds == "on" || bounds == "1", stack == "check" || stack == "on" || stack == "1");
2023            let identical = candidate.as_ref().is_ok_and(|new| {
2024                old.curve.degree == new.curve.degree
2025                    && old.curve.knots.len() == new.curve.knots.len()
2026                    && old.curve.knots.iter().zip(&new.curve.knots).all(|(a, b)| a.to_bits() == b.to_bits())
2027                    && old.curve.control_points.len() == new.curve.control_points.len()
2028                    && old.curve.control_points.iter().zip(&new.curve.control_points).all(|(a, b)| {
2029                        [a.x.to_bits(), a.y.to_bits(), a.z.to_bits(), a.w.to_bits()]
2030                            == [b.x.to_bits(), b.y.to_bits(), b.z.to_bits(), b.w.to_bits()]
2031                    }) && old.report == new.report
2032            });
2033            if let Ok(path) = std::env::var("BREP_PCURVE_EVAL_CENSUS") {
2034                use std::io::Write;
2035                if let Ok(mut file) = std::fs::OpenOptions::new().create(true).append(true).open(path) {
2036                    let _ = writeln!(file, "pcurve.eval_census identical={identical} controls={} samples={}", old.curve.control_points.len(), old.report.samples);
2037                }
2038            }
2039        }
2040        return Ok(old);
2041    }
2042    fit_pcurve_on_surface_cached(surface, curve, mode == "1" || mode == "on", bounds == "1" || bounds == "on", stack == "1" || stack == "on")
2043}
2044
2045fn fit_pcurve_on_surface_cached(surface: &NurbsSurface, curve: &NurbsCurve, enabled: bool, bounds: bool, stack: bool) -> Result<PcurveFit, String> {
2046    let _stack = PcurveStackPointScope::open(stack && matches!(surface.analytic(), Some(AnalyticSurface::Sphere { .. })));
2047    let _samples = PcurveSampleScope::open(surface, curve, enabled);
2048    let _bounds = PcurveRejectScope::open(bounds && matches!(surface.analytic(), Some(AnalyticSurface::Sphere { .. })));
2049    let [t0, t1] = curve.domain()?;
2050    if surface.is_affine()? {
2051        let Some(inversion) = AffineInversion::of(surface)? else {
2052            return Err("build_pcurve_on_surface: singular affine parameterization".into());
2053        };
2054        let pcurve = inversion.image_of(curve)?;
2055        return Ok(PcurveFit {
2056            report: PcurveFitReport {
2057                residual: 0.0,
2058                floor: PCURVE_REFINEMENT_TOLERANCE,
2059                samples: pcurve.control_points.len(),
2060                exit: PcurveFitExit::Converged,
2061                off_surface: 0.0,
2062                raised: false,
2063                clamped_excursion: 0.0,
2064                clamped_distance: 0.0,
2065            },
2066            curve: pcurve,
2067        });
2068    }
2069
2070    let scale = 1.0 + curve.evaluate((t0 + t1) / 2.0)?.length();
2071    let drop_tolerance = 1e-4 * scale;
2072    let endpoint_tolerance = 1e-3 * scale;
2073    let refinement_tolerance = PCURVE_REFINEMENT_TOLERANCE;
2074    let ([u0, u1], [v0, v1]) = surface_domains(surface)?;
2075    let invert =
2076        |fraction: f64| invert_checked(surface, section_curve_point(curve, t0 + (t1 - t0) * fraction)?);
2077
2078    let mut parameters = Vec::with_capacity(25);
2079    let mut raw_surface_parameters = Vec::with_capacity(25);
2080    // The edge curve's own distance from the surface at every station inverted,
2081    // accepted or not: the floor below which no pcurve can bring the residual.
2082    let mut off_surface = 0.0_f64;
2083    // The edge's own C0 knots must remain corners of its parameter image.
2084    // Plant those stations before inversion; refinement retains their joins.
2085    let corners = range_breaks(curve, t0, t1, true);
2086    let mut stations: Vec<f64> = (0..=24).map(|index| index as f64 / 24.0).collect();
2087    // Replace nearby uniform seeds, never the native corner itself. Keep
2088    // endpoints and other native corners even when their spans are short.
2089    stations.retain(|station| {
2090        *station == 0.0 || *station == 1.0 || corners.contains(station)
2091            || !corners.iter().any(|corner| (*station - corner).abs() <= SPAN_FLOOR)
2092    });
2093    for &corner in &corners {
2094        let at = stations.partition_point(|value| *value < corner);
2095        if stations.get(at) != Some(&corner) {
2096            stations.insert(at, corner);
2097        }
2098    }
2099    let joins = corners;
2100    for (index, &fraction) in stations.iter().enumerate() {
2101        let (parameter, distance) = invert(fraction)?;
2102        off_surface = off_surface.max(distance);
2103        if distance > drop_tolerance && index != 0 && index != stations.len() - 1 {
2104            continue;
2105        }
2106        if distance > endpoint_tolerance {
2107            if std::env::var("BREP_DEBUG_PCURVE").is_ok() {
2108                let p3 = curve.evaluate(t0 + (t1 - t0) * fraction).ok();
2109                let p0 = curve.evaluate(t0).ok();
2110                let p1 = curve.evaluate(t1).ok();
2111                eprintln!(
2112                    "PCURVE-FAIL idx={index} frac={fraction} dist={distance} endpt_tol={endpoint_tolerance} scale={scale}\n  curve3D@frac={p3:?}\n  curve3D@t0={p0:?} curve3D@t1={p1:?}\n  surf_domain=u[{u0},{u1}] v[{v0},{v1}] invpar={parameter:?}\n  surf@invpar={:?}",
2113                    surface.evaluate(parameter[0], parameter[1]).ok()
2114                );
2115            }
2116            return Err(format!(
2117                "build_pcurve_on_surface: endpoint projection failed (distance={distance})"
2118            ));
2119        }
2120        parameters.push(fraction);
2121        raw_surface_parameters.push(parameter);
2122    }
2123
2124    let (mut pcurve, excursion, distance) =
2125        build_interpolant_joined(surface, &raw_surface_parameters, &parameters, &joins)?;
2126    let refinement = refine_pcurve(
2127        surface,
2128        curve,
2129        [t0, t1],
2130        [u0, u1],
2131        [v0, v1],
2132        refinement_tolerance,
2133        &joins,
2134        &mut parameters,
2135        &mut raw_surface_parameters,
2136        &mut pcurve,
2137        off_surface,
2138        [excursion, distance],
2139        |fraction, _parameter, _on_curve| {
2140            let (surface_parameter, distance) = invert(fraction)?;
2141            Ok((
2142                (distance <= drop_tolerance).then_some(surface_parameter),
2143                distance,
2144            ))
2145        },
2146    )?;
2147    Ok(PcurveFit {
2148        curve: pcurve,
2149        report: PcurveFitReport {
2150            residual: refinement.residual,
2151            floor: refinement_tolerance,
2152            samples: parameters.len(),
2153            exit: refinement.exit,
2154            off_surface: refinement.off_surface,
2155            raised: refinement.raised,
2156            clamped_excursion: refinement.clamped[0],
2157            clamped_distance: refinement.clamped[1],
2158        },
2159    })
2160}
2161
2162/// [`fit_pcurve_on_surface`] for the callers that only need the curve. The
2163/// report is not dropped: it is tallied on the open [`PcurveFitScope`], if any,
2164/// so the operation that owns this fit can say in its diagnostics whether every
2165/// trim reached the floor.
2166pub fn build_pcurve_on_surface(
2167    surface: &NurbsSurface,
2168    curve: &NurbsCurve,
2169) -> Result<NurbsCurve, String> {
2170    let fit = fit_pcurve_on_surface(surface, curve)?;
2171    record_fit(&fit.report);
2172    Ok(fit.curve)
2173}
2174
2175/// Optional section-fit clock; records every early fallback without changing it.
2176struct SectionFitClock {
2177    started: Option<web_time::Instant>,
2178    global: std::time::Duration,
2179    seeded: bool,
2180}
2181impl SectionFitClock {
2182    fn new() -> Self {
2183        Self { started: std::env::var_os("BREP_PROFILE").is_some().then(web_time::Instant::now),
2184            global: std::time::Duration::ZERO, seeded: false }
2185    }
2186}
2187impl Drop for SectionFitClock {
2188    fn drop(&mut self) {
2189        if let Some(started) = self.started {
2190            eprintln!("pcurve.section_time global={:.3} seeded={:.3} result={}",
2191                self.global.as_secs_f64() * 1000.0,
2192                started.elapsed().saturating_sub(self.global).as_secs_f64() * 1000.0,
2193                if self.seeded { "seeded" } else { "global" });
2194        }
2195    }
2196}
2197
2198/// SECTION-PCURVE SEEDED MARCH (t222: cone × ABC 00000327, non-integral genus).
2199///
2200/// `build_pcurve_on_surface` inverts every sample by GLOBAL closest point. Where
2201/// the carrier surface is COMPRESSED / self-overlapping along the row the
2202/// section rides, the global search aliases interior samples onto a DISTANT
2203/// preimage sheet, folding the pcurve out past the trim boundary and re-crossing
2204/// it. The arrangement then splits the shared section at that phantom crossing,
2205/// while the mate face (whose carrier is not folded there) keeps the section
2206/// whole — so the two operands' fragments disagree and the section strands
2207/// one-use (non-integral genus). Ground truth for t222: 00000327 face 496's
2208/// v≈0.7875 row maps u∈[0.55,0.81] into a ~0.18mm neighbourhood of the section
2209/// endpoint A; the global pcurve for piece 9 folded out to u=0.806 and back,
2210/// re-crossing trim edge 349 at v≈0.784, 0.003 below the corner vertex A.
2211///
2212/// This marches the interior inversions with each seeded from the PREVIOUS
2213/// accepted parameters, so a marched sample
2214/// adopts the nearby branch instead of the momentarily-closest distant sheet.
2215/// The two ENDPOINT samples keep the deterministic global inversion (they are
2216/// the piece's shared junction vertices — same reasoning as
2217/// `repair_branch_jumps`). Additive + fail-soft: the marched chain is used ONLY
2218/// when it CLOSES onto the global far endpoint (its last interior sample is
2219/// parameter-adjacent to it, measured against the chain's own median step);
2220/// otherwise the plain global build is returned byte-for-byte. A single-preimage
2221/// carrier (the cone side of the same section) marches to the same samples the
2222/// global search already had. Use the analytic-aware seeded projector for both
2223/// the march and inserted stations: raw Newton stops at 1e-7 even on an exact
2224/// cylinder, introducing avoidable trim error. General folded carriers retain
2225/// their local seeded Newton path; analytic carriers take their closed form.
2226///
2227/// Escape hatch: `BREP_SECTION_PCURVE_MARCH=0`.
2228pub fn fit_pcurve_on_surface_marched(
2229    surface: &NurbsSurface,
2230    curve: &NurbsCurve,
2231) -> Result<PcurveFit, String> {
2232    let mut clock = SectionFitClock::new();
2233    let global = fit_pcurve_on_surface(surface, curve)?;
2234    if let Some(started) = clock.started { clock.global = started.elapsed(); }
2235    if std::env::var("BREP_SECTION_PCURVE_MARCH").as_deref() == Ok("0") || surface.is_affine()? {
2236        return Ok(global);
2237    }
2238    let [t0, t1] = curve.domain()?;
2239    // A closed (ring) section has no distinct endpoints to anchor the march;
2240    // leave it to the existing path (closed rings are handled elsewhere).
2241    if curve.evaluate(t0)?.sub(curve.evaluate(t1)?).length() <= 1e-6 {
2242        return Ok(global);
2243    }
2244    const SAMPLES: usize = 24;
2245    let fractions: Vec<f64> = (0..=SAMPLES).map(|i| i as f64 / SAMPLES as f64).collect();
2246    let edge: Vec<Vec3> = fractions
2247        .iter()
2248        .map(|fraction| curve.evaluate(t0 + (t1 - t0) * fraction))
2249        .collect::<Result<Vec<_>, _>>()?;
2250    let scale = 1.0 + curve.evaluate((t0 + t1) / 2.0)?.length();
2251    let endpoint_tolerance = 1e-3 * scale;
2252    let (first, first_distance) = invert_checked(surface, edge[0])?;
2253    let (last, last_distance) = invert_checked(surface, edge[SAMPLES])?;
2254    if first_distance > endpoint_tolerance || last_distance > endpoint_tolerance {
2255        return Ok(global);
2256    }
2257    // The edge curve's distance from the surface at every station this chain
2258    // inverts — on the MARCHED branch, which is the one being fitted.
2259    let mut off_surface = first_distance.max(last_distance);
2260    let ([u0, u1], [v0, v1]) = surface_domains(surface)?;
2261    let u_span = (u1 - u0).abs().max(EPSILON);
2262    let v_span = (v1 - v0).abs().max(EPSILON);
2263    let (closed_u, closed_v) = surface_closedness(surface)?;
2264    let norm_step = |a: [f64; 2], b: [f64; 2]| -> f64 {
2265        let mut du = a[0] - b[0];
2266        if closed_u {
2267            while du > 0.5 * u_span {
2268                du -= u_span;
2269            }
2270            while du < -0.5 * u_span {
2271                du += u_span;
2272            }
2273        }
2274        let mut dv = a[1] - b[1];
2275        if closed_v {
2276            while dv > 0.5 * v_span {
2277                dv -= v_span;
2278            }
2279            while dv < -0.5 * v_span {
2280                dv += v_span;
2281            }
2282        }
2283        ((du / u_span).powi(2) + (dv / v_span).powi(2)).sqrt()
2284    };
2285    // Forward seeded march over the interior samples.
2286    let mut raw = vec![first];
2287    let mut previous = first;
2288    for index in 1..SAMPLES {
2289        let seeded =
2290            crate::projection::project_point_to_surface_from_seed(surface, edge[index], previous)?;
2291        let (_, global_distance) = invert_checked(surface, edge[index])?;
2292        // The seeded footpoint must still sit on the surface — as tight as the
2293        // fit band or the global answer already had it. If it fell off (the
2294        // seed led Newton into a valley), abandon the march and keep global.
2295        if seeded.distance > 4.0 * global_distance + endpoint_tolerance {
2296            return Ok(global);
2297        }
2298        off_surface = off_surface.max(seeded.distance);
2299        previous = [seeded.u, seeded.v];
2300        raw.push(previous);
2301    }
2302    raw.push(last);
2303    // CLOSURE GATE: the last marched interior sample must be parameter-adjacent
2304    // to the global far endpoint — the march stayed on ONE branch the whole way.
2305    // Measure the endpoint gap against the chain's OWN median step so a genuine
2306    // long edge is not rejected while a sheet-hop (which leaves a big gap to the
2307    // endpoint) is.
2308    let mut steps: Vec<f64> = (1..raw.len())
2309        .map(|i| norm_step(raw[i], raw[i - 1]))
2310        .collect();
2311    let endpoint_gap = steps.pop().unwrap_or(0.0);
2312    steps.sort_by(f64::total_cmp);
2313    let median = steps
2314        .get(steps.len() / 2)
2315        .copied()
2316        .unwrap_or(0.0)
2317        .max(EPSILON);
2318    if endpoint_gap > (4.0 * median).max(0.05) {
2319        return Ok(global);
2320    }
2321    // Build the interpolant from the marched samples, then refine — re-projecting
2322    // each insert SEEDED from the interpolant (already on the marched branch), so
2323    // a mid-refinement global inversion cannot re-alias onto the far sheet.
2324    let mut parameters = fractions;
2325    let (mut pcurve, excursion, distance) = build_interpolant(surface, &raw, &parameters)?;
2326    let refinement_tolerance = PCURVE_REFINEMENT_TOLERANCE;
2327    // Same classified exits and budget ladder as `fit_pcurve_on_surface`. A
2328    // seeded insert always lands, so this loop cannot stall.
2329    let refinement = refine_pcurve(
2330        surface,
2331        curve,
2332        [t0, t1],
2333        [u0, u1],
2334        [v0, v1],
2335        refinement_tolerance,
2336        &[],
2337        &mut parameters,
2338        &mut raw,
2339        &mut pcurve,
2340        off_surface,
2341        [excursion, distance],
2342        |_fraction, seed, on_curve| {
2343            let seeded = crate::projection::project_point_to_surface_from_seed(surface, on_curve, [seed.x, seed.y])?;
2344            Ok((Some([seeded.u, seeded.v]), seeded.distance))
2345        },
2346    )?;
2347    clock.seeded = true;
2348    Ok(PcurveFit {
2349        curve: pcurve,
2350        report: PcurveFitReport {
2351            residual: refinement.residual,
2352            floor: refinement_tolerance,
2353            samples: parameters.len(),
2354            exit: refinement.exit,
2355            off_surface: refinement.off_surface,
2356            raised: refinement.raised,
2357            clamped_excursion: refinement.clamped[0],
2358            clamped_distance: refinement.clamped[1],
2359        },
2360    })
2361}
2362
2363/// [`fit_pcurve_on_surface_marched`] for the callers that only need the curve;
2364/// the report is tallied on the open [`PcurveFitScope`] exactly as
2365/// [`build_pcurve_on_surface`] does.
2366pub fn build_pcurve_on_surface_marched(
2367    surface: &NurbsSurface,
2368    curve: &NurbsCurve,
2369) -> Result<NurbsCurve, String> {
2370    let fit = fit_pcurve_on_surface_marched(surface, curve)?;
2371    record_fit(&fit.report);
2372    Ok(fit.curve)
2373}
2374
2375/// Build a pcurve for a represented subrange of a larger edge curve.
2376///
2377/// On an affine carrier the answer is exact and is taken as such
2378/// ([`affine_pcurve_on_range`]). Otherwise this samples only the represented
2379/// interval, which is essential when off-interval control points do not lie on
2380/// the target carrier — the exact lane restricts the net by knot insertion
2381/// first, so those control points are removed rather than ignored.
2382pub fn fit_pcurve_on_surface_range(
2383    surface: &NurbsSurface,
2384    curve: &NurbsCurve,
2385    edge_start: f64,
2386    edge_end: f64,
2387    forward: bool,
2388    tolerance: f64,
2389) -> Result<PcurveFit, String> {
2390    if let Some(exact) =
2391        affine_pcurve_on_range(surface, curve, edge_start, edge_end, forward, tolerance)?
2392    {
2393        return Ok(exact);
2394    }
2395    fit_pcurve_on_surface_range_dense(
2396        surface, curve, edge_start, edge_end, forward, tolerance, 64, 3, 513,
2397    )
2398}
2399
2400/// [`fit_pcurve_on_surface_range`] for the callers that only need the curve:
2401/// the fit is ACCEPTED or REFUSED on its bar ([`accept_fit`]), never returned
2402/// off it.
2403pub fn build_pcurve_on_surface_range(
2404    surface: &NurbsSurface,
2405    curve: &NurbsCurve,
2406    edge_start: f64,
2407    edge_end: f64,
2408    forward: bool,
2409    tolerance: f64,
2410) -> Result<NurbsCurve, String> {
2411    accept_fit(fit_pcurve_on_surface_range(
2412        surface, curve, edge_start, edge_end, forward, tolerance,
2413    )?)
2414}
2415
2416/// `BREP_DEBUG_STATION_FIT`: trace every station fit round by round, and the
2417/// stations around the worst span of a fit off its bar. Read once per process.
2418fn station_fit_tracing() -> bool {
2419    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
2420    *ON.get_or_init(|| std::env::var_os("BREP_DEBUG_STATION_FIT").is_some())
2421}
2422
2423/// Narrowest span, as a fraction of the parameter range, that
2424/// [`fit_pcurve_on_surface_stations`] subdivides. `refine_pcurve` floors at
2425/// 1e-3 from 25 base samples; this fitter starts from 64 and quarters, so a
2426/// floor of 1e-3 bound on its first pass and refused 67 of the 57-document
2427/// corpus's bodies (measured 2026-09-26). 1e-6 admits every halving a real
2428/// trim needs and stops the runaway that fits stations 4e-7 apart.
2429const SPAN_FLOOR: f64 = 1e-6;
2430
2431/// Rounds the raised pass of [`fit_pcurve_on_surface_stations`] may spend:
2432/// enough halvings for any span the sample cap can resolve.
2433const RAISED_ROUNDS: usize = 40;
2434
2435/// The refusal every station builder returns for a fit off its bar.
2436pub const PCURVE_OFF_BAR: &str = "pcurve fit refused: the trim misses its stations by";
2437
2438/// The one acceptance decision behind [`build_pcurve_on_surface_range`],
2439/// [`build_pcurve_on_surface_range_dense`] and
2440/// [`build_pcurve_on_surface_stations`]: a fit on its bar
2441/// ([`PcurveFitReport::on_bar`]) is the curve, a fit off it is a refusal that
2442/// names the residual, the bar, what was asked, how far the stations stand off
2443/// the carrier and why refinement stopped.
2444///
2445/// Until 2026-09-26 these builders returned whatever their last round built
2446/// without measuring it (the 2026-09-18 census: 4564 of 54556 imported pcurves
2447/// over the ask they were built to, 2072 of them at a station the refinement
2448/// itself had tested and given up on). Nothing here widens a band: the bar is
2449/// the caller's own ask plus what the input makes unreachable.
2450fn accept_fit(fit: PcurveFit) -> Result<NurbsCurve, String> {
2451    let report = fit.report;
2452    if report.on_bar() {
2453        return Ok(fit.curve);
2454    }
2455    Err(off_bar_message(&report))
2456}
2457
2458fn off_bar_message(report: &PcurveFitReport) -> String {
2459    format!(
2460        "{PCURVE_OFF_BAR} {:.3e} out of sample against a bar of {:.3e} (asked {:.1e}, the \
2461         stations stand {:.3e} off the carrier; {:?} at {} samples{}{})",
2462        report.residual,
2463        report.floor + report.off_surface,
2464        report.floor,
2465        report.off_surface,
2466        report.exit,
2467        report.samples,
2468        if report.raised { ", after the raise" } else { "" },
2469        if report.clamped_excursion > 0.0 {
2470            format!(
2471                "; clamped into the chart by {:.3e} in parameter, {:.3e} in 3D",
2472                report.clamped_excursion, report.clamped_distance
2473            )
2474        } else {
2475            String::new()
2476        },
2477    )
2478}
2479
2480/// The class slug of a pcurve fit refused off its bar
2481/// ([`crate::RefusalClass::NonConvergence`]): minted by
2482/// [`build_pcurve_on_surface_range_classed`] and read by
2483/// [`is_pcurve_off_bar`], so a dispatcher decides on the class, never on the
2484/// message text.
2485pub(crate) const PCURVE_OFF_BAR_WHAT: &str = "pcurve_fit_off_bar";
2486
2487/// Whether `refusal` is a pcurve fit that could not reach its bar.
2488pub(crate) fn is_pcurve_off_bar(refusal: &crate::KernelRefusal) -> bool {
2489    matches!(&refusal.class, crate::RefusalClass::NonConvergence { what } if what == PCURVE_OFF_BAR_WHAT)
2490}
2491
2492/// [`build_pcurve_on_surface_range`] with a typed refusal: a fit off its bar
2493/// is `NonConvergence { what: PCURVE_OFF_BAR_WHAT }` at `stage`, with the same
2494/// message; any other failure of the fit is `Internal` under `what`.
2495pub(crate) fn build_pcurve_on_surface_range_classed(
2496    surface: &NurbsSurface,
2497    curve: &NurbsCurve,
2498    edge_start: f64,
2499    edge_end: f64,
2500    forward: bool,
2501    tolerance: f64,
2502    stage: KernelStage,
2503    what: &'static str,
2504) -> Result<NurbsCurve, crate::KernelRefusal> {
2505    use crate::OrRefuse;
2506    let fit = fit_pcurve_on_surface_range(surface, curve, edge_start, edge_end, forward, tolerance)
2507        .or_refuse(stage, what)?;
2508    accept_fit_classed(fit, stage)
2509}
2510
2511/// [`accept_fit`] with the refusal typed: `NonConvergence { what:
2512/// PCURVE_OFF_BAR_WHAT }` at `stage`, the message unchanged.
2513pub(crate) fn accept_fit_classed(fit: PcurveFit, stage: KernelStage) -> Result<NurbsCurve, crate::KernelRefusal> {
2514    if fit.report.on_bar() {
2515        return Ok(fit.curve);
2516    }
2517    Err(crate::KernelRefusal {
2518        class: crate::RefusalClass::NonConvergence { what: PCURVE_OFF_BAR_WHAT.into() },
2519        stage,
2520        message: off_bar_message(&fit.report),
2521    })
2522}
2523
2524/// The EXACT pcurve for a coedge's subrange of `curve` on an affine carrier,
2525/// or `None` when there is no such answer and the sampled lane must run.
2526///
2527/// [`fit_pcurve_on_surface`] has always mapped a WHOLE curve's control net
2528/// exactly on an affine carrier. A coedge's trim is that same curve restricted
2529/// to `[edge_start, edge_end]` and oriented by `forward`, and both operations
2530/// are exact on a NURBS: [`NurbsCurve::split`] subdivides by knot insertion,
2531/// [`NurbsCurve::reversed`] mirrors the net, and rescaling the knots to
2532/// `[0, 1]` is affine in the edge's own parameter — which is precisely the
2533/// fraction convention the sampled lane uses, so the pcurve's correspondence
2534/// with the edge is the same one either lane produces.
2535///
2536/// Sampling where an exact answer exists leaves a real error: measured
2537/// 2026-09-17, a booleaned band rim's two planar trims sat 2.379e-4 and
2538/// 2.395e-4 off their edges, where this lane lands 1.4e-13 off.
2539///
2540/// The image is verified against the caller's own `tolerance` before it is
2541/// returned. The exact image of a curve that does NOT lie on this carrier is
2542/// its orthogonal projection, which is not that coedge's trim, so every such
2543/// case falls through to the sampled lane and keeps the refusals that lane
2544/// makes today.
2545fn affine_pcurve_on_range(
2546    surface: &NurbsSurface,
2547    curve: &NurbsCurve,
2548    edge_start: f64,
2549    edge_end: f64,
2550    forward: bool,
2551    tolerance: f64,
2552) -> Result<Option<PcurveFit>, String> {
2553    // Opt-out for A/B bisection of this lane against the sampled one, in the
2554    // shape of the two hatches beside it (`BREP_NO_PCURVE_REPAIR`,
2555    // `BREP_SECTION_PCURVE_MARCH`). It is what showed that the boolean's
2556    // planar residuals do NOT come through here: the same binary with this set
2557    // and unset read identically to every digit on 21_band_rim.
2558    if std::env::var("BREP_AFFINE_RANGE_PCURVE").as_deref() == Ok("0") {
2559        return Ok(None);
2560    }
2561    let Some(inversion) = AffineInversion::of(surface)? else {
2562        return Ok(None);
2563    };
2564    if !(edge_start.is_finite() && edge_end.is_finite() && edge_start < edge_end) {
2565        // The sampled lane owns this refusal; it is not this lane's to reword.
2566        return Ok(None);
2567    }
2568    let [t0, t1] = curve.domain()?;
2569    let start = edge_start.max(t0);
2570    let end = edge_end.min(t1);
2571    // A range narrower than the knot identity tolerance cannot be split onto
2572    // its own endpoints at all.
2573    if end - start <= 2.0 * KNOT_IDENTITY_TOL {
2574        return Ok(None);
2575    }
2576    let mut restricted = curve.clone();
2577    if end < t1 - KNOT_IDENTITY_TOL {
2578        restricted = restricted.split(end)?.0;
2579    }
2580    if start > t0 + KNOT_IDENTITY_TOL {
2581        restricted = restricted.split(start)?.1;
2582    }
2583    let mut pcurve = inversion.image_of(&restricted)?;
2584    if !forward {
2585        pcurve = pcurve.reversed()?;
2586    }
2587    let first = pcurve.knots[0];
2588    let last = pcurve.knots[pcurve.knots.len() - 1];
2589    if !(last - first > 0.0) {
2590        return Ok(None);
2591    }
2592    let knots = pcurve
2593        .knots
2594        .iter()
2595        .map(|knot| (knot - first) / (last - first))
2596        .collect::<Vec<_>>();
2597    let pcurve = NurbsCurve::new(pcurve.degree, knots, pcurve.control_points.clone())?;
2598
2599    // Verify against the range the CALLER asked for, not the one the
2600    // restriction produced: `split` snaps onto a nearby knot, so a snap that
2601    // moved the correspondence reads here as a deviation. Sampling at
2602    // fractions that are not the stations any lane interpolates through keeps
2603    // this a check on the whole trim rather than on its endpoints.
2604    let scale = 1.0 + curve.evaluate((start + end) / 2.0)?.length();
2605    let bar = tolerance.max(1e-11 * scale);
2606    let mut residual = 0.0_f64;
2607    for index in 0..=32 {
2608        let fraction = index as f64 / 32.0;
2609        let uv = pcurve.evaluate(fraction)?;
2610        // `evaluate` CLAMPS out-of-domain uv. A planar carrier's domain is a
2611        // bounding rectangle that a booleaned trim can leave, and an affine
2612        // patch's extension is the same plane, so read it unclamped.
2613        let on_carrier = surface.evaluate_extended(uv.x, uv.y)?;
2614        let edge_fraction = if forward { fraction } else { 1.0 - fraction };
2615        let on_edge = curve.evaluate(start + (end - start) * edge_fraction)?;
2616        residual = residual.max(on_carrier.sub(on_edge).length());
2617        if residual > bar {
2618            return Ok(None);
2619        }
2620    }
2621    let samples = pcurve.control_points.len();
2622    Ok(Some(PcurveFit {
2623        curve: pcurve,
2624        report: PcurveFitReport {
2625            residual,
2626            // The floor this lane VERIFIED against: the caller's ask, or the
2627            // floating-point floor of an exact map on a part this size. An
2628            // exact image is on its bar by construction; a caller asking for
2629            // less than the map's own precision is not refused for it.
2630            floor: bar,
2631            samples,
2632            exit: PcurveFitExit::Converged,
2633            off_surface: 0.0,
2634            raised: false,
2635            clamped_excursion: 0.0,
2636            clamped_distance: 0.0,
2637        },
2638    }))
2639}
2640
2641fn align_collapsed_endpoints(surface: &NurbsSurface, raw: &mut [[f64; 2]]) -> Result<(), String> {
2642    let anchor = surface.control_points[0][0].point()?;
2643    let mut extent = 0.0_f64;
2644    for control in surface.control_points.iter().flatten() {
2645        extent = extent.max(control.point()?.sub(anchor).length());
2646    }
2647    // This is a geometric identity check, independent of the fitting allowance
2648    // and of world position. Positive rational weights keep the whole iso-curve
2649    // inside the convex hull of its Euclidean controls. Cap the size coupling
2650    // at the linear tolerance so a large patch cannot erase a thin finite row.
2651    let pole_band = (1e-10 * (1.0 + extent)).min(LINEAR_TOLERANCE);
2652    for (endpoint, neighbor) in [(0, 1), (raw.len() - 1, raw.len() - 2)] {
2653        let point = surface.evaluate(raw[endpoint][0], raw[endpoint][1])?;
2654        for axis in 0..2 {
2655            let mut candidate = raw[endpoint];
2656            candidate[axis] = raw[neighbor][axis];
2657            if candidate == raw[endpoint]
2658                || surface
2659                    .evaluate(candidate[0], candidate[1])?
2660                    .sub(point)
2661                    .length()
2662                    > pole_band
2663            {
2664                continue;
2665            }
2666            let row = if axis == 0 {
2667                surface.iso_curve_v(raw[endpoint][1])?
2668            } else {
2669                surface.iso_curve_u(raw[endpoint][0])?
2670            };
2671            let mut collapsed = true;
2672            for control in &row.control_points {
2673                if control.point()?.sub(point).length() > pole_band {
2674                    collapsed = false;
2675                    break;
2676                }
2677            }
2678            if collapsed {
2679                raw[endpoint] = candidate;
2680            }
2681        }
2682    }
2683    Ok(())
2684}
2685
2686/// Re-seat any raw inversion sample that BRANCH-JUMPED — snapped to a distant
2687/// fold of a self-overlapping general carrier — back onto the branch traced by
2688/// its neighbours.
2689///
2690/// Each entry in `raw` is an INDEPENDENT global closest-point inversion of the
2691/// corresponding 3D edge sample. Every one is geometrically valid (on the
2692/// surface, at the edge), but they need not be CONTIGUOUS: where a rational
2693/// B-spline surface folds back over the small trimmed patch it carries, the
2694/// momentarily-closest fold flips from one sample to the next, so the raw
2695/// polygon zig-zags across the whole domain and self-crosses — and the region
2696/// its interpolant bounds no longer covers the true face (its surface flux can
2697/// exceed its own area). We anchor on the LONGEST run of mutually-continuous
2698/// samples — the fold the trimmed patch actually lies on, since a small face
2699/// lives on ONE fold and the jumped samples are the minority the global search
2700/// snapped elsewhere — then walk outward in both directions, re-seeding Newton
2701/// from the last good parameters and adopting the continuous footpoint whenever
2702/// it is geometrically as valid as the global one. Anchoring on consensus (not
2703/// blindly on sample 0, which can itself be an outlier that would drag the
2704/// whole edge onto the wrong branch and tear the loop open at its endpoint)
2705/// leaves continuous nonsingular fits unchanged. Certified collapsed endpoint
2706/// rows first adopt their neighbour's branch; a bad seed in the subsequent
2707/// jump repair cannot make a sample worse than the global search already had it.
2708fn repair_branch_jumps(
2709    surface: &NurbsSurface,
2710    edge_points: &[Vec3],
2711    raw: &mut [[f64; 2]],
2712    tolerance: f64,
2713) -> Result<(), String> {
2714    if raw.len() < 3 {
2715        return Ok(());
2716    }
2717    // Affine carriers invert linearly and exactly — no folds, nothing to chase.
2718    // Checked first so the common planar/affine face never touches the env.
2719    if surface.is_affine()? {
2720        return Ok(());
2721    }
2722    // Opt-out for A/B bisection of a STEP-import regression against this repair.
2723    if std::env::var("BREP_NO_PCURVE_REPAIR").is_ok() {
2724        return Ok(());
2725    }
2726    // A pole has no unique coordinate along its collapsed row. Continuing the
2727    // adjacent sample's branch is safe only when the ENTIRE row is collapsed;
2728    // coincident points across an ordinary seam or fold are not enough.
2729    align_collapsed_endpoints(surface, raw)?;
2730    let ([u0, u1], [v0, v1]) = surface_domains(surface)?;
2731    let u_span = (u1 - u0).abs().max(EPSILON);
2732    let v_span = (v1 - v0).abs().max(EPSILON);
2733    let (closed_u, closed_v) = surface_closedness(surface)?;
2734    // Normalised, seam-aware step between two parameter samples. Wrapping the
2735    // closed directions keeps a legitimate seam crossing SMALL, so the seam /
2736    // periodic-unwrap machinery elsewhere is never disturbed by this repair.
2737    let norm_step = |a: [f64; 2], b: [f64; 2]| -> f64 {
2738        let mut du = a[0] - b[0];
2739        if closed_u {
2740            while du > 0.5 * u_span {
2741                du -= u_span;
2742            }
2743            while du < -0.5 * u_span {
2744                du += u_span;
2745            }
2746        }
2747        let mut dv = a[1] - b[1];
2748        if closed_v {
2749            while dv > 0.5 * v_span {
2750                dv -= v_span;
2751            }
2752            while dv < -0.5 * v_span {
2753                dv += v_span;
2754            }
2755        }
2756        ((du / u_span).powi(2) + (dv / v_span).powi(2)).sqrt()
2757    };
2758    // A jump crosses a large fraction of the WHOLE domain — orders above the
2759    // per-sample motion of any real (even domain-spanning) edge, which advances
2760    // ~1/N of its traversal between consecutive stations.
2761    const JUMP_THRESHOLD: f64 = 0.2;
2762    let count = raw.len();
2763
2764    // Locate the longest maximal run of consecutive continuous samples — the
2765    // branch to anchor on. If nothing jumps, this spans [0, count-1] and both
2766    // re-seat passes below are empty, leaving `raw` untouched.
2767    let (mut best_start, mut best_len, mut run_start) = (0usize, 1usize, 0usize);
2768    for index in 1..count {
2769        if norm_step(raw[index], raw[index - 1]) > JUMP_THRESHOLD {
2770            if index - run_start > best_len {
2771                best_len = index - run_start;
2772                best_start = run_start;
2773            }
2774            run_start = index;
2775        }
2776    }
2777    if count - run_start > best_len {
2778        best_len = count - run_start;
2779        best_start = run_start;
2780    }
2781    let (spine_lo, spine_hi) = (best_start, best_start + best_len - 1);
2782
2783    // Adopt the continuous footpoint only when it (a) still sits on the surface
2784    // — as tight as the fit band or the global answer — and (b) genuinely
2785    // closes the jump rather than trading it for another. Returns the parameter
2786    // to carry forward as the next seed (the repaired one, or the untouched
2787    // global when no repair applies).
2788    let reseat = |edge_point: Vec3,
2789                  previous: [f64; 2],
2790                  global: [f64; 2]|
2791     -> Result<[f64; 2], String> {
2792        let global_step = norm_step(global, previous);
2793        if global_step <= JUMP_THRESHOLD {
2794            return Ok(global);
2795        }
2796        let seeded =
2797            project_point_to_surface_seeded(surface, edge_point, previous[0], previous[1])?;
2798        let candidate = [seeded.u, seeded.v];
2799        let global_residual = surface
2800            .evaluate(global[0], global[1])?
2801            .sub(edge_point)
2802            .length();
2803        let on_surface = seeded.distance <= 4.0 * global_residual + tolerance.max(1e-12);
2804        if on_surface && norm_step(candidate, previous) < 0.5 * global_step {
2805            if std::env::var("BREP_DEBUG_PCURVE").is_ok() {
2806                eprintln!(
2807                    "pcurve repair: jump {global_step:.4} ({global:?}) -> {:.4} ({candidate:?}) res {:.2e}->{:.2e}",
2808                    norm_step(candidate, previous),
2809                    global_residual,
2810                    seeded.distance
2811                );
2812            }
2813            Ok(candidate)
2814        } else {
2815            Ok(global)
2816        }
2817    };
2818
2819    // Walk forward off the spine's high end, then backward off its low end,
2820    // chaining each repaired sample as the next seed so continuity propagates.
2821    //
2822    // Apart from the certified collapsed rows above, the two ENDPOINT samples
2823    // (fraction 0 and 1) are NEVER moved: they are the
2824    // edge's shared loop vertices. The global inversion is deterministic, so the
2825    // two coedges meeting at a vertex land it at the SAME parameters even when
2826    // that vertex sits on a fold reachable from two branches — moving one side
2827    // to a different branch tears the loop open there (`synthesize_pole_edge`
2828    // then rejects the non-collapsed gap). A vertex's genuine fold transition
2829    // (an edge whose interior rides u≈0.08 but whose endpoint must meet its
2830    // neighbour at u≈0.95) is exactly this case and must be preserved, not
2831    // "continuity-repaired" back onto the interior branch.
2832    let mut previous = raw[spine_hi];
2833    for index in (spine_hi + 1)..count.saturating_sub(1) {
2834        raw[index] = reseat(edge_points[index], previous, raw[index])?;
2835        previous = raw[index];
2836    }
2837    let mut previous = raw[spine_lo];
2838    for index in (1..spine_lo).rev() {
2839        raw[index] = reseat(edge_points[index], previous, raw[index])?;
2840        previous = raw[index];
2841    }
2842    Ok(())
2843}
2844
2845/// Range fitter with explicit sampling knobs, reporting what the fit achieved.
2846/// [`fit_pcurve_on_surface_range`] keeps the long-standing (base 64, 3
2847/// refinement rounds, 513 cap) budget; a fit that binds at that cap with the
2848/// bar unmet grows once to [`PCURVE_RAISED_SAMPLES`]
2849/// ([`fit_pcurve_on_surface_stations`]).
2850///
2851/// NOTE (2026-09-03): this comment used to say "STEP import retries failed fits
2852/// with a denser budget". No caller passes these knobs any more — that retry
2853/// was removed and the sentence outlived it. The knobs are kept because they
2854/// are the honest way to ASK whether a fit had headroom left, which is what
2855/// `examples/pcurve_residual_probe.rs` uses them for: on every ABC corpus
2856/// coedge that failed `validate`'s pcurve check, budgets up to (512, 8, 8193)
2857/// with a 1000x tighter target reproduced the coarse fit's deviation to six
2858/// decimals, because that deviation is the edge-vs-surface closest-point
2859/// residual and a curve ON the surface cannot beat it.
2860#[allow(clippy::too_many_arguments)]
2861pub fn fit_pcurve_on_surface_range_dense(
2862    surface: &NurbsSurface,
2863    curve: &NurbsCurve,
2864    edge_start: f64,
2865    edge_end: f64,
2866    forward: bool,
2867    tolerance: f64,
2868    base_samples: usize,
2869    refinement_rounds: usize,
2870    parameter_cap: usize,
2871) -> Result<PcurveFit, String> {
2872    if !(edge_start.is_finite() && edge_end.is_finite() && edge_start < edge_end) {
2873        return Err("build_pcurve_on_surface_range: invalid edge interval".into());
2874    }
2875    let evaluate_edge = |fraction: f64| {
2876        let edge_fraction = if forward { fraction } else { 1.0 - fraction };
2877        curve.evaluate(edge_start + (edge_end - edge_start) * edge_fraction)
2878    };
2879    let breaks = range_breaks(curve, edge_start, edge_end, forward);
2880    let ask = tolerance.max(PCURVE_REFINEMENT_TOLERANCE);
2881    let fit = fit_station_pcurve(
2882        surface,
2883        &evaluate_edge,
2884        &breaks,
2885        &breaks,
2886        ask,
2887        base_samples,
2888        refinement_rounds,
2889        parameter_cap,
2890        SPAN_FLOOR,
2891    )?;
2892    end_span_challenger(surface, curve, &evaluate_edge, edge_start, edge_end, forward, &breaks, ask, base_samples, refinement_rounds, parameter_cap, fit)
2893}
2894
2895/// The edge curve's OWN distinct interior knots inside `[edge_start,
2896/// edge_end]`, mapped through the trim's range and sense to coedge
2897/// fractions, that fall inside `pcurve`'s FIRST or LAST span (between the
2898/// domain end and its nearest interior knot), sorted.
2899fn native_end_knot_fractions(curve: &NurbsCurve, edge_start: f64, edge_end: f64, forward: bool, pcurve: &NurbsCurve) -> Result<Vec<f64>, String> {
2900    let [q0, q1] = pcurve.domain()?;
2901    let mut interior: Vec<f64> = pcurve.knots.iter().copied().filter(|k| *k > q0 && *k < q1).collect();
2902    interior.dedup();
2903    let (Some(&first), Some(&last)) = (interior.first(), interior.last()) else { return Ok(Vec::new()) };
2904    let (low, high) = (edge_start.min(edge_end), edge_start.max(edge_end));
2905    let span = edge_end - edge_start;
2906    let mut fractions: Vec<f64> = curve
2907        .knots
2908        .iter()
2909        .copied()
2910        .filter(|k| *k > low && *k < high)
2911        .map(|k| {
2912            let along = (k - edge_start) / span;
2913            if forward { along } else { 1.0 - along }
2914        })
2915        .filter(|f| f.is_finite() && ((*f > q0 && *f < first) || (*f > last && *f < q1)))
2916        .collect();
2917    fractions.sort_by(f64::total_cmp);
2918    fractions.dedup();
2919    Ok(fractions)
2920}
2921
2922/// The admission rule for a foot read against an edge point: finite distance,
2923/// finite point, finite (u, v) inside the native domain. Shared by
2924/// [`common_station_read`] and the station fitter's tracking mode.
2925fn foot_admitted(foot: &crate::SurfaceProjection, [u0, u1]: [f64; 2], [v0, v1]: [f64; 2]) -> bool {
2926    let finite = |p: Vec3| p.x.is_finite() && p.y.is_finite() && p.z.is_finite();
2927    foot.distance.is_finite() && finite(foot.point) && foot.u.is_finite() && foot.v.is_finite() && (u0..=u1).contains(&foot.u) && (v0..=v1).contains(&foot.v)
2928}
2929
2930/// The tracking mode's verification probes: the current pcurve's native probes
2931/// ([`native_probe_fractions`]: endpoints, quarters and 16 interior points of
2932/// each knot span), its EXACT knots (the final common read includes them, and
2933/// the native probes do not), and the caller's fixed fractions; finite, in
2934/// [0, 1], sorted, deduplicated.
2935fn verification_fractions(pcurve: &NurbsCurve, verify: &[f64]) -> Result<Vec<f64>, String> {
2936    let mut fractions = native_probe_fractions(&[pcurve])?;
2937    fractions.extend(pcurve.knots.iter().copied());
2938    fractions.extend(verify.iter().copied());
2939    fractions.retain(|f| f.is_finite() && (0.0..=1.0).contains(f));
2940    fractions.sort_by(f64::total_cmp);
2941    fractions.dedup();
2942    Ok(fractions)
2943}
2944
2945/// The off-carrier candidate admission, at the same probes and shared feet
2946/// (`[tracking, deviation, excess]` per curve, [`common_station_read_with_excess`]):
2947/// every reading finite, the candidate's tracking strictly lower, and EITHER
2948/// its maximum deviation no worse than the legacy's (the original rule) OR the
2949/// candidate meeting the ORIGINAL floors outright, tracking and excess both
2950/// within `PCURVE_REFINEMENT_TOLERANCE` (1e-7).
2951///
2952/// Why the second branch: for fits whose images follow the shared admitted
2953/// feet, the maximum deviation can be dominated by the edge's standoff.
2954/// Their measured maxima can then differ by rounding while tracking improves.
2955/// This does not assert that the admitted foot is a certified global nearest
2956/// point or that an arbitrary pcurve has the same maximum deviation.
2957/// next5 fixture 25 (BREP_DEBUG_STATION_FIT): every tracking candidate reached
2958/// the floor (9.52e-8 .. 9.94e-8 tracking) and was declined on a deviation
2959/// 1.2e-14 .. 6.7e-13 above the legacy's at 2.1e-5 .. 9.0e-4 standoffs, while
2960/// the legacy kept 5.9e-7 .. 8.5e-5 tracking. A candidate within the original
2961/// floors on both readings is what those controls require; it is not a
2962/// standoff allowance and no bar moves.
2963pub(crate) fn floor_admits(old: [f64; 3], new: [f64; 3]) -> bool {
2964    let floor = PCURVE_REFINEMENT_TOLERANCE;
2965    old.iter().chain(new.iter()).all(|v| v.is_finite())
2966        && new[0] < old[0]
2967        && (new[1] <= old[1] || (new[0] <= floor && new[2] <= floor))
2968}
2969
2970/// The common reader's foot: the NEAREST admitted ([`foot_admitted`]) of the
2971/// global projection, the projection seeded at the reference (legacy) uv and
2972/// the one seeded at the candidate (image) uv, in THAT order, so that between
2973/// admitted feet at equal distance the first in this order is taken
2974/// (`min_by` keeps the first minimum). [`common_station_read`] and the station
2975/// fitter's tracking mode both take their foot here, so an equal-distance tie
2976/// resolves to the same foot in both.
2977fn common_foot(
2978    global: Option<crate::SurfaceProjection>,
2979    reference: Option<crate::SurfaceProjection>,
2980    candidate: Option<crate::SurfaceProjection>,
2981    domain_u: [f64; 2],
2982    domain_v: [f64; 2],
2983) -> Option<crate::SurfaceProjection> {
2984    [global, reference, candidate]
2985        .into_iter()
2986        .flatten()
2987        .filter(|f| foot_admitted(f, domain_u, domain_v))
2988        .min_by(|a, b| a.distance.total_cmp(&b.distance))
2989}
2990
2991/// The probes a RANGE trim is read at by the common reader: `curves`'
2992/// native spans (endpoints, quarters and 16 interior points of each knot
2993/// span) and exact knots, plus the edge curve's own knots CLIPPED to
2994/// `[t0, t1]` (with the range ends) and the same 19 points on every clipped
2995/// span, mapped through the coedge's sense to fractions; finite, in [0, 1],
2996/// sorted, deduplicated.
2997pub(crate) fn range_use_probes(curves: &[&NurbsCurve], edge_curve: &NurbsCurve, t0: f64, t1: f64, forward: bool) -> Result<Vec<f64>, String> {
2998    let mut probes = native_probe_fractions(curves)?;
2999    for curve in curves {
3000        probes.extend(curve.knots.iter().copied());
3001    }
3002    let span = t1 - t0;
3003    if span.is_finite() && span != 0.0 {
3004        let (low, high) = (t0.min(t1), t0.max(t1));
3005        let mut knots: Vec<f64> = edge_curve.knots.iter().copied().filter(|k| *k >= low && *k <= high).collect();
3006        knots.push(low);
3007        knots.push(high);
3008        knots.sort_by(f64::total_cmp);
3009        knots.dedup();
3010        let locals: Vec<f64> = [0.25, 0.5, 0.75]
3011            .into_iter()
3012            .chain((1..=TRACKING_ACCEPTANCE_POINTS).map(|index| index as f64 / (TRACKING_ACCEPTANCE_POINTS + 1) as f64))
3013            .collect();
3014        let mut ts = knots.clone();
3015        for pair in knots.windows(2).filter(|w| w[1] > w[0]) {
3016            for &local in &locals {
3017                ts.push(pair[0] + (pair[1] - pair[0]) * local);
3018            }
3019        }
3020        for t in ts {
3021            let along = (t - t0) / span;
3022            probes.push(if forward { along } else { 1.0 - along });
3023        }
3024    }
3025    probes.retain(|f| f.is_finite() && (0.0..=1.0).contains(f));
3026    probes.sort_by(f64::total_cmp);
3027    probes.dedup();
3028    Ok(probes)
3029}
3030
3031/// [`common_station_read`] for two RANGE trims of one coedge (`old`, `new`,
3032/// both on the coedge fraction domain [0, 1]) against the edge curve over
3033/// `[t0, t1]` in the coedge's sense, at [`range_use_probes`] of both: the same
3034/// probes and one shared admitted foot per probe, finite or an error. A trim
3035/// not on [0, 1] is an error.
3036// Unused by the import lane since the tracking trigger and keep were withdrawn
3037// for this merge; kept, with its controls, for their re-proposal.
3038#[cfg_attr(not(test), allow(dead_code))]
3039pub(crate) fn range_common_read(
3040    surface: &NurbsSurface,
3041    edge_curve: &NurbsCurve,
3042    t0: f64,
3043    t1: f64,
3044    forward: bool,
3045    old: &NurbsCurve,
3046    new: &NurbsCurve,
3047) -> Result<((f64, f64), (f64, f64)), String> {
3048    let (o, n) = range_common_read_with_excess(surface, edge_curve, t0, t1, forward, old, new)?;
3049    Ok(((o[0], o[1]), (n[0], n[1])))
3050}
3051
3052/// [`range_common_read`] with each trim's maximum pointwise excess over the
3053/// shared admitted foot's own distance: `[tracking, deviation, excess]` per
3054/// trim ([`common_station_read_with_excess`]).
3055// Unused by the import lane since the tracking trigger and keep were withdrawn
3056// for this merge; kept, with its controls, for their re-proposal.
3057#[cfg_attr(not(test), allow(dead_code))]
3058pub(crate) fn range_common_read_with_excess(
3059    surface: &NurbsSurface,
3060    edge_curve: &NurbsCurve,
3061    t0: f64,
3062    t1: f64,
3063    forward: bool,
3064    old: &NurbsCurve,
3065    new: &NurbsCurve,
3066) -> Result<([f64; 3], [f64; 3]), String> {
3067    for curve in [old, new] {
3068        if !matches!(curve.domain(), Ok([a, b]) if a == 0.0 && b == 1.0) {
3069            return Err("range common read: a trim not on [0, 1]".into());
3070        }
3071    }
3072    let probes = range_use_probes(&[old, new], edge_curve, t0, t1, forward)?;
3073    let evaluate = |fraction: f64| -> Result<Vec3, String> {
3074        let along = if forward { fraction } else { 1.0 - fraction };
3075        edge_curve.evaluate(t0 + (t1 - t0) * along)
3076    };
3077    common_station_read_with_excess(surface, &evaluate, old, new, &probes)
3078}
3079
3080/// The legacy and candidate pcurves read against the edge at the SAME probes
3081/// and against the SAME foot per probe: at each fraction, the edge point's
3082/// foot is the NEAREST admitted one among the global projection and the
3083/// projections seeded at the legacy and the candidate image's (u, v). A foot
3084/// is admitted with a finite distance and point and a finite (u, v) inside the
3085/// native domain. Both images are then measured against that one shared foot
3086/// (TRACKING) and against the edge point (same-parameter DEVIATION). The
3087/// shared foot is the nearest of these three, not a certified global nearest.
3088/// Any non-finite image, point or distance, or a probe with no admitted foot,
3089/// is an error (the caller keeps the legacy fit). Returns
3090/// ((legacy tracking, legacy deviation), (candidate tracking, candidate
3091/// deviation)), maxima over the probes.
3092pub(crate) fn common_station_read(
3093    surface: &NurbsSurface,
3094    evaluate_edge: &dyn Fn(f64) -> Result<Vec3, String>,
3095    legacy: &NurbsCurve,
3096    candidate: &NurbsCurve,
3097    probes: &[f64],
3098) -> Result<((f64, f64), (f64, f64)), String> {
3099    let (old, new) = common_station_read_with_excess(surface, evaluate_edge, legacy, candidate, probes)?;
3100    Ok(((old[0], old[1]), (new[0], new[1])))
3101}
3102
3103/// [`common_station_read`] that also returns, per curve, the maximum
3104/// pointwise EXCESS: the same-parameter deviation minus the shared admitted
3105/// foot's own distance at that probe (the part over the edge's standoff
3106/// there, which the every-use controls bar at the original 1e-7). Returns
3107/// `[tracking, deviation, excess]` for the legacy and the candidate.
3108pub(crate) fn common_station_read_with_excess(
3109    surface: &NurbsSurface,
3110    evaluate_edge: &dyn Fn(f64) -> Result<Vec3, String>,
3111    legacy: &NurbsCurve,
3112    candidate: &NurbsCurve,
3113    probes: &[f64],
3114) -> Result<([f64; 3], [f64; 3]), String> {
3115    let (domain_u, domain_v) = surface_domains(surface)?;
3116    let finite = |p: Vec3| p.x.is_finite() && p.y.is_finite() && p.z.is_finite();
3117    // [tracking, deviation, excess] per curve; the excess (deviation minus
3118    // the shared foot's distance, per probe) starts at -inf, so a read with no
3119    // probe is not finite and admits nothing.
3120    let mut read = ([0.0_f64, 0.0, f64::NEG_INFINITY], [0.0_f64, 0.0, f64::NEG_INFINITY]);
3121    for &fraction in probes {
3122        let point = evaluate_edge(fraction)?;
3123        let (old_uv, new_uv) = (legacy.evaluate(fraction)?, candidate.evaluate(fraction)?);
3124        let (old_image, new_image) = (surface.evaluate_extended(old_uv.x, old_uv.y)?, surface.evaluate_extended(new_uv.x, new_uv.y)?);
3125        if !(finite(point) && finite(old_image) && finite(new_image)) {
3126            return Err(format!("common station read: non-finite point at fraction {fraction}"));
3127        }
3128        // Reading ONE curve against itself (`legacy` and `candidate` the same
3129        // object, as a trigger's read is): the candidate-seeded projection is
3130        // the reference-seeded one on identical inputs, so it is computed once
3131        // (same result, same tie order).
3132        let reference_foot = memo_seeded_foot(surface, point, old_uv.x, old_uv.y);
3133        let candidate_foot = if std::ptr::eq(legacy, candidate) {
3134            reference_foot
3135        } else {
3136            memo_seeded_foot(surface, point, new_uv.x, new_uv.y)
3137        };
3138        let foot = common_foot(
3139            memo_global_foot(surface, point),
3140            reference_foot,
3141            candidate_foot,
3142            domain_u,
3143            domain_v,
3144        )
3145        .ok_or_else(|| format!("common station read: no admitted foot at fraction {fraction}"))?;
3146        let values = [
3147            old_image.sub(foot.point).length(),
3148            old_image.sub(point).length(),
3149            new_image.sub(foot.point).length(),
3150            new_image.sub(point).length(),
3151        ];
3152        if values.iter().any(|v| !v.is_finite()) {
3153            return Err(format!("common station read: non-finite distance at fraction {fraction}"));
3154        }
3155        if !foot.distance.is_finite() {
3156            return Err(format!("common station read: non-finite foot distance at fraction {fraction}"));
3157        }
3158        read.0[0] = read.0[0].max(values[0]);
3159        read.0[1] = read.0[1].max(values[1]);
3160        read.0[2] = read.0[2].max(values[1] - foot.distance);
3161        read.1[0] = read.1[0].max(values[2]);
3162        read.1[1] = read.1[1].max(values[3]);
3163        read.1[2] = read.1[2].max(values[3] - foot.distance);
3164    }
3165    Ok(read)
3166}
3167
3168/// The interior probe fractions of the edge curve's own FIRST and LAST native
3169/// knot spans inside `[edge_start, edge_end]` (quarter points and 16 interior
3170/// points of each), mapped through the trim's range and sense to coedge
3171/// fractions in [0, 1].
3172fn edge_end_span_fractions(curve: &NurbsCurve, edge_start: f64, edge_end: f64, forward: bool) -> Vec<f64> {
3173    let (low, high) = (edge_start.min(edge_end), edge_start.max(edge_end));
3174    let mut knots: Vec<f64> = curve.knots.iter().copied().filter(|k| *k > low && *k < high).collect();
3175    knots.dedup();
3176    let spans = match (knots.first(), knots.last()) {
3177        (Some(&first), Some(&last)) => vec![(low, first), (last, high)],
3178        _ => vec![(low, high)],
3179    };
3180    let span = edge_end - edge_start;
3181    let mut out = Vec::new();
3182    for (a, b) in spans {
3183        if !(b > a) {
3184            continue;
3185        }
3186        for local in [0.25, 0.5, 0.75].into_iter().chain((1..=TRACKING_ACCEPTANCE_POINTS).map(|index| index as f64 / (TRACKING_ACCEPTANCE_POINTS + 1) as f64)) {
3187            let along = (a + (b - a) * local - edge_start) / span;
3188            let fraction = if forward { along } else { 1.0 - along };
3189            if fraction.is_finite() && (0.0..=1.0).contains(&fraction) {
3190                out.push(fraction);
3191            }
3192        }
3193    }
3194    out.sort_by(f64::total_cmp);
3195    out.dedup();
3196    out
3197}
3198
3199/// At most this many of the legacy pcurve's worst spans are seeded.
3200const WORST_SPANS: usize = 4;
3201/// Interior stations seeded in each of them.
3202const WORST_SPAN_SEEDS: usize = 7;
3203
3204/// The seed fractions of [`end_span_challenger`]'s worst-span source: the
3205/// legacy pcurve's own spans (between its distinct knots) whose same-parameter
3206/// deviation, read at the quarter points and 16 interior points, and at any of
3207/// `extra_probes` (the edge's own end-span interior points mapped to coedge
3208/// fractions) that fall inside the span, exceeds
3209/// `bar`, worst first, at most [`WORST_SPANS`] of them, each seeded with
3210/// [`WORST_SPAN_SEEDS`] evenly spaced interior fractions. Fails closed on any
3211/// non-finite reading.
3212fn legacy_worst_span_seeds(
3213    evaluate_edge: &dyn Fn(f64) -> Result<Vec3, String>,
3214    surface: &NurbsSurface,
3215    pcurve: &NurbsCurve,
3216    bar: f64,
3217    extra_probes: &[f64],
3218) -> Result<Vec<f64>, String> {
3219    let [q0, q1] = pcurve.domain()?;
3220    let mut knots: Vec<f64> = pcurve.knots.iter().copied().filter(|k| *k >= q0 && *k <= q1).collect();
3221    knots.dedup();
3222    let locals: Vec<f64> = [0.25, 0.5, 0.75]
3223        .into_iter()
3224        .chain((1..=TRACKING_ACCEPTANCE_POINTS).map(|index| index as f64 / (TRACKING_ACCEPTANCE_POINTS + 1) as f64))
3225        .collect();
3226    let mut over: Vec<(f64, f64, f64)> = Vec::new();
3227    for span in knots.windows(2).filter(|w| w[1] > w[0]) {
3228        let mut worst = 0.0_f64;
3229        let inside = extra_probes.iter().copied().filter(|f| *f > span[0] && *f < span[1]);
3230        for fraction in locals.iter().map(|local| span[0] + (span[1] - span[0]) * local).chain(inside) {
3231            let uv = pcurve.evaluate(fraction)?;
3232            let deviation = surface.evaluate_extended(uv.x, uv.y)?.sub(evaluate_edge(fraction)?).length();
3233            if !deviation.is_finite() {
3234                return Err(format!("worst-span read: non-finite deviation at fraction {fraction}"));
3235            }
3236            worst = worst.max(deviation);
3237        }
3238        if worst > bar {
3239            over.push((worst, span[0], span[1]));
3240        }
3241    }
3242    over.sort_by(|a, b| b.0.total_cmp(&a.0).then(a.1.total_cmp(&b.1)));
3243    over.truncate(WORST_SPANS);
3244    Ok(over
3245        .into_iter()
3246        .flat_map(|(_, lo, hi)| (1..=WORST_SPAN_SEEDS).map(move |index| lo + (hi - lo) * index as f64 / (WORST_SPAN_SEEDS + 1) as f64))
3247        .collect())
3248}
3249
3250/// Why the range lane's [`end_span_challenger`] runs.
3251#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3252enum ChallengerTrigger {
3253    /// The legacy residual misses `ask + standoff` (the original trigger).
3254    Deviation,
3255    /// The legacy residual is within `ask + standoff`, the edge stands off its
3256    /// carrier by more than the ask, and the legacy fit's COMMON tracking
3257    /// (`common_station_read` at the fixed probes) misses the ask.
3258    Tracking,
3259}
3260
3261/// The challenger's trigger. The original rule reads the same-parameter
3262/// DEVIATION against `ask + standoff`; over a standoff `g` a tangential slip
3263/// `d` adds only about d²/(2g) to it, so a slip up to sqrt(ask² + 2·ask·g)
3264/// never triggers (about 1.3e-5 at g = 9e-4, the fixture-25 inherited edges).
3265/// When the deviation rule does not fire and the edge stands off its carrier
3266/// by more than the ask (the same gate `refine_pcurve` takes its
3267/// standoff-tracking lane on), the legacy fit's common tracking is read
3268/// (`tracking`, called only then): over the ask, the challenger runs on
3269/// tracking. An unread tracking (None or non-finite) never triggers.
3270fn challenger_trigger(residual: f64, off_surface: f64, ask: f64, tracking: impl FnOnce() -> Option<f64>) -> Option<ChallengerTrigger> {
3271    if residual > ask + off_surface {
3272        return Some(ChallengerTrigger::Deviation);
3273    }
3274    if !(off_surface > ask) {
3275        return None;
3276    }
3277    match tracking() {
3278        Some(value) if value.is_finite() && value > ask => Some(ChallengerTrigger::Tracking),
3279        _ => None,
3280    }
3281}
3282
3283/// The END-SPAN CHALLENGER of the range lane (2026-10-05, the four original
3284/// fitter rows of `abc_00000011/12` edges 7 and 243). On e90c30c94 their worst
3285/// excess (4.58e-6 and 5.14e-6) sat in the installed pcurve's LAST span, at the
3286/// edge's start, where the edge curve's own first knot span is only 4.5e-6
3287/// (e7) and 1.2e-4 (e243) wide while the fitter's end span was 1.4e-4 wide at
3288/// its cap. It runs when [`challenger_trigger`] fires: the legacy fit misses
3289/// its bar (residual over the ask plus its standoff), or, on an edge standing
3290/// off its carrier by more than the ask, its common tracking misses the ask.
3291/// It refits with the edge's own interior knots that
3292/// fall inside the legacy pcurve's first or last span as additional stations
3293/// (not joins; corners stay the legacy ones), through the same fitter with the
3294/// unchanged ask, SPAN_FLOOR, cap and rounds. The candidate replaces the legacy
3295/// fit only when both, read at COMMON probes (both pcurves' own knot spans,
3296/// knots and endpoints, plus the edge's own knots and knot spans mapped to
3297/// fractions) against one SHARED foot per probe ([`common_station_read`]),
3298/// read finite, the candidate's tracking is strictly lower and its
3299/// same-parameter deviation no worse. Otherwise, or on any error or unreadable read, the legacy fit
3300/// stands exactly.
3301#[allow(clippy::too_many_arguments)]
3302fn end_span_challenger(
3303    surface: &NurbsSurface,
3304    curve: &NurbsCurve,
3305    evaluate_edge: &dyn Fn(f64) -> Result<Vec3, String>,
3306    edge_start: f64,
3307    edge_end: f64,
3308    forward: bool,
3309    breaks: &[f64],
3310    ask: f64,
3311    base_samples: usize,
3312    refinement_rounds: usize,
3313    parameter_cap: usize,
3314    legacy: PcurveFit,
3315) -> Result<PcurveFit, String> {
3316    // On the bar by deviation: nothing is read (the original zero-work
3317    // path). The TRACKING trigger (538dd700c: an off-carrier edge on its
3318    // deviation bar challenged on its common tracking) is withdrawn from this
3319    // merge (Claude master's ruling, 2026-10-05): bisected as the first commit
3320    // that moved step_import's a_trim_off_its_bar_is_accepted_and_named, and
3321    // the four original fitter rows do not need it (they enter on the
3322    // deviation trigger).
3323    if !(legacy.report.residual > ask + legacy.report.off_surface) {
3324        return Ok(legacy);
3325    }
3326    // The trigger read, the candidate's tracking verification and the final
3327    // read project the same edge points again: memoized, same answers.
3328    let _feet = FootMemoScope::open(surface);
3329    let Ok(end_knots) = native_end_knot_fractions(curve, edge_start, edge_end, forward, &legacy.curve) else { return Ok(legacy) };
3330    // The legacy fit's own WORST native spans (2026-10-05, root's boundary
3331    // audit of the four rows): the e90 witnesses read a 4.58e-6 / 5.14e-6
3332    // pointwise excess at q 0.99996 inside the closed native domain, in the
3333    // legacy pcurve's last span, where no edge knot falls. Each span between the
3334    // legacy pcurve's own distinct knots is read at its 19 probes; the spans
3335    // whose same-parameter deviation exceeds the ask plus the legacy standoff,
3336    // worst first and at most WORST_SPANS of them, each get WORST_SPAN_SEEDS
3337    // evenly spaced interior stations. Unreadable reads decline.
3338    // The edge's OWN first and last native knot spans, read at their quarter
3339    // points and 16 interior points, mapped through the trim's range and sense
3340    // to coedge fractions (e7's first edge span [0, 4.496e-6] of a
3341    // 0.018661-long trim maps reversed to q in [0.99976, 1], overlapping the
3342    // legacy pcurve's last span [0.99986, 1]).
3343    let edge_end_probes = edge_end_span_fractions(curve, edge_start, edge_end, forward);
3344    // The FIXED part of the common probe set, known before the candidate is
3345    // fitted: the legacy pcurve's own spans, endpoints and knots, and the
3346    // edge's own end-span probes, knot-span quarters and knots (every probe
3347    // that could have TRIGGERED the challenger among them). The candidate fit
3348    // verifies against these as well as its own spans, so it stops on the
3349    // reader that judges it.
3350    let Ok(mut fixed) = native_probe_fractions(&[&legacy.curve]) else { return Ok(legacy) };
3351    fixed.extend(edge_end_probes.iter().copied());
3352    let (low, high) = (edge_start.min(edge_end), edge_start.max(edge_end));
3353    let mut edge_knots: Vec<f64> = curve.knots.iter().copied().filter(|k| *k >= low && *k <= high).collect();
3354    edge_knots.push(low);
3355    edge_knots.push(high);
3356    edge_knots.sort_by(f64::total_cmp);
3357    edge_knots.dedup();
3358    let to_fraction = |t: f64| {
3359        let along = (t - edge_start) / (edge_end - edge_start);
3360        if forward { along } else { 1.0 - along }
3361    };
3362    for span in edge_knots.windows(2).filter(|w| w[1] > w[0]) {
3363        for local in [0.25, 0.5, 0.75] {
3364            fixed.push(to_fraction(span[0] + (span[1] - span[0]) * local));
3365        }
3366    }
3367    fixed.extend(edge_knots.iter().map(|&t| to_fraction(t)));
3368    fixed.extend(end_knots.iter().copied());
3369    fixed.extend(legacy.curve.knots.iter().copied());
3370    fixed.retain(|f| f.is_finite() && (0.0..=1.0).contains(f));
3371    fixed.sort_by(f64::total_cmp);
3372    fixed.dedup();
3373    let trigger = challenger_trigger(legacy.report.residual, legacy.report.off_surface, ask, || {
3374        common_station_read(surface, evaluate_edge, &legacy.curve, &legacy.curve, &fixed).ok().map(|((tracking, _), _)| tracking)
3375    });
3376    let Some(trigger) = trigger else { return Ok(legacy) };
3377    let Ok(worst_seeds) = legacy_worst_span_seeds(evaluate_edge, surface, &legacy.curve, ask + legacy.report.off_surface, &edge_end_probes) else { return Ok(legacy) };
3378    // The original guard holds for the deviation trigger only: a tracking
3379    // trigger needs no added station (the tracking mode and its verification
3380    // read the fixed probes).
3381    if trigger == ChallengerTrigger::Deviation && end_knots.is_empty() && worst_seeds.is_empty() {
3382        return Ok(legacy);
3383    }
3384    let mut stations: Vec<f64> = breaks.iter().copied().chain(end_knots.iter().copied()).chain(worst_seeds.iter().copied()).collect();
3385    stations.sort_by(f64::total_cmp);
3386    stations.dedup();
3387    // The fitter's cap is max(requested cap, initial station count): the added
3388    // stations must not raise it. Decline when the merged initial count
3389    // (base stations plus every break and end knot) could exceed the
3390    // requested cap.
3391    let initial = base_samples.max(1).checked_add(1).and_then(|count| count.checked_add(stations.len()));
3392    if initial.is_none_or(|count| count > parameter_cap) {
3393        return Ok(legacy);
3394    }
3395    let Ok(candidate) = fit_station_pcurve_mode(surface, evaluate_edge, &stations, breaks, ask, base_samples, refinement_rounds, parameter_cap, SPAN_FLOOR, true, Some(&legacy.curve), &fixed) else {
3396        return Ok(legacy);
3397    };
3398    if !(candidate.report.residual.is_finite() && candidate.report.off_surface.is_finite() && candidate.report.clamped_excursion.is_finite() && candidate.report.clamped_distance.is_finite()) {
3399        return Ok(legacy);
3400    }
3401    // Common probes: the fixed set plus the candidate's own knot spans,
3402    // endpoints and knots (the same set as both curves' native probes plus
3403    // the edge's, as before).
3404    let Ok(mut probes) = native_probe_fractions(&[&candidate.curve]) else { return Ok(legacy) };
3405    probes.extend(fixed.iter().copied());
3406    probes.extend(candidate.curve.knots.iter().copied());
3407    probes.retain(|f| f.is_finite() && (0.0..=1.0).contains(f));
3408    probes.sort_by(f64::total_cmp);
3409    probes.dedup();
3410    let readings = common_station_read_with_excess(surface, evaluate_edge, &legacy.curve, &candidate.curve, &probes);
3411    let accepted = matches!(&readings, Ok((old, new)) if floor_admits(*old, *new));
3412    if station_fit_tracing() {
3413        eprintln!(
3414            "STATION-FIT end-span challenger: trigger={trigger:?} end_knots={} worst_span_seeds={} edge_end_probes={} legacy={:?}/{:e} candidate={:?}/{:e} common={readings:?} decision={}",
3415            end_knots.len(), worst_seeds.len(), edge_end_probes.len(), legacy.report.exit, legacy.report.residual, candidate.report.exit, candidate.report.residual,
3416            if accepted { "candidate" } else { "legacy" }
3417        );
3418    }
3419    Ok(if accepted { candidate } else { legacy })
3420}
3421
3422
3423/// [`fit_pcurve_on_surface_range_dense`] for the callers that only need the
3424/// curve, accepted or refused on its bar ([`accept_fit`]).
3425#[allow(clippy::too_many_arguments)]
3426pub fn build_pcurve_on_surface_range_dense(
3427    surface: &NurbsSurface,
3428    curve: &NurbsCurve,
3429    edge_start: f64,
3430    edge_end: f64,
3431    forward: bool,
3432    tolerance: f64,
3433    base_samples: usize,
3434    refinement_rounds: usize,
3435    parameter_cap: usize,
3436) -> Result<NurbsCurve, String> {
3437    accept_fit(fit_pcurve_on_surface_range_dense(
3438        surface,
3439        curve,
3440        edge_start,
3441        edge_end,
3442        forward,
3443        tolerance,
3444        base_samples,
3445        refinement_rounds,
3446        parameter_cap,
3447    )?)
3448}
3449
3450/// The fractions of `[edge_start, edge_end]`, walked in the coedge's sense, at
3451/// which `curve` is not C2: interior knots of multiplicity at least its
3452/// degree. A rational-quadratic arc past a quarter turn is two segments joined
3453/// at a double knot, and an interpolant through uniform samples across that
3454/// joint cannot represent the second-derivative jump: on the 2026-09-18 import
3455/// census 1511 of the 2979 arc trims blamed on the fitter had their worst
3456/// miss at fraction 0.49–0.51, the mid double knot, exactly as the fillet's
3457/// corner patch had measured (`blend/track_fit.rs::curve_breaks`, which this
3458/// mirrors for a range).
3459pub(crate) fn range_breaks(
3460    curve: &NurbsCurve,
3461    edge_start: f64,
3462    edge_end: f64,
3463    forward: bool,
3464) -> Vec<f64> {
3465    let mut fractions = Vec::new();
3466    let span = edge_end - edge_start;
3467    if !(span.abs() > 0.0) {
3468        return fractions;
3469    }
3470    let (low, high) = (edge_start.min(edge_end), edge_start.max(edge_end));
3471    let mut index = 0;
3472    while index < curve.knots.len() {
3473        let value = curve.knots[index];
3474        let run = curve.knots[index..]
3475            .iter()
3476            .take_while(|knot| **knot == value)
3477            .count();
3478        if value > low && value < high && run >= curve.degree.max(1) {
3479            let along = (value - edge_start) / span;
3480            fractions.push(if forward { along } else { 1.0 - along });
3481        }
3482        index += run;
3483    }
3484    fractions.sort_by(f64::total_cmp);
3485    fractions
3486}
3487
3488/// The body of [`fit_pcurve_on_surface_range_dense`], parameterized by the
3489/// 3D station the pcurve must pass through at each coedge fraction instead of
3490/// by an edge curve and a range.
3491///
3492/// The station supplier is the whole difference between deriving a pcurve and
3493/// reading one. `fit_pcurve_on_surface_range_dense` supplies points off the
3494/// edge's own 3D curve, so the answer is "the nearest point of the carrier",
3495/// which is ambiguous exactly where a trim is interesting — a seam branch, a
3496/// near-tangential approach, a pole. The STEP importer's supplied-pcurve lane
3497/// supplies points off the VENDOR's stated trim instead, and the ambiguity is
3498/// gone because the vendor resolved it.
3499///
3500/// `stations(fraction)` must be continuous in `fraction` over `[0, 1]` and land
3501/// on (or very near) `surface`; `breaks` are the fractions at which it is not
3502/// C2 ([`range_breaks`]), each of which becomes a station so no kink sits
3503/// between two nodes. Everything else — inversion, branch repair, refinement
3504/// and the measurement — is shared with the derived lane by construction.
3505///
3506/// The SURFACE's knot-line crossings are deliberately not stations here,
3507/// although `blend/track_fit.rs` makes them so. Measured 2026-09-26 over the
3508/// 57-document import corpus: with each crossing bisected on the fraction and
3509/// projected seeded from the left station, 34 bodies refused (19 with a foot
3510/// that misses its global distance rejected) against 15 without the pass —
3511/// every extra refusal a fit stalled around a crossing station, on
3512/// `AssemblyExample-Assembly` and `abc_00000014` among others. The raised
3513/// pass resolves the O(h²) tail across a crossing on its own.
3514///
3515/// # What the fit is measured against, and when it stops
3516///
3517/// The stations' own standoff from the carrier is read FIRST, from the base
3518/// inversions, and the refinement target is the ask plus that standoff
3519/// ([`PcurveFitReport::on_bar`]): a station standing `g` off the surface
3520/// cannot be imaged closer than `g`, so chasing it to the ask alone spends the
3521/// whole budget for nothing (the 2026-09-18 census: 2052 imported pcurves at
3522/// the 513 cap, 1958 of them on a curve that is not on its carrier).
3523///
3524/// Every probe and the final measurement read the carrier through
3525/// `evaluate_extended`: a pcurve riding a periodic seam legitimately carries
3526/// parameters past the domain, and the clamped `evaluate` this loop used until
3527/// 2026-09-26 read every such station as a gross miss — an insert per round
3528/// until the cap, on a trim that was right.
3529///
3530/// The RETURNED curve is measured out of sample — at the quarter points of
3531/// every span between its nodes, where an interpolant is exact at the nodes
3532/// and extremal between — unless its last round probed every span and found
3533/// nothing to insert, in which case that round's maximum already is that
3534/// measurement. A fit that binds at `parameter_cap` or spends its rounds with
3535/// the bar still unmet grows ONCE to [`PCURVE_RAISED_SAMPLES`]
3536/// (deterministic). The report says which exit it took and what it reached;
3537/// the `build_*` wrappers refuse over the bar, this function never does.
3538#[allow(clippy::too_many_arguments)]
3539pub fn fit_pcurve_on_surface_stations(
3540    surface: &NurbsSurface,
3541    stations: &dyn Fn(f64) -> Result<Vec3, String>,
3542    breaks: &[f64],
3543    tolerance: f64,
3544    base_samples: usize,
3545    refinement_rounds: usize,
3546    parameter_cap: usize,
3547) -> Result<PcurveFit, String> {
3548    fit_station_pcurve(
3549        surface, stations, breaks, &[], tolerance.max(PCURVE_REFINEMENT_TOLERANCE),
3550        base_samples, refinement_rounds, parameter_cap, SPAN_FLOOR,
3551    )
3552}
3553
3554/// Precision construction for stations on recognized analytic carriers. Unlike
3555/// general projection, their inverse maps reach floating point accuracy. This
3556/// is an explicit construction contract, not a change to general fit policy.
3557pub(crate) fn analytic_station_pcurve(
3558    surface: &NurbsSurface,
3559    stations: &dyn Fn(f64) -> Result<Vec3, String>,
3560    tolerance: f64,
3561) -> Result<NurbsCurve, String> {
3562    if surface.analytic().is_none() {
3563        return Err("analytic pcurve requires an analytic carrier".into());
3564    }
3565    let mut breaks = Vec::new();
3566    for _ in 0..4 {
3567        let fit = fit_station_pcurve(surface, stations, &breaks, &[], tolerance, 64, 64, 8192, 1e-10)?;
3568        if fit.report.residual > tolerance || fit.report.off_surface > tolerance {
3569            return Err(format!(
3570                "analytic pcurve construction missed its contract: {:?}",
3571                fit.report
3572            ));
3573        }
3574        let mut failed = Vec::new();
3575        // Independent Gauss stations in every returned knot span, rather than
3576        // re-reading the interpolation nodes or the fitter's quarter stations.
3577        for pair in fit.curve.knots.windows(2) {
3578            if pair[1] <= pair[0] {
3579                continue;
3580            }
3581            for local in [
3582                0.06943184420297371,
3583                0.33000947820757187,
3584                0.6699905217924281,
3585                0.9305681557970262,
3586            ] {
3587                let t = pair[0] + (pair[1] - pair[0]) * local;
3588                let uv = fit.curve.evaluate(t)?;
3589                if surface
3590                    .evaluate_extended(uv.x, uv.y)?
3591                    .sub(stations(t)?)
3592                    .length()
3593                    > tolerance
3594                {
3595                    failed.push(t);
3596                }
3597            }
3598        }
3599        if failed.is_empty() {
3600            return Ok(fit.curve);
3601        }
3602        if breaks.len() + failed.len() > 8192 {
3603            break;
3604        }
3605        breaks.extend(failed);
3606        breaks.sort_by(f64::total_cmp);
3607        breaks.dedup();
3608    }
3609    Err("analytic pcurve failed independent knot-span witnesses".into())
3610}
3611
3612#[allow(clippy::too_many_arguments)]
3613fn fit_station_pcurve(
3614    surface: &NurbsSurface,
3615    stations: &dyn Fn(f64) -> Result<Vec3, String>,
3616    breaks: &[f64],
3617    corners: &[f64],
3618    tolerance: f64,
3619    base_samples: usize,
3620    refinement_rounds: usize,
3621    parameter_cap: usize,
3622    span_floor: f64,
3623) -> Result<PcurveFit, String> {
3624    fit_station_pcurve_mode(surface, stations, breaks, corners, tolerance, base_samples, refinement_rounds, parameter_cap, span_floor, false, None, &[])
3625}
3626
3627/// [`fit_station_pcurve`] with an optional TRACKING mode, taken only by the
3628/// range lane's [`end_span_challenger`]; every other caller keeps the legacy
3629/// mode byte for byte. The legacy fitter probes, ranks and stops on the
3630/// image's same-parameter DEVIATION from the edge point. On an edge standing
3631/// off its carrier that deviation never falls under the ask, so every probe is
3632/// a candidate, the cap goes to the probes with the largest STANDOFF, and a
3633/// tangential slip of `d` adds only about d²/(2g) to a deviation over a
3634/// standoff `g`: the four original rows' challenger met its standoff (4.670e-6)
3635/// and kept a common tracking of 1.434e-6 (root's e24 run, 2026-10-05). In
3636/// tracking mode each probe reads its TRACKING, the image against the edge
3637/// point's foot (the nearer admitted one of the global projection and the
3638/// projection seeded at the image's uv: finite, inside the native domain, as
3639/// [`common_station_read`] admits). A probe is a candidate only over the ask,
3640/// the cap goes to the worst TRACKING first, and the one raise is taken when
3641/// the last round's tracking still misses the ask. The reported residual
3642/// stays the same-parameter deviation (standoff included). A probe with no
3643/// admitted foot is an error, which the challenger turns into the exact legacy
3644/// fit.
3645#[allow(clippy::too_many_arguments)]
3646fn fit_station_pcurve_mode(
3647    surface: &NurbsSurface,
3648    stations: &dyn Fn(f64) -> Result<Vec3, String>,
3649    breaks: &[f64],
3650    corners: &[f64],
3651    tolerance: f64,
3652    base_samples: usize,
3653    refinement_rounds: usize,
3654    parameter_cap: usize,
3655    span_floor: f64,
3656    track_projection: bool,
3657    reference: Option<&NurbsCurve>,
3658    verify: &[f64],
3659) -> Result<PcurveFit, String> {
3660    // Read only in tracking mode: the legacy mode makes no extra call.
3661    let domains = if track_projection { Some(surface_domains(surface)?) } else { None };
3662    // The tracking reading at one fraction, by the SAME foot rule as
3663    // [`common_station_read`], the reader the challenger accepts on: the
3664    // nearest admitted foot among the global projection and the projections
3665    // seeded at this image's uv and at the reference (legacy) pcurve's uv at
3666    // the same fraction. Returns the tracking and that foot (uv, distance),
3667    // which is where a tracking insert is placed.
3668    let tracking_of = |represented: Vec3, edge_point: Vec3, uv: Vec3, fraction: f64| -> Result<(f64, [f64; 2], f64), String> {
3669        let (domain_u, domain_v) = domains.ok_or_else(|| "station tracking: legacy mode".to_string())?;
3670        let finite = |p: Vec3| p.x.is_finite() && p.y.is_finite() && p.z.is_finite();
3671        let reference_seed = match reference {
3672            Some(curve) => curve.evaluate(fraction).ok().and_then(|seed| memo_seeded_foot(surface, edge_point, seed.x, seed.y)),
3673            None => None,
3674        };
3675        // The common reader's order (global, reference, candidate), so an
3676        // equal-distance tie takes the same foot here as there.
3677        let foot = common_foot(
3678            memo_global_foot(surface, edge_point),
3679            reference_seed,
3680            memo_seeded_foot(surface, edge_point, uv.x, uv.y),
3681            domain_u,
3682            domain_v,
3683        )
3684        .ok_or_else(|| "station tracking: no admitted foot".to_string())?;
3685        let tracking = represented.sub(foot.point).length();
3686        if !(finite(represented) && tracking.is_finite()) {
3687            return Err("station tracking: non-finite reading".into());
3688        }
3689        Ok((tracking, [foot.u, foot.v], foot.distance))
3690    };
3691    // The last round's tracking missed the ask (tracking mode only).
3692    let mut tracking_unmet = false;
3693    let evaluate_edge = stations;
3694    let base_samples = base_samples.max(1);
3695    // The general caller floors its ask: its projector places a foot
3696    // to about `LINEAR_TOLERANCE` (1e-7), so a caller asking for 1e-9 asks for
3697    // more than any station can deliver. Chased to such an ask the fit spends
3698    // its cap and reads its own noise — the direct-edit heals asked 1e-9 on
3699    // stations 9.9e-8 off their carrier and were refused by 8.5e-9
3700    // (2026-09-26). The floor is the ask's floor; the report says what was
3701    // reached against it.
3702
3703    let mut parameters = (0..=base_samples)
3704        .map(|index| index as f64 / base_samples as f64)
3705        .collect::<Vec<_>>();
3706    // A break within the span floor of a station IS that station: two nodes
3707    // closer than that make the interpolant swing between them, and over a
3708    // stretch that short the kink moves the fit by nothing a bar can read.
3709    // `abc_00000011` face #549's curve carries a triple knot 4e-7 before its
3710    // end; as a station it put the cubic 1.594e-2 off between it and the last
3711    // one (measured 2026-09-26), where the file's curve sits 1e-7 off.
3712    // A break that is a CORNER of the curve (`corners`, a subset of
3713    // `breaks`: the range lane passes its curve's knots of multiplicity >=
3714    // degree as both) is a C0 JOIN of the interpolant
3715    // (`build_interpolant_joined`): one cubic through the corner overshoots
3716    // on both sides whatever is inserted. A break that is only a station
3717    // (an analytic witness, a caller's own marker) joins nothing.
3718    let mut joins = Vec::with_capacity(corners.len());
3719    for &fraction in breaks {
3720        if !(fraction > 0.0 && fraction < 1.0) {
3721            continue;
3722        }
3723        let corner = corners.contains(&fraction);
3724        let at = parameters.partition_point(|parameter| *parameter < fraction);
3725        let near_left = at > 0 && fraction - parameters[at - 1] <= span_floor;
3726        let near_right = at < parameters.len() && parameters[at] - fraction <= span_floor;
3727        if near_left || near_right {
3728            // The break IS that station (a corner at a base station, e.g.
3729            // the midpoint of a two-piece curve at 32/64): no insert, but the
3730            // station is still the join.
3731            if corner {
3732                joins.push(if near_right { parameters[at] } else { parameters[at - 1] });
3733            }
3734            continue;
3735        }
3736        parameters.insert(at, fraction);
3737        if corner {
3738            joins.push(fraction);
3739        }
3740    }
3741    // The 3D edge point behind each raw inversion sample, kept parallel so the
3742    // continuity repair can re-seed a jumped station from its own footpoint.
3743    let mut edge_points = parameters
3744        .iter()
3745        .map(|fraction| evaluate_edge(*fraction))
3746        .collect::<Result<Vec<_>, _>>()?;
3747    // The stations' standoff from the carrier: the part of every residual no
3748    // pcurve can remove, known before a single probe is spent.
3749    let mut off_surface = 0.0_f64;
3750    let mut raw = Vec::with_capacity(edge_points.len());
3751    let mut gaps = Vec::with_capacity(edge_points.len());
3752    for point in &edge_points {
3753        let (parameter, gap) = invert_checked(surface, *point)?;
3754        off_surface = off_surface.max(gap);
3755        raw.push(parameter);
3756        gaps.push(gap);
3757    }
3758    repair_branch_jumps(surface, &edge_points, &mut raw, tolerance)?;
3759    let (mut pcurve, mut excursion, mut distance) =
3760        build_interpolant_joined(surface, &raw, &parameters, &joins)?;
3761
3762    let mut cap = parameter_cap.max(parameters.len());
3763    let mut rounds = refinement_rounds;
3764    let mut raised = false;
3765    loop {
3766        let mut exit = PcurveFitExit::RoundBudget;
3767        let mut converged_max = None;
3768        // This pass's last round probed every span (none narrow, none
3769        // truncated) and every probe tracked within the ask (tracking mode).
3770        let mut tracking_met = false;
3771        for _ in 0..rounds {
3772            if parameters.len() >= cap {
3773                exit = PcurveFitExit::SampleCeiling;
3774                break;
3775            }
3776            // The target is the ASK, bare: a station standing off the carrier
3777            // is chased to the foot it projects to, as the fitter has always
3778            // done. A target of ask + standoff (one landing, 2026-09-26) let
3779            // such a fit stop at its base stations with the interpolant
3780            // wandering between them, folded a molex wall's mesh and put a
3781            // trim of abc_00000023 2.2e-5 off its own parameter; the bar
3782            // below still reads what it reached.
3783            let target = tolerance;
3784            let mut candidates = Vec::new();
3785            let mut round_max = 0.0_f64;
3786            let mut truncated = false;
3787            let mut skipped_narrow = false;
3788            let worst_first = worst_first();
3789            'spans: for index in 0..parameters.len() - 1 {
3790                // The loop's own resolution floor: a span narrower than this
3791                // is not subdivided. Without it the
3792                // raised pass inserted into a vanishing span at a trim's end
3793                // until the cap — `abc_00000011` face #549's last stations sat
3794                // 4e-7 apart with their feet clamped at the patch edge, and the
3795                // cubic through them swung 1.594e-2 off between them (measured
3796                // 2026-09-26). A miss that survives only inside such a span is
3797                // reported as [`PcurveFitExit::SpanFloor`].
3798                if parameters[index + 1] - parameters[index] < span_floor {
3799                    skipped_narrow = true;
3800                    continue;
3801                }
3802                for local in [0.25, 0.5, 0.75] {
3803                    if !worst_first && parameters.len() + candidates.len() >= cap {
3804                        truncated = true;
3805                        break 'spans;
3806                    }
3807                    let fraction =
3808                        parameters[index] + (parameters[index + 1] - parameters[index]) * local;
3809                    let uv = pcurve.evaluate(fraction)?;
3810                    let represented = surface.evaluate_extended(uv.x, uv.y)?;
3811                    let edge_point = evaluate_edge(fraction)?;
3812                    let deviation = represented.sub(edge_point).length();
3813                    // The probe's reading: its deviation (legacy), or its
3814                    // tracking against the admitted foot (tracking mode).
3815                    let (reading, foot) = if track_projection {
3816                        let (tracking, foot_uv, foot_gap) = tracking_of(represented, edge_point, uv, fraction)?;
3817                        (tracking, Some((foot_uv, foot_gap)))
3818                    } else {
3819                        (deviation, None)
3820                    };
3821                    round_max = round_max.max(reading);
3822                    if reading <= target {
3823                        continue;
3824                    }
3825                    candidates.push((index, fraction, edge_point, uv, reading, foot));
3826                }
3827            }
3828            // Tracking mode's VERIFICATION, before it may stop: a round whose
3829            // quarter probes all track within the ask is read again at the
3830            // probes the challenger's acceptance reads, the current pcurve's
3831            // own knot spans (endpoints, quarters and 16 interior points: the
3832            // interpolant's knots are averages of three stations, not the
3833            // stations) and the caller's fixed fractions (the legacy pcurve's
3834            // spans and the edge's own). A probe over the ask becomes a
3835            // candidate at its own fraction, placed at its own foot. One
3836            // within the span floor of a station cannot be inserted: it is
3837            // counted, and the fit may not report its tracking as met. On e24
3838            // the four rows stopped on their quarter probes and read 1.144e-7 /
3839            // 1.590e-7 at the common probes (a4c84871 runtime, 2026-10-05).
3840            let mut verify_blocked = false;
3841            if track_projection && candidates.is_empty() && !truncated && !skipped_narrow {
3842                for fraction in verification_fractions(&pcurve, verify)? {
3843                    let index = parameters.partition_point(|parameter| *parameter <= fraction).saturating_sub(1).min(parameters.len() - 2);
3844                    let uv = pcurve.evaluate(fraction)?;
3845                    let represented = surface.evaluate_extended(uv.x, uv.y)?;
3846                    let edge_point = evaluate_edge(fraction)?;
3847                    let (tracking, foot_uv, foot_gap) = tracking_of(represented, edge_point, uv, fraction)?;
3848                    round_max = round_max.max(tracking);
3849                    if tracking <= target {
3850                        continue;
3851                    }
3852                    if fraction - parameters[index] <= span_floor || parameters[index + 1] - fraction <= span_floor {
3853                        verify_blocked = true;
3854                        continue;
3855                    }
3856                    // Two over-ask probes closer than the span floor in one
3857                    // span: keep the worse, so no near-duplicate stations.
3858                    if let Some(last) = candidates.last_mut() {
3859                        if last.0 == index && fraction - last.1 <= span_floor {
3860                            if tracking > last.4 {
3861                                *last = (index, fraction, edge_point, uv, tracking, Some((foot_uv, foot_gap)));
3862                            }
3863                            continue;
3864                        }
3865                    }
3866                    candidates.push((index, fraction, edge_point, uv, tracking, Some((foot_uv, foot_gap))));
3867                }
3868            }
3869            tracking_unmet = track_projection && round_max > target;
3870            // A round with more candidates than the cap has room for spends
3871            // that room on its WORST probes, kept in curve order, rather than
3872            // on the first spans in order: truncating in span order left the
3873            // late spans of an off-carrier ring at their base spacing and its
3874            // image 1.523e-6 off its feet; worst first reaches 5.84e-8 on the
3875            // same 513 samples. An even stride along the curve reached 2.87e-7
3876            // there but diluted the inserts a local miss needs and lost fits
3877            // over the corpus (a 1.3e-5 trim of `abc_00000011` fell back to its
3878            // 4.4e-4 size-ask fit), measured 2026-09-27.
3879            let room = cap.saturating_sub(parameters.len());
3880            if candidates.len() > room {
3881                truncated = true;
3882                let mut order: Vec<usize> = (0..candidates.len()).collect();
3883                order.sort_by(|&a, &b| candidates[b].4.total_cmp(&candidates[a].4).then(a.cmp(&b)));
3884                order.truncate(room);
3885                order.sort_unstable();
3886                candidates = order.into_iter().map(|index| candidates[index]).collect();
3887            }
3888            let mut inserts = Vec::with_capacity(candidates.len());
3889            for (index, fraction, edge_point, uv, _, foot) in candidates {
3890                // A tracking candidate is placed at the very foot it was read
3891                // against, so the node's image IS that foot; the legacy
3892                // inversion is unchanged.
3893                let (parameter, gap) = match foot {
3894                    Some(placed) => placed,
3895                    None => invert_near(surface, edge_point, [uv.x, uv.y], gaps[index].max(gaps[index + 1]))?,
3896                };
3897                inserts.push((index + 1, fraction, edge_point, parameter, gap));
3898            }
3899            if station_fit_tracing() {
3900                eprintln!(
3901                    "STATION-FIT round: samples={} target={target:.3e} round_max={round_max:.3e} inserts={} truncated={truncated}{}",
3902                    parameters.len(),
3903                    inserts.len(),
3904                    // Tracking mode's round_max is a TRACKING reading.
3905                    if track_projection { " mode=tracking" } else { "" }
3906                );
3907            }
3908            if inserts.is_empty() {
3909                exit = if truncated {
3910                    PcurveFitExit::SampleCeiling
3911                } else if skipped_narrow {
3912                    // Every probed span is within the target; the narrow ones
3913                    // were not probed, and the sweep below measures them.
3914                    PcurveFitExit::SpanFloor
3915                } else if track_projection {
3916                    // Every probe TRACKS within the ask, but round_max is a
3917                    // tracking reading, not the deviation the report carries.
3918                    // The exit is Stalled (no probe can be improved; the
3919                    // residual measured below is the edge's own standoff),
3920                    // and it becomes Converged below only if that measured
3921                    // deviation itself meets the floor. A verification probe
3922                    // over the ask that could not be inserted leaves the
3923                    // tracking UNMET.
3924                    tracking_met = !verify_blocked;
3925                    PcurveFitExit::Stalled
3926                } else {
3927                    converged_max = Some(round_max);
3928                    PcurveFitExit::Converged
3929                };
3930                break;
3931            }
3932            for (index, fraction, edge_point, parameter, gap) in inserts.into_iter().rev() {
3933                parameters.insert(index, fraction);
3934                edge_points.insert(index, edge_point);
3935                raw.insert(index, parameter);
3936                gaps.insert(index, gap);
3937                off_surface = off_surface.max(gap);
3938            }
3939            // Inserts are independent global inversions too — re-run the repair
3940            // so a fold-flip introduced mid-refinement cannot poison the next
3941            // round's deviation interpolant.
3942            repair_branch_jumps(surface, &edge_points, &mut raw, tolerance)?;
3943            let rebuilt = build_interpolant_joined(surface, &raw, &parameters, &joins)?;
3944            pcurve = rebuilt.0;
3945            excursion = rebuilt.1;
3946            distance = rebuilt.2;
3947            if truncated {
3948                exit = PcurveFitExit::SampleCeiling;
3949                break;
3950            }
3951        }
3952        let residual = match converged_max {
3953            Some(measured) => measured,
3954            None => {
3955                station_residual(surface, evaluate_edge, &pcurve, &parameters, tolerance, &mut off_surface)?
3956            }
3957        };
3958        if station_fit_tracing() {
3959            eprintln!(
3960                "STATION-FIT pass raised={raised} exit={exit:?} samples={} residual={residual:.3e} off_surface={off_surface:.3e}",
3961                parameters.len()
3962            );
3963            if residual > tolerance + off_surface && (exit == PcurveFitExit::Converged || raised) {
3964                // Where the miss sits, and the uv track around it: the trace a
3965                // refusal needs to be attributed to a fold, a seam or the file.
3966                let (mut worst, mut at) = (0.0f64, 0usize);
3967                for (index, span) in parameters.windows(2).enumerate() {
3968                    let fraction = 0.5 * (span[0] + span[1]);
3969                    let uv = pcurve.evaluate(fraction)?;
3970                    let deviation = surface.evaluate_extended(uv.x, uv.y)?.sub(evaluate_edge(fraction)?).length();
3971                    if deviation > worst {
3972                        worst = deviation;
3973                        at = index;
3974                    }
3975                }
3976                let ([u0, u1], [v0, v1]) = surface_domains(surface)?;
3977                let (closed_u, closed_v) = surface_closedness(surface)?;
3978                eprintln!(
3979                    "STATION-FIT OFF BAR: worst {worst:.3e} between stations {at} and {}; surface degree {}x{} net {}x{} domain u[{u0},{u1}] v[{v0},{v1}] closed ({closed_u},{closed_v}) analytic {:?}",
3980                    at + 1,
3981                    surface.degree_u,
3982                    surface.degree_v,
3983                    surface.control_points.len(),
3984                    surface.control_points[0].len(),
3985                    surface.analytic().map(|_| "yes").unwrap_or("no")
3986                );
3987                {
3988                    let fraction = 0.5 * (parameters[at] + parameters[at + 1]);
3989                    let uv = pcurve.evaluate(fraction)?;
3990                    let image = surface.evaluate_extended(uv.x, uv.y)?;
3991                    let station = evaluate_edge(fraction)?;
3992                    let foot = project_point_to_surface(surface, station)?;
3993                    let seeded = project_point_to_surface_seeded(surface, station, raw[at][0], raw[at][1])?;
3994                    eprintln!(
3995                        "    at the worst midpoint: deviation {:.4e}, station gap {:.4e} (seeded {:.4e}), image-to-foot {:.4e} (to seeded foot {:.4e}), foot uv ({:.7}, {:.7}) seeded ({:.7}, {:.7}) image uv ({:.7}, {:.7})",
3996                        image.sub(station).length(), foot.distance, seeded.distance, image.sub(foot.point).length(), image.sub(seeded.point).length(), foot.u, foot.v, seeded.u, seeded.v, uv.x, uv.y
3997                    );
3998                }
3999                let lo = at.saturating_sub(3);
4000                let hi = (at + 4).min(parameters.len() - 1);
4001                for index in lo..=hi {
4002                    eprintln!(
4003                        "    station {index}: fraction {:.6} uv ({:.6}, {:.6}) point ({:.4}, {:.4}, {:.4})",
4004                        parameters[index], raw[index][0], raw[index][1], edge_points[index].x, edge_points[index].y, edge_points[index].z
4005                    );
4006                }
4007            }
4008        }
4009        // Legacy only: a SpanFloor exit whose measured DEVIATION is on the
4010        // bar is promoted. In tracking mode the deviation sits at the standoff
4011        // whatever the unprobed narrow spans' TRACKING is, so SpanFloor stays
4012        // SpanFloor (unread); a tracking-mode fit is Converged only when every
4013        // span was probed within the ask AND the measured deviation meets the
4014        // floor (the exit's documented meaning, never the standoff bar).
4015        if !track_projection && exit == PcurveFitExit::SpanFloor && residual <= tolerance + off_surface {
4016            exit = PcurveFitExit::Converged;
4017        }
4018        if tracking_met && residual <= tolerance {
4019            exit = PcurveFitExit::Converged;
4020        }
4021        if exit != PcurveFitExit::Converged
4022            && !raised
4023            && (residual > tolerance + off_surface || tracking_unmet)
4024            && cap < PCURVE_RAISED_SAMPLES
4025        {
4026            raised = true;
4027            cap = PCURVE_RAISED_SAMPLES;
4028            // The raised pass is bounded by SAMPLES, not rounds: a kink
4029            // converges O(h²), a round per halving, and the three rounds of
4030            // the first pass are what left the 2026-09-18 census's fits over
4031            // their ask with budget to spare (RoundBudget at 158–400 of 2000
4032            // samples, measured 2026-09-26). Forty rounds cover every halving
4033            // the cap admits; a fit that is not converging stalls out first.
4034            rounds = RAISED_ROUNDS;
4035            continue;
4036        }
4037        return Ok(PcurveFit {
4038            curve: pcurve,
4039            report: PcurveFitReport {
4040                residual,
4041                floor: tolerance,
4042                samples: parameters.len(),
4043                exit,
4044                off_surface,
4045                raised,
4046                clamped_excursion: excursion,
4047                clamped_distance: distance,
4048            },
4049        });
4050    }
4051}
4052
4053/// [`fit_pcurve_on_surface_stations`] for the callers that only need the
4054/// curve, accepted or refused on its bar ([`accept_fit`]).
4055pub fn build_pcurve_on_surface_stations(
4056    surface: &NurbsSurface,
4057    stations: &dyn Fn(f64) -> Result<Vec3, String>,
4058    breaks: &[f64],
4059    tolerance: f64,
4060    base_samples: usize,
4061    refinement_rounds: usize,
4062    parameter_cap: usize,
4063) -> Result<NurbsCurve, String> {
4064    accept_fit(fit_pcurve_on_surface_stations(
4065        surface,
4066        stations,
4067        breaks,
4068        tolerance,
4069        base_samples,
4070        refinement_rounds,
4071        parameter_cap,
4072    )?)
4073}
4074
4075/// The largest 3D distance between `pcurve`'s image and its stations at the
4076/// quarter points of every span of `parameters` — out of sample by
4077/// construction, since the interpolant is exact at its nodes. Unclamped
4078/// evaluations; a station read over the running bar is inverted so that
4079/// `off_surface` covers the standoff AT the stations the residual is taken at,
4080/// not only at the nodes (a curve lifted off its plane by a bump stands
4081/// further off between two nodes than at either).
4082fn station_residual(
4083    surface: &NurbsSurface,
4084    stations: &dyn Fn(f64) -> Result<Vec3, String>,
4085    pcurve: &NurbsCurve,
4086    parameters: &[f64],
4087    tolerance: f64,
4088    off_surface: &mut f64,
4089) -> Result<f64, String> {
4090    let mut worst = 0.0_f64;
4091    let mut read = |fraction: f64| -> Result<(), String> {
4092        let uv = pcurve.evaluate(fraction)?;
4093        let represented = surface.evaluate_extended(uv.x, uv.y)?;
4094        let station = stations(fraction)?;
4095        let deviation = represented.sub(station).length();
4096        worst = worst.max(deviation);
4097        if deviation > tolerance + *off_surface {
4098            *off_surface = off_surface.max(invert_checked(surface, station)?.1);
4099        }
4100        Ok(())
4101    };
4102    for span in parameters.windows(2) {
4103        for local in [0.25, 0.5, 0.75] {
4104            read(span[0] + (span[1] - span[0]) * local)?;
4105        }
4106    }
4107    Ok(worst)
4108}
4109