Torus
Build a torus (donut) with rotational sweeps, keeping the geometry and exports in the library just like the cube section. For the cylinder example, see modeling_cylinder.md.
Build a torus with rsweep
What rsweep does
rsweep spins a geometric element around an axis to create the next-level element:
- spin a vertex → you get a wire (circle)
- spin a wire → you get a shell
A torus is built by two rotations: one to form the circle, another to spin that circle into the donut.
src/torus.rs
#![allow(unused)] fn main() { use truck_modeling::*; }
#![allow(unused)] fn main() { pub fn torus() -> Solid { // STEPS 1-3 GO HERE } }
1. Place a vertex at (0, 0, 1).
#![allow(unused)] fn main() { let vertex: Vertex = builder::vertex(Point3::new(0.0, 0.0, 1.0)); }
what this code does
Creates a B-rep vertex at (0, 0, 1) to act as the seed point for the rotational sweeps.
visual
y
│
│
● │ (start at z = 1)
│
└──── x
/
z
2. Spin the vertex around +X to form a circular wire.
#![allow(unused)] fn main() { let circle: Wire = builder::rsweep( &vertex, Point3::new(0.0, 0.5, 1.0), // point on rotation axis Vector3::unit_x(), // axis direction Rad(7.0), // > 2π ensures closure ); }
what this code does
rsweep clones the vertex and spins it around the +X axis through (0, 0.5, 1.0); the start and end positions connect into a circular wire.
visual
Axis: +X through (0, 0.5, 1.0)
(spins around X)
^
|
●---+---● (wire)
|
axis
3. Spin the circle around +Y to form the torus shell.
#![allow(unused)] fn main() { builder::rsweep(&circle, Point3::origin(), Vector3::unit_y(), Rad(7.0)) }
what this code does
Rotates the circle about the Y axis at the origin; the swept surface forms the torus shell.
visual
Second rotation around +Y wraps the circle into a torus:
●─────●
/ \
● ●
\ /
●─────●
Update src/lib.rs to expose torus
#![allow(unused)] fn main() { pub mod torus; pub use torus::torus; }
Example entry point
examples/torus.rs stays tiny and calls into the library:
fn main() { let torus = truck_brep::torus(); truck_brep::save_obj(&torus, "output/torus.obj").unwrap(); truck_brep::save_step(&torus, "output/torus.step").unwrap(); }
Directory tree (for this section)
truck_brep/
├─ src/
│ ├─ lib.rs # helpers + re-exports
│ ├─ cube.rs # from previous section (optional)
│ └─ torus.rs # torus()
├─ examples/
│ ├─ cube.rs
│ └─ torus.rs
└─ output/ # created at runtime
Complete code
src/lib.rs
#![allow(unused)] fn main() { use std::{fs, io, path::Path}; use truck_meshalgo::prelude::*; use truck_modeling::*; use truck_stepio::out::{CompleteStepDisplay, StepModel}; use truck_topology::compress::{CompressedShell, CompressedSolid}; pub mod cube; pub use cube::cube; pub mod torus; pub use torus::torus; /// Helper to compress modeling shapes into STEP-compatible data. pub trait StepCompress { type Compressed; fn compress_for_step(&self) -> Self::Compressed; } impl StepCompress for Shell { type Compressed = CompressedShell<Point3, Curve, Surface>; fn compress_for_step(&self) -> Self::Compressed { self.compress() } } impl StepCompress for Solid { type Compressed = CompressedSolid<Point3, Curve, Surface>; fn compress_for_step(&self) -> Self::Compressed { self.compress() } } /// Export any B-rep (Solid or Shell) to STEP. pub fn save_step<T, P>(brep: &T, path: P) -> io::Result<()> where T: StepCompress, for<'a> StepModel<'a, Point3, Curve, Surface>: From<&'a T::Compressed>, P: AsRef<Path>, { let path = path.as_ref(); if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; } let compressed = brep.compress_for_step(); let display = CompleteStepDisplay::new( StepModel::from(&compressed), Default::default(), ); fs::write(path, display.to_string()) } /// Triangulate any B-rep (Solid or Shell) and write an OBJ mesh. pub fn save_obj(shape: &impl MeshableShape, path: impl AsRef<Path>) -> io::Result<()> { let mesh = shape.triangulation(0.01).to_polygon(); let path = path.as_ref(); if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; } let mut obj = fs::File::create(path)?; obj::write(&mesh, &mut obj).map_err(|err| io::Error::new(io::ErrorKind::Other, err)) } }
src/torus.rs
#![allow(unused)] fn main() { use truck_modeling::*; pub fn torus() -> Shell { let vertex: Vertex = builder::vertex(Point3::new(0.0, 0.0, 1.0)); let circle: Wire = builder::rsweep( &vertex, Point3::new(0.0, 0.5, 1.0), // point on rotation axis Vector3::unit_x(), // axis direction Rad(7.0), // > 2π ensures closure ); builder::rsweep(&circle, Point3::origin(), Vector3::unit_y(), Rad(7.0)) } }
examples/torus.rs
fn main() { let torus = truck_brep::torus(); truck_brep::save_obj(&torus, "output/torus.obj").unwrap(); truck_brep::save_step_any(&torus, "output/torus.step").unwrap(); }