use axiolid_core::Scalar;
use axiolid_curve::{CurvatureLaw, Intrinsic2, Intrinsic3};
use super::{frame_stretch2, frame_stretch3, inflate, ordered, taylor, CurveDerivativeBounds};
use crate::chain::curvature_bound;
fn span(a: Scalar, b: Scalar, length: Scalar) -> Option<(Scalar, Scalar)> {
if !(a.is_finite() && b.is_finite() && length.is_finite() && length > 0.0) {
return None;
}
let (lo, hi) = ordered(a, b);
(lo >= 0.0 && hi <= length).then_some((lo, hi))
}
fn law_bounds(
law: &CurvatureLaw,
length: Scalar,
stretch: Scalar,
lo: Scalar,
hi: Scalar,
) -> Option<CurveDerivativeBounds> {
let k = curvature_bound(law, lo, hi)?;
let seamed = law
.seams_within(length)
.iter()
.any(|&seam| seam > lo && seam < hi);
let third = if seamed {
Scalar::INFINITY
} else {
curvature_bound(&law.derivative(), lo, hi)? + k * k
};
Some(CurveDerivativeBounds {
first: inflate(stretch),
second: inflate(stretch * k),
third: inflate(stretch * third),
})
}
#[must_use]
pub fn intrinsic_derivative_bounds2(
curve: &Intrinsic2,
a: Scalar,
b: Scalar,
) -> Option<CurveDerivativeBounds> {
let (lo, hi) = span(a, b, curve.length)?;
law_bounds(
&curve.curvature,
curve.length,
frame_stretch2(&curve.start),
lo,
hi,
)
}
#[must_use]
pub fn intrinsic_chord_bound2(curve: &Intrinsic2, a: Scalar, b: Scalar) -> Option<Scalar> {
let bounds = intrinsic_derivative_bounds2(curve, a, b)?;
let out = inflate(taylor(b - a, bounds.second));
out.is_finite().then_some(out)
}
#[must_use]
pub fn intrinsic_chord_bound3(curve: &Intrinsic3, a: Scalar, b: Scalar) -> Option<Scalar> {
let (lo, hi) = span(a, b, curve.length)?;
let k = curvature_bound(&curve.curvature, lo, hi)?;
let out = inflate(taylor(hi - lo, frame_stretch3(&curve.start) * k));
out.is_finite().then_some(out)
}