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();
}