Skip to content

Commit

Permalink
Migrated all models over to the new API
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael-F-Bryan committed Jul 28, 2022
1 parent 7dd24b3 commit 67a2337
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 79 deletions.
1 change: 1 addition & 0 deletions crates/fj/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub trait Host {
/// This is mainly for more advanced use cases (e.g. when you need to close
/// over extra state to load the model). For simpler models, you probably
/// want to use [`HostExt::register_model()`] instead.
#[doc(hidden)]
fn register_boxed_model(&mut self, model: Box<dyn Model>);
}

Expand Down
10 changes: 5 additions & 5 deletions crates/fj/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl PluginMetadata {
}

/// Set the [`PluginMetadata::short_description`] field.
pub fn set_short_description(
pub fn with_short_description(
self,
short_description: impl Into<String>,
) -> Self {
Expand All @@ -63,7 +63,7 @@ impl PluginMetadata {
}

/// Set the [`PluginMetadata::description`] field.
pub fn set_description(self, description: impl Into<String>) -> Self {
pub fn with_description(self, description: impl Into<String>) -> Self {
let description = description.into();
if description.is_empty() {
return self;
Expand All @@ -76,7 +76,7 @@ impl PluginMetadata {
}

/// Set the [`PluginMetadata::homepage`] field.
pub fn set_homepage(self, homepage: impl Into<String>) -> Self {
pub fn with_homepage(self, homepage: impl Into<String>) -> Self {
let homepage = homepage.into();
if homepage.is_empty() {
return self;
Expand All @@ -89,7 +89,7 @@ impl PluginMetadata {
}

/// Set the [`PluginMetadata::repository`] field.
pub fn set_repository(self, repository: impl Into<String>) -> Self {
pub fn with_repository(self, repository: impl Into<String>) -> Self {
let repository = repository.into();
if repository.is_empty() {
return self;
Expand All @@ -102,7 +102,7 @@ impl PluginMetadata {
}

/// Set the [`PluginMetadata::license`] field.
pub fn set_license(self, license: impl Into<String>) -> Self {
pub fn with_license(self, license: impl Into<String>) -> Self {
let license = license.into();
if license.is_empty() {
return self;
Expand Down
60 changes: 43 additions & 17 deletions models/cuboid/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,44 @@
#[fj::model]
pub fn model(
#[param(default = 3.0)] x: f64,
#[param(default = 2.0)] y: f64,
#[param(default = 1.0)] z: f64,
) -> fj::Shape {
#[rustfmt::skip]
let rectangle = fj::Sketch::from_points(vec![
[-x / 2., -y / 2.],
[ x / 2., -y / 2.],
[ x / 2., y / 2.],
[-x / 2., y / 2.],
]).with_color([100,255,0,200]);

let cuboid = fj::Sweep::from_path(rectangle.into(), [0., 0., z]);

cuboid.into()
use fj::{
ArgumentMetadata, ContextExt, HostExt, Model, ModelMetadata, PluginMetadata,
};

fj::register_model!(|host| {
host.register_model(Cuboid);

Ok(PluginMetadata::new(
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
))
});

pub struct Cuboid;

impl Model for Cuboid {
fn shape(
&self,
ctx: &dyn fj::Context,
) -> Result<fj::Shape, Box<dyn std::error::Error + Send + Sync>> {
let x: f64 = ctx.parse_optional_argument("x")?.unwrap_or(3.0);
let y: f64 = ctx.parse_optional_argument("y")?.unwrap_or(2.0);
let z: f64 = ctx.parse_optional_argument("z")?.unwrap_or(1.0);

#[rustfmt::skip]
let rectangle = fj::Sketch::from_points(vec![
[-x / 2., -y / 2.],
[ x / 2., -y / 2.],
[ x / 2., y / 2.],
[-x / 2., y / 2.],
]).with_color([100,255,0,200]);

let cuboid = fj::Sweep::from_path(rectangle.into(), [0., 0., z]);

Ok(cuboid.into())
}

fn metadata(&self) -> ModelMetadata {
ModelMetadata::new("Cuboid")
.with_argument(ArgumentMetadata::new("x").with_default_value("3.0"))
.with_argument(ArgumentMetadata::new("y").with_default_value("2.0"))
.with_argument(ArgumentMetadata::new("z").with_default_value("1.0"))
}
}
64 changes: 52 additions & 12 deletions models/spacer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,56 @@
use fj::syntax::*;
use fj::{
syntax::*, ArgumentMetadata, ContextExt, HostExt, Model, ModelMetadata,
PluginMetadata,
};

#[fj::model]
pub fn model(
#[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));
fj::register_model!(|host| {
host.register_model(Spacer);

let footprint = outer_edge.difference(&inner_edge);
let spacer = footprint.sweep([0., 0., height]);
Ok(PluginMetadata::new(
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
))
});

spacer.into()
struct Spacer;

impl Model for Spacer {
fn shape(
&self,
ctx: &dyn fj::Context,
) -> Result<fj::Shape, Box<dyn std::error::Error + Send + Sync>> {
let outer: f64 = ctx.parse_optional_argument("outer")?.unwrap_or(1.0);
let inner: f64 = ctx.parse_optional_argument("inner")?.unwrap_or(0.5);
let height: f64 = ctx.parse_optional_argument("height")?.unwrap_or(1.0);

if outer < inner * 1.01 {
todo!("Return a suitable error");
}
if inner > outer * 0.99 {
todo!("Return a suitable error");
}

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]);

Ok(spacer.into())
}

fn metadata(&self) -> ModelMetadata {
ModelMetadata::new("Spacer")
.with_argument(
ArgumentMetadata::new("outer").with_default_value("1.0"),
)
.with_argument(
ArgumentMetadata::new("inner").with_default_value("0.5"),
)
.with_argument(
ArgumentMetadata::new("height").with_default_value("1.0"),
)
}
}
111 changes: 78 additions & 33 deletions models/star/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,85 @@
use std::f64::consts::PI;

#[fj::model]
pub fn model(
#[param(default = 5, min = 3)] num_points: u64,
#[param(default = 1.0, min = 1.0)] r1: f64,
#[param(default = 2.0, min = 2.0)] r2: f64,
#[param(default = 1.0)] h: f64,
) -> fj::Shape {
let num_vertices = num_points * 2;
let vertex_iter = (0..num_vertices).map(|i| {
let angle =
fj::Angle::from_rad(2. * PI / num_vertices as f64 * i as f64);
let radius = if i % 2 == 0 { r1 } else { r2 };
(angle, radius)
});

// Now that we got that iterator prepared, generating the vertices is just a
// bit of trigonometry.
let mut outer = Vec::new();
let mut inner = Vec::new();
for (angle, radius) in vertex_iter {
let (sin, cos) = angle.rad().sin_cos();

let x = cos * radius;
let y = sin * radius;

outer.push([x, y]);
inner.push([x / 2., y / 2.]);
}
use fj::{
ArgumentMetadata, ContextExt, HostExt, Model, ModelMetadata, PluginMetadata,
};

fj::register_model!(|host| {
host.register_model(Star);

Ok(PluginMetadata::new(
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION"),
))
});

struct Star;

impl Model for Star {
fn shape(
&self,
ctx: &dyn fj::Context,
) -> Result<fj::Shape, Box<dyn std::error::Error + Send + Sync>> {
let num_points: u64 =
ctx.parse_optional_argument("num_points")?.unwrap_or(5);
let r1: f64 = ctx.parse_optional_argument("r1")?.unwrap_or(1.0);
let r2: f64 = ctx.parse_optional_argument("r2")?.unwrap_or(2.0);
let h: f64 = ctx.parse_optional_argument("h")?.unwrap_or(1.0);

if num_points < 3 {
todo!();
}
if r1 < 1.0 {
todo!();
}
if r2 < 2.0 {
todo!();
}

let num_vertices = num_points * 2;
let vertex_iter = (0..num_vertices).map(|i| {
let angle =
fj::Angle::from_rad(2. * PI / num_vertices as f64 * i as f64);
let radius = if i % 2 == 0 { r1 } else { r2 };
(angle, radius)
});

let outer = fj::Sketch::from_points(outer);
let inner = fj::Sketch::from_points(inner);
// Now that we got that iterator prepared, generating the vertices is just a
// bit of trigonometry.
let mut outer = Vec::new();
let mut inner = Vec::new();
for (angle, radius) in vertex_iter {
let (sin, cos) = angle.rad().sin_cos();

let footprint = fj::Difference2d::from_shapes([outer.into(), inner.into()]);
let x = cos * radius;
let y = sin * radius;

let star = fj::Sweep::from_path(footprint.into(), [0., 0., h]);
outer.push([x, y]);
inner.push([x / 2., y / 2.]);
}

star.into()
let outer = fj::Sketch::from_points(outer);
let inner = fj::Sketch::from_points(inner);

let footprint =
fj::Difference2d::from_shapes([outer.into(), inner.into()]);

let star = fj::Sweep::from_path(footprint.into(), [0., 0., h]);

Ok(star.into())
}

fn metadata(&self) -> ModelMetadata {
ModelMetadata::new("Star")
.with_argument(
ArgumentMetadata::new("num_points").with_default_value("5"),
)
.with_argument(
ArgumentMetadata::new("r1").with_default_value("1.0"),
)
.with_argument(
ArgumentMetadata::new("r2").with_default_value("2.0"),
)
.with_argument(ArgumentMetadata::new("h").with_default_value("1.0"))
}
}
4 changes: 4 additions & 0 deletions models/test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
name = "test"
version = "0.1.0"
edition = "2021"
description = "An example model"
homepage = "https://www.fornjot.app/"
repository = "https://github.com/hannobraun/fornjot"
license = "0BSD"

[lib]
crate-type = ["cdylib"]
Expand Down
47 changes: 35 additions & 12 deletions models/test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,41 @@
use std::f64::consts::PI;

use fj::{syntax::*, Angle};

#[fj::model]
pub fn model() -> fj::Shape {
let a = star(4, 1., [0, 255, 0, 200]);
let b = star(5, -1., [255, 0, 0, 255])
.rotate([1., 1., 1.], Angle::from_deg(45.))
.translate([3., 3., 1.]);
let c = spacer().translate([6., 6., 1.]);

let group = a.group(&b).group(&c);
use fj::{syntax::*, Angle, HostExt, ModelMetadata, PluginMetadata};

fj::register_model!(|host| {
host.register_model(Test);

Ok(
PluginMetadata::new(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"))
.with_short_description(env!("CARGO_PKG_DESCRIPTION"))
.with_description(include_str!("../README.md"))
.with_homepage(env!("CARGO_PKG_HOMEPAGE"))
.with_repository(env!("CARGO_PKG_REPOSITORY"))
.with_license(env!("CARGO_PKG_LICENSE")),
)
});

struct Test;

impl fj::Model for Test {
fn shape(
&self,
_ctx: &dyn fj::Context,
) -> Result<fj::Shape, Box<dyn std::error::Error + Send + Sync>> {
let a = star(4, 1., [0, 255, 0, 200]);
let b = star(5, -1., [255, 0, 0, 255])
.rotate([1., 1., 1.], Angle::from_deg(45.))
.translate([3., 3., 1.]);
let c = spacer().translate([6., 6., 1.]);

let group = a.group(&b).group(&c);

Ok(group.into())
}

group.into()
fn metadata(&self) -> ModelMetadata {
ModelMetadata::new("Test")
}
}

fn star(num_points: u64, height: f64, color: [u8; 4]) -> fj::Shape {
Expand Down

0 comments on commit 67a2337

Please sign in to comment.