use super::*;
#[derive(Clone, Debug)]
pub struct StepTrimReadings {
pub stated_precisions_mm: Vec<f64>,
pub has_structure: bool,
pub bodies: Vec<StepBodyTrimReadings>,
}
#[derive(Clone, Debug)]
pub struct StepBodyTrimReadings {
pub body_ref: usize,
pub solid: Result<BrepSolid, String>,
pub closure_refusal: Option<String>,
pub edges: Vec<StepEdgeReading>,
pub faces: Vec<StepFaceReading>,
}
#[derive(Clone, Debug)]
pub struct StepEdgeReading {
pub edge_id: u64,
pub curve_ref: Option<usize>,
pub written: Option<(NurbsCurve, [f64; 2])>,
pub stages: Vec<String>,
}
#[derive(Clone, Debug)]
pub struct StepFaceReading {
pub face_id: u64,
pub face_ref: usize,
pub surface_ref: usize,
pub supplied: Vec<StepSuppliedTrim>,
}
#[derive(Clone, Debug)]
pub struct StepSuppliedTrim {
pub edge_id: u64,
pub forward: bool,
pub stations: Vec<Vec3>,
}
const STATIONS: usize = 64;
pub fn import_step_trim_readings(text: &str) -> Result<StepTrimReadings, String> {
if !text.contains("ISO-10303-21") {
return Err("step_import: not an ISO-10303-21 Part 21 file".into());
}
let entities = parse_data_section(text)?;
let resolver = Resolver::new(&entities, derive_length_scale_mm(&entities));
let stated_precisions_mm = stated_precisions_mm(&entities);
let has_structure = !structure_edges(&entities, &resolver).is_empty();
let mut bodies = Vec::new();
for body in flat_step_bodies(&resolver, &entities) {
let body_ref = match body {
StepBody::SolidBrep(entity_ref) | StepBody::BrepWithVoids(entity_ref) => entity_ref,
StepBody::SurfaceModelShell { shell_ref, .. } => shell_ref,
};
let (solid, capture, closure_refusal) = match build_step_body_captured(&resolver, body) {
Ok((solid, capture, readings)) => (
Ok(solid),
capture.unwrap_or_default(),
readings.closure.overridden().map(|refusal| refusal.message.clone()),
),
Err(error) => (Err(error.to_string()), Default::default(), None),
};
let mut edges: Vec<StepEdgeReading> = Vec::new();
let mut faces: Vec<StepFaceReading> = Vec::new();
if let Ok(solid) = &solid {
for edge in &solid.edges {
let written = capture.written.get(&edge.id);
edges.push(StepEdgeReading {
edge_id: edge.id,
curve_ref: written.and_then(|written| written.curve_ref),
written: written.map(|written| (written.curve.clone(), [written.t0, written.t1])),
stages: capture.stages.get(&edge.id).cloned().unwrap_or_default(),
});
}
for face in solid.shells.iter().flat_map(|shell| &shell.faces) {
let Some(&(_, face_ref, surface_ref)) =
capture.faces.iter().find(|(id, _, _)| *id == face.id)
else {
continue;
};
let mut supplied = Vec::new();
for coedge in face.loops.iter().flat_map(|loop_record| &loop_record.coedges) {
let Some(written) = capture.written.get(&coedge.edge_id) else {
continue;
};
let Some(curve_ref) = written.curve_ref else {
continue;
};
let bundle = resolver.supplied_pcurves(curve_ref);
let Some(pcurve) = bundle.iter().find(|pcurve| pcurve.basis_ref == surface_ref)
else {
continue;
};
let mut stations = Vec::with_capacity(STATIONS + 1);
let mut cursor = None;
let mut readable = true;
for index in 0..=STATIONS {
let fraction = index as f64 / STATIONS as f64;
let along = if coedge.forward { fraction } else { 1.0 - fraction };
let Ok(point) =
written.curve.evaluate(written.t0 + (written.t1 - written.t0) * along)
else {
readable = false;
break;
};
let Ok((uv, on_trim)) = pcurve.snap(point, cursor) else {
readable = false;
break;
};
cursor = Some(uv);
stations.push(on_trim);
}
if readable {
supplied.push(StepSuppliedTrim {
edge_id: coedge.edge_id,
forward: coedge.forward,
stations,
});
}
}
faces.push(StepFaceReading {
face_id: face.id,
face_ref,
surface_ref,
supplied,
});
}
}
bodies.push(StepBodyTrimReadings {
body_ref,
solid,
closure_refusal,
edges,
faces,
});
}
Ok(StepTrimReadings {
stated_precisions_mm,
has_structure,
bodies,
})
}