Skip to main content

brep_kernel/io/step_import/
mod.rs

1//! STEP Part 21 import for NURBS and analytic surfaces, assemblies, and PMI.
2//!
3//! The importer reconstructs and validates BREP topology. Analytic carriers are
4//! converted to NURBS sized to the face bounds. Pcurves are derived by projecting
5//! each edge onto its carrier; surface-curve wrappers contribute their 3D curve.
6//! Seam edges occupy opposite parameter boundaries, and collapsed pole bounds
7//! become degenerate edges so faces close and integrate correctly.
8
9use crate::topology::{
10    BrepSolid, CoedgeRecord, EdgeRecord, FaceRecord, LoopRecord, ShellRecord, VertexRecord,
11};
12use crate::{
13    build_pcurve_on_surface_range, make_arc, make_extrusion, make_hyperbola, make_line,
14    make_parabola, make_plane, make_revolution, offset_surface, transform_brep, AffineTransform,
15    NurbsCurve, NurbsSurface, Vec3, Vec4,
16};
17use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
18use std::collections::VecDeque;
19
20const TAU: f64 = std::f64::consts::TAU;
21
22mod parse;
23mod bodies;
24mod assembly;
25mod builder;
26mod geometry;
27mod styles;
28mod pmi;
29// BREP private tests: c4f20f6ac1ecc685
30
31use crate::appearance::{BodyAppearance, ImportedColor};
32use parse::*;
33use bodies::*;
34use builder::*;
35use geometry::*;
36use styles::*;
37pub use assembly::{read_step_assembly, StepAssembly, StepOccurrence, StepProduct};
38pub use pmi::read_step_pmi;
39pub(crate) use pmi::decode_step_text as decode_step_text_for_tests;
40
41
42// ---------------------------------------------------------------------------
43// Topology assembly
44// ---------------------------------------------------------------------------
45
46/// Public entry: parse a STEP Part 21 document and return one `BrepSolid` per
47/// MANIFOLD_SOLID_BREP, FACETED_BREP, or certified BREP_WITH_VOIDS. Every
48/// returned solid passes `validate()`.
49pub fn import_step(text: &str) -> Result<Vec<BrepSolid>, String> {
50    Ok(import_step_with_appearance(text)?.0)
51}
52
53/// [`import_step`] plus the file's PRESENTATION colours: one
54/// [`BodyAppearance`] per returned solid, in the same order.
55///
56/// This is the lane the IMPORT3D feature uses, because colour is stamped as
57/// scene metadata on the names IT chooses — see
58/// `feature_pipeline::features::import3d` and `io/appearance.rs` for the record
59/// shape. A file with no presentation entities returns default (empty)
60/// appearances, never a short vector, so callers can `zip` unconditionally.
61pub fn import_step_with_appearance(
62    text: &str,
63) -> Result<(Vec<BrepSolid>, Vec<BodyAppearance>), String> {
64    let imported = collect_step_solids(text)?;
65    if imported.solids.is_empty() {
66        return Err(imported.first_error.unwrap_or_else(|| {
67            "step_import: no MANIFOLD_SOLID_BREP/FACETED_BREP/BREP_WITH_VOIDS body imported (unsupported or invalid representation)"
68                .into()
69        }));
70    }
71    Ok((imported.solids, imported.appearances))
72}
73
74/// Like [`import_step`] but reports how many bodies failed and the first error,
75/// so callers can distinguish a fully- from a partially-imported assembly.
76pub fn import_step_report(text: &str) -> Result<(Vec<BrepSolid>, usize, Option<String>), String> {
77    let imported = collect_step_solids(text)?;
78    Ok((imported.solids, imported.failed, imported.first_error))
79}