use crate::geometry::{
pcurve::PcurveGeometry, DirectedParameterRange, IntcurveSupportSide, SupportPcurve,
};
use crate::scalar::FiniteReal;
use crate::test_support::nurbs::pcurve;
use crate::topology::ParameterInterval;
#[test]
fn numerical_audit_identity_map_keeps_a_small_finite_parameter() {
let side = IntcurveSupportSide {
surface: None,
pcurve: Some(SupportPcurve::new(
PcurveGeometry::Nurbs { nurbs: pcurve() },
Some(DirectedParameterRange::new([0.0, 1e308]).unwrap()),
)),
};
let parameter = 1e-308;
let mapped = side
.pcurve_parameter(ParameterInterval::new([0.0, 1e308]).unwrap(), parameter)
.unwrap()
.get();
assert!((mapped / parameter - 1.0).abs() <= 8.0 * f64::EPSILON);
}
#[test]
fn support_mapping_preserves_decreasing_parameter_direction() {
for endpoints in [[0.0, 0.0], [0.0, f64::NAN], [f64::INFINITY, 0.0]] {
assert!(DirectedParameterRange::new(endpoints).is_err());
}
assert!(serde_json::from_str::<DirectedParameterRange>("[2.0,2.0]").is_err());
let side = IntcurveSupportSide {
surface: None,
pcurve: Some(SupportPcurve::new(
PcurveGeometry::Nurbs { nurbs: pcurve() },
Some(DirectedParameterRange::new([5.0, 2.0]).unwrap()),
)),
};
assert_eq!(
side.pcurve_parameter(ParameterInterval::new([0.0, 1.0]).unwrap(), 0.0)
.map(FiniteReal::get),
Some(5.0)
);
assert_eq!(
side.pcurve_parameter(ParameterInterval::new([0.0, 1.0]).unwrap(), 1.0)
.map(FiniteReal::get),
Some(2.0)
);
let range = side
.pcurve_parameter_range()
.expect("the side states its pcurve range");
assert_eq!(range.endpoints(), [5.0, 2.0]);
assert_eq!(range.finite_endpoints().map(FiniteReal::get), [5.0, 2.0]);
assert_eq!(
serde_json::from_value::<IntcurveSupportSide>(serde_json::to_value(&side).unwrap())
.unwrap(),
side
);
}
#[test]
fn finite_support_endpoints_do_not_require_a_representable_span() {
for (solved, mapped, midpoint) in [
([-f64::MAX, f64::MAX], [5.0, 2.0], 3.5),
([-1.0, 1.0], [-f64::MAX, f64::MAX], 0.0),
([-f64::MAX, f64::MAX], [f64::MAX, -f64::MAX], 0.0),
] {
let side = IntcurveSupportSide {
surface: None,
pcurve: Some(SupportPcurve::new(
PcurveGeometry::Nurbs { nurbs: pcurve() },
Some(DirectedParameterRange::new(mapped).unwrap()),
)),
};
assert_eq!(
side.pcurve_parameter(ParameterInterval::new(solved).unwrap(), solved[0])
.map(FiniteReal::get),
Some(mapped[0])
);
assert_eq!(
side.pcurve_parameter(ParameterInterval::new(solved).unwrap(), 0.0)
.map(FiniteReal::get),
Some(midpoint)
);
assert_eq!(
side.pcurve_parameter(ParameterInterval::new(solved).unwrap(), solved[1])
.map(FiniteReal::get),
Some(mapped[1])
);
assert_eq!(
side.pcurve_parameter(ParameterInterval::new(solved).unwrap(), f64::NAN)
.map(FiniteReal::get),
None
);
}
}
#[test]
fn support_mapping_preserves_endpoints_despite_subtraction_cancellation() {
let side = IntcurveSupportSide {
surface: None,
pcurve: Some(SupportPcurve::new(
PcurveGeometry::Nurbs { nurbs: pcurve() },
Some(DirectedParameterRange::new([1e16, 1.0]).unwrap()),
)),
};
assert_eq!(
side.pcurve_parameter(ParameterInterval::new([0.0, 1.0]).unwrap(), 0.0)
.map(FiniteReal::get),
Some(1e16)
);
assert_eq!(
side.pcurve_parameter(ParameterInterval::new([0.0, 1.0]).unwrap(), 1.0)
.map(FiniteReal::get),
Some(1.0)
);
}
#[test]
fn a_support_context_over_an_increasing_interval_matches_its_raw_admission() {
use crate::geometry::IntcurveSupportContext;
use crate::topology::IncreasingParameterInterval;
let side = |range| IntcurveSupportSide {
surface: None,
pcurve: Some(SupportPcurve::new(
PcurveGeometry::Nurbs { nurbs: pcurve() },
range,
)),
};
let sides = [
side(Some(DirectedParameterRange::new([1.0, 0.0]).unwrap())),
side(None),
];
let interval = IncreasingParameterInterval::new([0.25, 3.0]).unwrap();
assert_eq!(
IntcurveSupportContext::try_new(
sides.clone(),
interval.endpoints(),
std::array::from_fn(|_| Vec::new()),
),
Ok(IntcurveSupportContext::over_interval(sides, interval))
);
}
#[test]
fn a_support_context_holds_its_admitted_interval_and_discontinuities() {
use crate::geometry::IntcurveSupportContext;
let sides = std::array::from_fn(|_| IntcurveSupportSide {
surface: None,
pcurve: None,
});
let context =
IntcurveSupportContext::try_new(sides, [2.0, 5.0], [vec![2.5], vec![], vec![3.0, 4.0]])
.unwrap();
assert_eq!(
context.parameter_range(),
ParameterInterval::new([2.0, 5.0]).unwrap()
);
assert_eq!(
FiniteReal::raw_lanes(context.discontinuities()),
[vec![2.5], vec![], vec![3.0, 4.0]]
);
let wire = serde_json::to_value(&context).unwrap();
assert_eq!(wire["parameter_range"], serde_json::json!([2.0, 5.0]));
assert_eq!(
wire["discontinuities"],
serde_json::json!([[2.5], [], [3.0, 4.0]])
);
assert_eq!(
serde_json::from_value::<IntcurveSupportContext>(wire).unwrap(),
context
);
}