From 67a23376232fea62aaba6757967e690b831c5da2 Mon Sep 17 00:00:00 2001 From: Michael-F-Bryan Date: Thu, 28 Jul 2022 23:39:33 +0800 Subject: [PATCH] Migrated all models over to the new API --- crates/fj/src/host.rs | 1 + crates/fj/src/metadata.rs | 10 ++-- models/cuboid/src/lib.rs | 60 +++++++++++++++------ models/spacer/src/lib.rs | 64 +++++++++++++++++----- models/star/src/lib.rs | 111 ++++++++++++++++++++++++++------------ models/test/Cargo.toml | 4 ++ models/test/src/lib.rs | 47 +++++++++++----- 7 files changed, 218 insertions(+), 79 deletions(-) diff --git a/crates/fj/src/host.rs b/crates/fj/src/host.rs index fbd8154bbd..ba712fb846 100644 --- a/crates/fj/src/host.rs +++ b/crates/fj/src/host.rs @@ -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); } diff --git a/crates/fj/src/metadata.rs b/crates/fj/src/metadata.rs index 4ae59231fe..b4fff07303 100644 --- a/crates/fj/src/metadata.rs +++ b/crates/fj/src/metadata.rs @@ -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, ) -> Self { @@ -63,7 +63,7 @@ impl PluginMetadata { } /// Set the [`PluginMetadata::description`] field. - pub fn set_description(self, description: impl Into) -> Self { + pub fn with_description(self, description: impl Into) -> Self { let description = description.into(); if description.is_empty() { return self; @@ -76,7 +76,7 @@ impl PluginMetadata { } /// Set the [`PluginMetadata::homepage`] field. - pub fn set_homepage(self, homepage: impl Into) -> Self { + pub fn with_homepage(self, homepage: impl Into) -> Self { let homepage = homepage.into(); if homepage.is_empty() { return self; @@ -89,7 +89,7 @@ impl PluginMetadata { } /// Set the [`PluginMetadata::repository`] field. - pub fn set_repository(self, repository: impl Into) -> Self { + pub fn with_repository(self, repository: impl Into) -> Self { let repository = repository.into(); if repository.is_empty() { return self; @@ -102,7 +102,7 @@ impl PluginMetadata { } /// Set the [`PluginMetadata::license`] field. - pub fn set_license(self, license: impl Into) -> Self { + pub fn with_license(self, license: impl Into) -> Self { let license = license.into(); if license.is_empty() { return self; diff --git a/models/cuboid/src/lib.rs b/models/cuboid/src/lib.rs index 6505e36121..2c2b3cd459 100644 --- a/models/cuboid/src/lib.rs +++ b/models/cuboid/src/lib.rs @@ -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> { + 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")) + } } diff --git a/models/spacer/src/lib.rs b/models/spacer/src/lib.rs index 98724904db..51a86d41e8 100644 --- a/models/spacer/src/lib.rs +++ b/models/spacer/src/lib.rs @@ -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> { + 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"), + ) + } } diff --git a/models/star/src/lib.rs b/models/star/src/lib.rs index 3d17756808..787b925718 100644 --- a/models/star/src/lib.rs +++ b/models/star/src/lib.rs @@ -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> { + 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")) + } } diff --git a/models/test/Cargo.toml b/models/test/Cargo.toml index d6bd468542..dd9fa6bc02 100644 --- a/models/test/Cargo.toml +++ b/models/test/Cargo.toml @@ -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"] diff --git a/models/test/src/lib.rs b/models/test/src/lib.rs index 76f955cf66..d68df86624 100644 --- a/models/test/src/lib.rs +++ b/models/test/src/lib.rs @@ -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> { + 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 {