Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Blends and chamfers

Everything here is in ogeom::fillet.

Rounding one edge

    let block = ogeom::algo::make_box(&mut model, Frame::WORLD, (40.0, 30.0, 12.0), T)
        .unwrap()
        .shape;

    // Pick the top edge along y = 0 and round it at radius 2.
    let edge = edge_near(&model, &block, Point::new(20.0, 0.0, 12.0));
    let rounded = ogeom::fillet::fillet_edge(&mut model, &block, &edge, 2.0, T)
        .unwrap()
        .shape;

    // A fillet removes the square corner and leaves the quarter cylinder:
    // ΔV = (1 − π/4)·r²·length, exactly.
    let volume = ogeom::algo::volume_properties(&model, &rounded, Deflection::default(), T)
        .unwrap()
        .mass;
    let exact = 40.0 * 30.0 * 12.0 - (1.0 - core::f64::consts::FRAC_PI_4) * 4.0 * 40.0;
    assert!((volume - exact).abs() / exact < 0.01);
FunctionResult
fillet_edgeConstant-radius round.
fillet_edge_variableRound with a radius law along the edge.
chamfer_edgeSymmetric flat bevel.
chamfer_edge_distancesAsymmetric bevel (two distances).
chamfer_edge_angleBevel from a distance and an angle.

Fillets are not limited to planes. Between cylinders, cones, spheres, tori and fitted patches, the rolling ball is marched numerically instead of solved in closed form. The blend surface is fitted through its cross-section arcs and merged into the solid the same way.

Several edges at once

Edges filleted or chamfered in separate calls each stop flush against whatever they end on. Passed in one call, they join:

    let block = ogeom::algo::make_box(&mut model, Frame::WORLD, (20.0, 20.0, 10.0), T)
        .unwrap()
        .shape;
    let top = [
        Point::new(10.0, 0.0, 10.0),
        Point::new(20.0, 10.0, 10.0),
        Point::new(10.0, 20.0, 10.0),
        Point::new(0.0, 10.0, 10.0),
    ]
    .map(|at| edge_near(&model, &block, at));

    // Four bevels as one operation mitre where they meet: each corner loses
    // the overlap of two prisms, a third of the cube of the distance.
    let bevelled = ogeom::fillet::chamfer_edges(&mut model, &block, &top, 1.0, T)
        .unwrap()
        .shape;
    let volume = ogeom::algo::volume_properties(&model, &bevelled, Deflection::default(), T)
        .unwrap()
        .mass;
    assert!((volume - (4000.0 - 4.0 * 10.0 + 4.0 / 3.0)).abs() < 1e-2);

    // Three fillets meeting at a corner close it with the ball's own patch,
    // an octant of a sphere, instead of leaving the bands' caps standing.
    let corner = [
        Point::new(10.0, 20.0, 10.0),
        Point::new(20.0, 10.0, 10.0),
        Point::new(20.0, 20.0, 5.0),
    ]
    .map(|at| edge_near(&model, &block, at));
    let rounded = ogeom::fillet::fillet_edges(&mut model, &block, &corner, 2.0, T)
        .unwrap()
        .shape;
    let spheres = ogeom::topo::explore_unique(&model, &rounded, ogeom::topo::ShapeType::Face)
        .unwrap()
        .iter()
        .filter(|face| {
            let data = model.node(face).unwrap().data().as_face().unwrap();
            matches!(
                model.geometry().surface(data.surface),
                Some(ogeom::geom::SurfaceGeometry::Sphere(_))
            )
        })
        .count();
    assert_eq!(spheres, 1);
  • fillet_edges trims neighbouring bands against each other, joins tangent chains without a seam, and fills every vertex where three or more filleted edges meet with a rolling-ball corner patch.
  • round_vertex is that corner tool on its own:
    • where one ball can touch all the faces, it produces a sphere patch;
    • where no single ball can (for example the apex of a rectangular pyramid), it produces the exact envelope of the rolling ball: spheres joined by cylinders.
  • chamfer_edges and chamfer_edges_with bevel a set of edges in one operation. Every wedge is built on the solid as it was before the call, so the bevels mitre where they meet.

Blends between faces without a shared edge

  • blend_faces rolls a constant-radius ball between two faces that need not share an edge.
  • march_blend is the underlying marcher. It traces the contact circle and reports why it stopped (BlendStop). Use it to blend up to an obstruction on purpose.

Tangency checks

A blend must end tangent to the faces it joins. analyse_blend measures the achieved contact and returns it as BlendContact. Fillets report their own tangency deviation, and a blend that cannot reach tangency within tolerance is refused.