Expand description
arris — a B-Rep geometric kernel written from scratch in Rust.
This crate is the facade: it re-exports the workspace crates as modules
(arris::math through arris::io) so a consumer depends on one name
and reaches everything through it. Nothing lives here that does not
live in a lower crate; the guarantees are each crate’s
(docs/ARCHITECTURE.md).
use arris::math::{Axis, Control, Point3};
use arris::topo::Model;
use arris::check::{Level, check};
let mut m = Model::default();
let (cylinder, provenance) =
arris::ops::primitive_cylinder(&mut m, Axis::z_at(Point3::origin()), 4.0, 12.0, &Control::NONE)
.unwrap();
assert!(check(&m, cylinder, Level::Full).is_ok());
assert_eq!(provenance.outputs().len(), 10);
let text = arris::io::step::write(&m, &[cylinder]).unwrap();
assert!(text.starts_with("ISO-10303-21;"));
// And back: every solid of a file, each its own result.
let mut back = Model::default();
let read = arris::io::step::read(&mut back, &text, &Default::default(), &Control::NONE).unwrap();
let body = read.solids[0].result.as_ref().unwrap().body;
assert!(check(&back, body, Level::Full).is_ok());A profile carried along a path is sweep: a path of lines, arcs,
helices or NURBS curves, each span exact where a quadric holds it and
fitted where none does.
use arris::Control;
use arris::geom::profile::{Profile, ProfileLoop};
use arris::geom::{FrameLaw, Path, PathSegment};
use arris::math::{Frame, Point2, Point3, Vec3};
use arris::ops::sweep;
use arris::topo::Model;
let profile = Profile {
plane: Frame::new(Point3::origin(), Vec3::z(), Vec3::x()).unwrap(),
outer: ProfileLoop::Circle { center: Point2::origin(), radius: 1.0 },
holes: vec![],
};
let path = Path {
start: Point3::origin(),
segments: vec![PathSegment::LineTo(Point3::new(0.0, 0.0, 10.0))],
};
let mut m = Model::default();
let (pipe, provenance) =
sweep(&mut m, &profile, &path, FrameLaw::default(), &Control::NONE).unwrap();
assert_eq!(m.faces(pipe).unwrap().len(), 3, "two caps and the wall");
assert_eq!(provenance.outputs().len(), 10);Profiles placed at different heights are lofted: loft goes through
two or more of them, ruled (each span straight) or smooth (one surface).
use arris::Control;
use arris::geom::profile::{Profile, ProfileLoop};
use arris::math::{Frame, Point2, Point3, Vec3};
use arris::ops::{LoftKind, loft};
use arris::topo::Model;
let disc = |z: f64, radius: f64| Profile {
plane: Frame::new(Point3::new(0.0, 0.0, z), Vec3::z(), Vec3::x()).unwrap(),
outer: ProfileLoop::Circle { center: Point2::origin(), radius },
holes: vec![],
};
let mut m = Model::default();
let sections = [disc(0.0, 2.0), disc(3.0, 1.0)];
let (cone, _) = loft(&mut m, §ions, LoftKind::Ruled, false, &Control::NONE).unwrap();
assert_eq!(m.faces(cone).unwrap().len(), 3, "two caps and the cone");Every operation on a model takes a Control last, so its caller can
stop it: a poll it answers from whatever its platform has (here an
AtomicBool another thread sets), a budget of steps, both or neither.
A stop is Interrupted in the operation’s own error type, and the
model is as it was before the call.
use arris::{Control, Stop};
use arris::ops::{OpError, primitive_box};
use arris::topo::Model;
use core::sync::atomic::{AtomicBool, Ordering};
let mut m = Model::default();
// A poll: the consumer's flag, asked at every step.
let cancel = AtomicBool::new(true);
let poll = || cancel.load(Ordering::Relaxed);
let stopped = primitive_box(&mut m, [0.0; 3], [1.0; 3], &Control::poll(&poll));
let Err(OpError::Interrupted(stop)) = stopped else { panic!("not stopped") };
assert_eq!(stop.by, Stop::Poll);
assert!(m.body(arris::topo::BodyId::new(0, 0)).is_err(), "nothing was left in the model");
// A budget: the same input and budget stop at the same step everywhere.
let spent = primitive_box(&mut m, [0.0; 3], [1.0; 3], &Control::budget(0));
assert!(matches!(spent, Err(OpError::Interrupted(s)) if s.by == Stop::Budget && s.steps == 0));
// Neither: run to the end. A budget that is enough changes nothing.
cancel.store(false, Ordering::Relaxed);
assert!(primitive_box(&mut m, [0.0; 3], [1.0; 3], &Control::poll(&poll).with_budget(100)).is_ok());Re-exports§
pub use arris_check as check;pub use arris_geom as geom;pub use arris_io as io;pub use arris_math as math;pub use arris_mesh as mesh;pub use arris_ops as ops;pub use arris_topo as topo;
Structs§
- Control
- How a caller stops an operation: a poll, a budget of steps, both or
neither. Every operation on a model, and every long query beside one,
takes one last;
Control::NONEis what a caller that does not care passes. - Interrupted
- An operation that was stopped, by the caller and not by its input. The model is as it was before the call.
Enums§
- Stop
- What stopped an operation.