diff --git a/Cargo.lock b/Cargo.lock index 316cc723c..dc963a304 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -629,10 +629,7 @@ dependencies = [ name = "cuboid" version = "0.1.0" dependencies = [ - "anyhow", - "clap", "fj", - "itertools", ] [[package]] @@ -781,12 +778,14 @@ dependencies = [ name = "fj" version = "0.46.0" dependencies = [ + "clap", "fj-core", "fj-export", "fj-interop", "fj-math", "fj-viewer", "fj-window", + "thiserror", ] [[package]] diff --git a/crates/fj-window/src/lib.rs b/crates/fj-window/src/lib.rs index 0a317a64b..1b0d14de4 100644 --- a/crates/fj-window/src/lib.rs +++ b/crates/fj-window/src/lib.rs @@ -13,4 +13,4 @@ mod run; mod window; -pub use self::run::run; +pub use self::run::{run, Error}; diff --git a/crates/fj/Cargo.toml b/crates/fj/Cargo.toml index 4d007ffdf..987895b85 100644 --- a/crates/fj/Cargo.toml +++ b/crates/fj/Cargo.toml @@ -10,6 +10,7 @@ license.workspace = true keywords.workspace = true categories.workspace = true + [dependencies] fj-core.workspace = true fj-export.workspace = true @@ -17,3 +18,8 @@ fj-interop.workspace = true fj-math.workspace = true fj-viewer.workspace = true fj-window.workspace = true +thiserror = "1.0.40" + +[dependencies.clap] +version = "4.3.1" +features = ["derive"] diff --git a/crates/fj/src/args.rs b/crates/fj/src/args.rs new file mode 100644 index 000000000..bf8566764 --- /dev/null +++ b/crates/fj/src/args.rs @@ -0,0 +1,19 @@ +use std::path::PathBuf; + +/// Standardized CLI for Fornjot models +#[derive(clap::Parser)] +pub struct Args { + /// Export model to this path + #[arg(short, long, value_name = "PATH")] + pub export: Option, +} + +impl Args { + /// Parse the command-line arguments + /// + /// Convenience method that saves the caller from having to import the + /// `clap::Parser` trait. + pub fn parse() -> Self { + ::parse() + } +} diff --git a/crates/fj/src/handle_model.rs b/crates/fj/src/handle_model.rs new file mode 100644 index 000000000..5fca60f3e --- /dev/null +++ b/crates/fj/src/handle_model.rs @@ -0,0 +1,47 @@ +use std::ops::Deref; + +use fj_core::algorithms::{approx::Tolerance, triangulate::Triangulate}; + +use crate::Args; + +/// Export or display a model, according to CLI arguments +/// +/// This function is intended to be called by applications that define a model +/// and want to provide a standardized CLI interface for dealing with that +/// model. +/// +/// This function is used by Fornjot's own testing infrastructure, but is useful +/// beyond that, when using Fornjot directly to define a model. +pub fn handle_model( + model: impl Deref, + tolerance: impl Into, +) -> Result +where + for<'r> (&'r Model, Tolerance): Triangulate, +{ + let mesh = (model.deref(), tolerance.into()).triangulate(); + + let args = Args::parse(); + if let Some(path) = args.export { + crate::export::export(&mesh, &path)?; + } else { + crate::window::run(mesh, false)?; + } + + Ok(()) +} + +/// Return value of [`handle_model`] +pub type Result = std::result::Result<(), Error>; + +/// Error returned by [`handle_model`] +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Error displaying model + #[error("Error displaying model")] + Display(#[from] crate::window::Error), + + /// Error exporting model + #[error("Error exporting model")] + Export(#[from] crate::export::Error), +} diff --git a/crates/fj/src/lib.rs b/crates/fj/src/lib.rs index 1df53c170..8224c3599 100644 --- a/crates/fj/src/lib.rs +++ b/crates/fj/src/lib.rs @@ -11,6 +11,14 @@ #![warn(missing_docs)] +mod args; +mod handle_model; + +pub use self::{ + args::Args, + handle_model::{handle_model, Error, Result}, +}; + pub use fj_core as core; pub use fj_export as export; pub use fj_interop as interop; diff --git a/models/cuboid/Cargo.toml b/models/cuboid/Cargo.toml index 09a5bd5dd..42746d61c 100644 --- a/models/cuboid/Cargo.toml +++ b/models/cuboid/Cargo.toml @@ -3,14 +3,5 @@ name = "cuboid" version = "0.1.0" edition = "2021" - -[dependencies] -anyhow = "1.0.71" -itertools = "0.10.5" - -[dependencies.clap] -version = "4.3.1" -features = ["derive"] - [dependencies.fj] path = "../../crates/fj" diff --git a/models/cuboid/src/main.rs b/models/cuboid/src/main.rs index 51a03f31f..3fbe0d285 100644 --- a/models/cuboid/src/main.rs +++ b/models/cuboid/src/main.rs @@ -1,41 +1,12 @@ -use std::{ops::Deref, path::PathBuf}; - -use fj::core::algorithms::{approx::Tolerance, triangulate::Triangulate}; - -fn main() -> anyhow::Result<()> { - let args = Args::parse(); +use fj::handle_model; +fn main() -> fj::Result { let cuboid = cuboid::cuboid(3., 2., 1.); // The tolerance makes no difference for this model, as there aren't any // curves. - let tolerance = Tolerance::from_scalar(1.)?; - - let mesh = (cuboid.deref(), tolerance).triangulate(); - - if let Some(path) = args.export { - fj::export::export(&mesh, &path)?; - } else { - fj::window::run(mesh, false)?; - } + let tolerance = 1.; + handle_model(cuboid, tolerance)?; Ok(()) } - -/// Standardized CLI for Fornjot models -#[derive(clap::Parser)] -pub struct Args { - /// Export model to this path - #[arg(short, long, value_name = "PATH")] - pub export: Option, -} - -impl Args { - /// Parse the command-line arguments - /// - /// Convenience method that saves the caller from having to import the - /// `clap::Parser` trait. - pub fn parse() -> Self { - ::parse() - } -}