use cadmpeg_core::CodecError;
use cadmpeg_ir::geometry::{
Curve, CurveGeometry, ProceduralCurve, ProceduralCurveDefinition, SolvedCurveGeometry,
};
use cadmpeg_ir::ids::CurveId;
use cadmpeg_ir::topology::{Coedge, Edge, IncreasingParameterInterval, ParameterInterval};
pub(super) fn localize_subsets(
curves: &mut [Curve],
edges: &mut [Edge],
coedges: &mut [Coedge],
procedural_curves: &[(CurveId, ProceduralCurve)],
) -> Result<(), CodecError> {
for (owner, procedural) in procedural_curves {
let ProceduralCurveDefinition::Subset(subset) = procedural.definition() else {
continue;
};
let [first, last] = subset.parameter_range().endpoints();
let shift = if *subset.sense() { -first } else { last };
let shifted = |[start, end]: [f64; 2]| {
ParameterInterval::new([start + shift, end + shift]).map_err(CodecError::malformed)
};
for curve in curves.iter_mut().filter(|curve| curve.id == *owner) {
if let CurveGeometry::Solved(SolvedCurveGeometry::Nurbs(cache)) = &mut curve.geometry {
cache
.edit_knots(|knots| knots.iter_mut().for_each(|knot| *knot += shift))
.map_err(|error| {
CodecError::malformed(format_args!("subset curve {owner}: {error}"))
})?;
}
if let Some(range) = curve.parameter_range {
curve.parameter_range =
IncreasingParameterInterval::new(shifted(range.endpoints())?.endpoints());
}
}
for edge in edges.iter_mut().filter(|edge| edge.curve() == Some(owner)) {
if let Some(range) = edge.param_range() {
edge.set_param_range(Some(shifted(range.get())?));
}
}
for use_curve in coedges
.iter_mut()
.filter_map(|coedge| coedge.use_curve.as_mut())
.filter(|use_curve| use_curve.curve == *owner)
{
use_curve.parameter_range = shifted(use_curve.parameter_range.endpoints())?;
}
}
Ok(())
}