Cube
Model a precise B-rep cube in Truck
B-rep Building Blocks
- Vertex → a point in 3D space.
- Edge → a curve connecting two vertices (line, arc, spline, etc.).
- Wire → an ordered loop of edges; closed wires bound faces.
- Face → a surface patch bounded by one outer wire (plus optional inner wires for holes).
- Shell → a connected set of stitched faces.
- Solid → a closed, watertight shell enclosing a volume.
Build a cube with tsweep
What tsweep does
tsweep takes a geometric element and pushes it in a straight line to create the next-level element:
- sweep a vertex → you get an edge
- sweep an edge → you get a face
- sweep a face → you get a solid
A cube is built by sweeping three times along the X, Y, and Z directions.
src/cube.rs
#![allow(unused)] fn main() { use truck_modeling::*; }
#![allow(unused)] fn main() { pub fn cube() -> Solid { // STEPS 1-4 GO HERE } }
1. Place the first vertex at (-1, 0, -1).
#![allow(unused)] fn main() { let vertex: Vertex = builder::vertex(Point3::new(-1.0, 0.0, -1.0)); }
what this code does
builder::vertex lifts a raw point into a B-rep Vertex, giving us a manipulable geometric anchor for the sweeps that follow.
visual
y
│
│
(x=-1) ● │
start \ │
here \│
└──── x
/
z
Point = (-1, 0, -1)
2. Sweep 2 units along +Z → edge.
#![allow(unused)] fn main() { let edge: Edge = builder::tsweep(&vertex, 2.0 * Vector3::unit_z()); }
what this code does
builder::tsweep clones the vertex and moves the copy by 2.0 * +Z—since +Z is the unit vector (0, 0, 1), the translation is (0, 0, 2) (two units up the Z axis).
It then returns the Edge spanning between the original point and the shifted one.
visual
Before sweep:
● (vertex)
After sweeping along +Z:
●──────────●
(start) (end)
This is the new Edge.
3. Sweep edge 2 units along +X → rectangular face.
#![allow(unused)] fn main() { let face: Face = builder::tsweep(&edge, 2.0 * Vector3::unit_x()); }
what this code does
The edge is duplicated and shifted +X by 2.0; tsweep stitches the original and shifted edges into a ruled surface, yielding a rectangular Face.
visual
Sweep direction +X:
●──────────●
| |
| |
| |
│ │
●──────────●
That forms a rectangular Face.
4. Sweep face 2 units along +Y → solid cube.
#![allow(unused)] fn main() { builder::tsweep(&face, 2.0 * Vector3::unit_y()) }
what this code does
Sweeps the rectangular face upward by 2.0 along +Y, then caps the start and end to form a closed shell; because the face is planar and bounded, the result is a watertight solid cube.
visual
Sweeping the rectangular face upward (+Y) forms the cube volume:
●─────────●
/| /|
/ | / |
●─────────● |
│ | │ |
│ ●──────┼──●
│ / │ /
●─────────●
(full solid)
Direction of final sweep: +Y
Update src/lib.rs to expose cube
#![allow(unused)] fn main() { pub mod cube; pub use cube::cube; }
Example entry point
examples/cube.rs calls into the library and uses the helper wrappers that create output folders automatically:
fn main() { let cube = truck_brep::cube(); truck_brep::save_obj(&cube, "output/cube.obj").unwrap(); truck_brep::save_step(&cube, "output/cube.step").unwrap(); }
This keeps the binary minimal and lets other sections reuse the same helpers.
Directory tree
truck_brep/
├─ src/
│ ├─ lib.rs # helpers + re-exports
│ └─ cube.rs # cube()
├─ examples/
│ └─ cube.rs # calls into lib
└─ output/ # generated OBJ/STEP (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; /// 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/cube.rs
#![allow(unused)] fn main() { use truck_modeling::*; pub fn cube() -> Solid { let vertex: Vertex = builder::vertex(Point3::new(-1.0, 0.0, -1.0)); let edge: Edge = builder::tsweep(&vertex, 2.0 * Vector3::unit_z()); let face: Face = builder::tsweep(&edge, 2.0 * Vector3::unit_x()); builder::tsweep(&face, 2.0 * Vector3::unit_y()) } }
examples/cube.rs
fn main() { let cube = truck_brep::cube(); truck_brep::save_obj(&cube, "output/cube.obj").unwrap(); truck_brep::save_step(&cube, "output/cube.step").unwrap(); }