mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-04 02:55:54 +00:00
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:
@@ -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));
|
||||
|
||||
@@ -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.] };
|
||||
|
||||
Reference in New Issue
Block a user