Expand description
Lean STEP (ISO 10303) I/O for 3D CAD kernels — reads every mainstream AP, writes only modern AP242.
⚠️ Experimental — early stage; expect breaking API changes at any time.
- Reads everything, writes AP242 — any mainstream AP comes in, legacy included; only AP242 edition 2 (IS) goes out.
- Lean — one universal schema model instead of a per-schema implementation; entities that never appear in real STEP files are pruned out.
- Heals non-standard input — what can be fixed is normalized; what cannot is dropped with a reason, never silently.
- Ergonomic API —
scene()navigates what you read with lightweight handles;StepBuilderwrites new files the way kernels hold data.
§Design
step-io exists to sit between a 3D CAD kernel and the STEP files it exchanges.
Most STEP libraries carry per-schema entity and read/write code, so each supported schema adds source and binary size. step-io instead merges the mainstream APs into one universal schema and reads them all through a single pipeline. Entities that never appear in practice are left out, judged against 50,000+ real-world files — the entity coverage matrix lists exactly what is read and written.
Output is AP242 edition 2 (IS) only — AP203 and AP214 were merged into it in 2014, and every modern tool reads it. When edition 3 reaches IS and takes over, the output target moves up with it: one output schema, always the current one.
Most of the pipeline is generated from the schemas rather than written by hand — no drift, little to maintain.
§Reading STEP into a kernel or viewer
Reading gives the result and the report together: read returns the
StepModel plus a Report of what was kept, normalized, or dropped
and why. Real-world files are rarely clean — messy content is healed or
dropped rather than failing the import, and the report is the record of
what happened on the way in.
The model is raw and complete: one public arena per entity type, schema-faithful. Everything the reader kept is directly accessible.
Scene — model.scene() — is the navigation layer on
top: lightweight Copy handles covering what imports touch most, not
every entity. In reach are b-rep geometry (solid → face → surface, edge →
curve → point), the assembly tree with placements, display meshes, PMI
(dimensions, tolerances, datum features), product metadata (versions,
approvals, documents), presentation (colour / layer / visibility), and
units — see the scene module docs. Anything beyond the handles is
reached through the raw model via Scene::model.
use step_io::scene::geometry::SurfaceKind;
let source = std::fs::read("part.step").unwrap();
let (model, _report) = step_io::read(&source).unwrap(); // report: kept / normalized / dropped
let scene = model.scene();
// Geometry comes in its stored analytic form first; NURBS only on demand.
for solid in scene.all_solids() {
for face in solid.faces() {
match face.surface().kind() {
SurfaceKind::Plane(_p) => { /* the kernel's own plane */ }
SurfaceKind::Cylindrical(_c) => { /* the kernel's own cylinder */ }
// … other analytic kinds …
_ => {
let _patch = face.to_nurbs(); // opt-in NURBS fallback
}
}
}
}
// Assemblies, meshes, PMI, metadata, presentation: the same handles —
// the full tour is in the `scene` module docs.
// Navigation anomalies collected during the walk above — not the read-time
// `Report`, a second channel. Log and continue, do not fail the import.
for w in scene.warnings() {
eprintln!("step-io: {w}");
}§Writing STEP from a kernel
The write side is strict by construction. Its foundation is Ap242Author,
a generated low-level layer with one constructor per AP242 entity (exposed
as StepBuilder::author); every argument is validated at insertion, so
the output always conforms to the AP242 edition 2 schema — there is no loss
report to check afterwards.
StepBuilder is the convenience layer on top, covering what exports
touch most: parts and b-rep topology (vertex → edge → face → solid, over
analytic surfaces or NURBS), assembly instances with placements, display
meshes, presentation (colour / transparency / layer / visibility), PLM
metadata (contributors, approvals, documents, security), units, and the
Part 21 header — see the build module docs.
use step_io::StepBuilder;
use step_io::build::PartOptions;
let mut b = StepBuilder::new().unwrap(); // millimetre; new_with() to choose
let wheel = b.part_with("wheel", &PartOptions {
id: Some("W-100".into()),
version: Some("B".into()),
..Default::default()
}).unwrap();
// Mirror the kernel's own arrays — vertex → edge → face → solid, one
// handle per element.
let vs: Vec<_> = kernel.points.iter()
.map(|p| b.vertex(*p).unwrap())
.collect();
let es: Vec<_> = kernel.edges.iter()
.map(|e| b.edge(vs[e.start], vs[e.end], curve_of(e)).unwrap())
.collect();
let fs: Vec<_> = kernel.faces.iter()
.map(|f| b.face(surface_of(f), f.same_sense, loops_of(f, &es)).unwrap())
.collect();
b.solid(wheel, "wheel body", fs).unwrap();
// Assemblies, display meshes, colours, layers, and PLM metadata are one
// call each.
std::fs::write("wheel.step", b.finish().unwrap()).unwrap();Re-exports§
pub use build::StepBuilder;pub use emit::FileHeader;pub use generated::author::Ap242Author;pub use generated::author::AuthorError;pub use generated::model::EntityKey;pub use generated::model::StepModel;pub use reader::DropKind;pub use reader::DropReason;pub use reader::Report;pub use reader::read;pub use parser::ApFamily;pub use parser::Error;pub use parser::LexError;pub use parser::LexErrorKind;pub use parser::SchemaId;pub use parser::Stage;pub use refgraph::RefGraph;
Modules§
- build
StepBuilder— the convenience authoring layer over the strictAp242Authorconstructors.- emit
- The Part 21 envelope — the last step of writing.
- generated
- The generated layer — the schema-faithful
modeland itsread,write, andauthorcode. - parser
parse_bytes— STEP source to the raw, untyped entity graph.- reader
read— STEP source toStepModelplus a provenanceReport.- refgraph
RefGraph— reverse-reference index over aStepModel.- scene
Scene— the convenience navigation layer over the rawStepModel.