pcurve: the lift check samples its interval's end exactly

The closed-form pcurve's lift check sampled t0 + (t1 − t0)·k/n, which at k = n can round
one step past t1 (1.2985843833752289 for an end of 1.2985843833752286), where the pcurve
on [t0, t1] has no point: the closed form was refused, and on a plane, which has no
parameter box for a kernel's pcurves, the face with it ("a face on an unbounded surface
without closed-form pcurves", Poppy Humanoid's Combine1 and others). The end is now t1.

Test: Poppy's interval on a spline on a plane; without the fix, "no exact pcurve of a
B-spline on a plane".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUXeKMoxpM7Vuv8Rb6E3K2
This commit is contained in:
jyviko
2026-10-27 17:26:07 -04:00
committed by Irakli Kourtis
parent 365d7545c0
commit e2c0c0a206
2 changed files with 15 additions and 2 deletions
+2 -1
View File
@@ -495,7 +495,8 @@ impl On {
let knots = match pc {
Curve2::Spline { knots, .. } | Curve2::RationalSpline { knots, .. } => knots,
};
let even = (0..=CHECKS).map(|k| t0 + (t1 - t0) * k as f64 / CHECKS as f64);
// The ends exactly: `t0 + (t1 − t0)·1` may round past `t1`, where the pcurve has no point.
let even = (0..=CHECKS).map(|k| if k == CHECKS { t1 } else { t0 + (t1 - t0) * k as f64 / CHECKS as f64 });
let spans = knots.windows(2).filter_map(|k| Some((*k.first()?, *k.get(1)?))).filter(|(a, b)| a < b).take(1 << 12).map(|(a, b)| 0.5 * (a + b));
even.chain(spans).all(|t| {
let lifted = pc.eval(t).and_then(|q| self.surface.point(q));
+13 -1
View File
@@ -22,7 +22,7 @@ fn lift_error(surface: &Surface, curve: &Curve, interval: [f64; 2], pc: &Curve2)
let knots = match pc {
Curve2::Spline { knots, .. } | Curve2::RationalSpline { knots, .. } => knots,
};
let mut ts: Vec<f64> = (0..=64).map(|k| t0 + (t1 - t0) * k as f64 / 64.).collect();
let mut ts: Vec<f64> = (0..=64).map(|k| if k == 64 { t1 } else { t0 + (t1 - t0) * k as f64 / 64. }).collect();
ts.extend(knots.windows(2).filter(|k| k[0] < k[1]).map(|k| 0.5 * (k[0] + k[1])));
ts.iter().map(|&t| s.point(pc.eval(t).unwrap()).unwrap().dist(c.point(t).unwrap())).fold(0., f64::max)
}
@@ -33,6 +33,18 @@ fn segment_points(pc: &Curve2) -> [[f64; 2]; 2] {
}
}
#[test]
fn a_spline_on_a_plane_over_an_interval_whose_even_steps_round_past_its_end_is_mapped() {
// Poppy Humanoid's edge: t0 + (t1 − t0)·1 is 1.2985843833752289, one rounding past t1, where
// a pcurve on [t0, t1] has no point; the closed form was refused for it.
let (t0, t1) = (0.013209624271103393f64, 1.2985843833752286f64);
assert!(t0 + (t1 - t0) * 1.0 > t1, "the interval's even step rounds past its end");
let plane = Surface::Plane { origin: [0.; 3], u_axis: [1., 0., 0.], v_axis: [0., 1., 0.] };
let curve = Curve::Spline { knots: vec![t0, t0, t0, t1, t1, t1], points: vec![[0., 0., 0.], [1., 2., 0.], [3., 1., 0.]] };
let pc = &pcurves_within(&plane, &one(&curve, [t0, t1]), 1e-9, None).unwrap()[0][0];
assert!(lift_error(&plane, &curve, [t0, t1], pc) < 1e-12);
}
#[test]
fn lines_polylines_and_splines_on_planes_are_their_points_mapped() {
let plane = Surface::PlaneThrough { origin: [1., 2., 3.], u_point: [3., 2., 3.], v_point: [1., 2., 7.] };