Attribute Macro fj::model

source ·
#[model]
Expand description

Define a function-based model.

The simplest model function takes no parameters and returns a hard-coded fj::Shape.

use fj::{Circle, Sketch, Shape};
#[model]
fn model() -> Shape {
    let circle = Circle::from_radius(10.0);
    Sketch::from_circle(circle).into()
}

For convenience, you can also return anything that could be converted into a fj::Shape (e.g. a fj::Sketch).

use fj::{Circle, Sketch};
#[model]
fn model() -> Sketch {
    let circle = Circle::from_radius(10.0);
    Sketch::from_circle(circle)
}

The return type is checked at compile time. That means something like this won’t work because () can’t be converted into a fj::Shape.

#[model]
fn model() { todo!() }

The model function’s arguments can be anything that implement std::str::FromStr.

#[model]
fn cylinder(height: f64, label: String, is_horizontal: bool) -> fj::Shape { todo!() }

Constraints and default values can be added to an argument using the #[param] attribute.

use fj::syntax::*;

#[fj::model]
pub fn spacer(
    #[param(default = 1.0, min = inner * 1.01)] outer: f64,
    #[param(default = 0.5, max = outer * 0.99)] inner: f64,
    #[param(default = 1.0)] height: f64,
) -> fj::Shape {
    let outer_edge = fj::Sketch::from_circle(fj::Circle::from_radius(outer));
    let inner_edge = fj::Sketch::from_circle(fj::Circle::from_radius(inner));

    let footprint = outer_edge.difference(&inner_edge);
    let spacer = footprint.sweep([0., 0., height]);

    spacer.into()
}

For more complex situations, model functions are allowed to return any error type that converts into a model error.

#[fj::model]
pub fn model() -> Result<fj::Shape, std::env::VarError> {
    let home_dir = std::env::var("HOME")?;

    todo!("Do something with {home_dir}")
}

fn assert_convertible(e: std::env::VarError) -> fj::models::Error { e.into() }