use axiolid_contracts::GeomResult;
use axiolid_nurbs::{intersect_surface_surface_certified, CertifiedSurfaceSurfaceIntersection3};
use axiolid_surface::BSplineSurface;
pub use crate::trimmed_intersection_types::{
CertifiedSurfacePairSplit3, CertifiedSurfacePairSplitOptions, CertifiedTrimmedSurfacePair3,
EmbeddedFaceCurve, SurfacePairMember, SurfacePairSplitUnresolvedReason,
};
use crate::trimmed_intersection_assembly::assemble;
use crate::trimmed_intersection_classify::classify;
pub fn split_surface_pair_certified(
first: &BSplineSurface,
second: &BSplineSurface,
options: CertifiedSurfacePairSplitOptions,
) -> GeomResult<CertifiedSurfacePairSplit3> {
let intersection =
intersect_surface_surface_certified(first, second, options.intersection_options())?;
let (mut traces, visited_patch_pairs, boundary_queries) = match intersection {
CertifiedSurfaceSurfaceIntersection3::Unresolved { .. } => {
return Ok(CertifiedSurfacePairSplit3::Unresolved {
intersection,
reason: SurfacePairSplitUnresolvedReason::IntersectionUnresolved,
});
}
CertifiedSurfaceSurfaceIntersection3::Complete {
traces,
visited_patch_pairs,
boundary_queries,
} => (traces, visited_patch_pairs, boundary_queries),
other => {
return Ok(CertifiedSurfacePairSplit3::Unresolved {
intersection: other,
reason: SurfacePairSplitUnresolvedReason::IntersectionUnresolved,
});
}
};
if traces.is_empty() {
return Ok(CertifiedSurfacePairSplit3::Empty {
visited_patch_pairs,
boundary_queries: u32::from(boundary_queries),
});
}
if traces.len() != 1 {
return Ok(unresolved_complete(
traces,
visited_patch_pairs,
boundary_queries,
SurfacePairSplitUnresolvedReason::UnsupportedTraceCount,
));
}
let Some(trace_ref) = traces.first() else {
return Ok(CertifiedSurfacePairSplit3::Empty {
visited_patch_pairs,
boundary_queries: u32::from(boundary_queries),
});
};
let residual_upper_bound = trace_ref
.start
.residual_upper_bound
.max(trace_ref.end.residual_upper_bound);
if !residual_upper_bound.is_finite() || residual_upper_bound > options.max_surface_residual() {
return Ok(unresolved_complete(
traces,
visited_patch_pairs,
boundary_queries,
SurfacePairSplitUnresolvedReason::ResidualExceedsPolicy,
));
}
let Some(classification) = classify(first, second, trace_ref) else {
return Ok(unresolved_complete(
traces,
visited_patch_pairs,
boundary_queries,
SurfacePairSplitUnresolvedReason::UnsupportedEndpointOwnership,
));
};
let Some(trace) = traces.pop() else {
return Ok(CertifiedSurfacePairSplit3::Empty {
visited_patch_pairs,
boundary_queries: u32::from(boundary_queries),
});
};
let split = assemble(
first,
second,
trace,
classification,
residual_upper_bound,
visited_patch_pairs,
boundary_queries,
)?;
Ok(CertifiedSurfacePairSplit3::Split(split))
}
fn unresolved_complete(
traces: Vec<axiolid_nurbs::TransverseSurfaceSurfaceTrace3>,
visited_patch_pairs: u32,
boundary_queries: u8,
reason: SurfacePairSplitUnresolvedReason,
) -> CertifiedSurfacePairSplit3 {
CertifiedSurfacePairSplit3::Unresolved {
intersection: CertifiedSurfaceSurfaceIntersection3::Complete {
traces,
visited_patch_pairs,
boundary_queries,
},
reason,
}
}