Skip to content

Commit

Permalink
Merge pull request #1872 from hannobraun/tolerance
Browse files Browse the repository at this point in the history
Compute tolerance manually, if not provided via CLI
  • Loading branch information
hannobraun authored Jun 12, 2023
2 parents ebcb223 + e4efdb0 commit 2d490eb
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 16 deletions.
26 changes: 25 additions & 1 deletion crates/fj/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
use std::path::PathBuf;
use std::{num::ParseFloatError, path::PathBuf, str::FromStr};

use fj_core::algorithms::approx::{InvalidTolerance, Tolerance};
use fj_math::Scalar;

/// 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<PathBuf>,

/// How much the export can deviate from the original model
#[arg(short, long, value_parser = parse_tolerance)]
pub tolerance: Option<Tolerance>,
}

impl Args {
Expand All @@ -17,3 +24,20 @@ impl Args {
<Self as clap::Parser>::parse()
}
}

fn parse_tolerance(input: &str) -> Result<Tolerance, ArgsError> {
let tolerance = f64::from_str(input)?;
let tolerance = Scalar::from_f64(tolerance);
let tolerance = Tolerance::from_scalar(tolerance)?;

Ok(tolerance)
}

#[derive(Debug, thiserror::Error)]
pub enum ArgsError {
#[error("Error parsing tolerance")]
ParseTolerance(#[from] ParseFloatError),

#[error(transparent)]
InvalidTolerance(#[from] InvalidTolerance),
}
39 changes: 31 additions & 8 deletions crates/fj/src/handle_model.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::ops::Deref;

use fj_core::algorithms::{
approx::Tolerance, bounding_volume::BoundingVolume,
approx::{InvalidTolerance, Tolerance},
bounding_volume::BoundingVolume,
triangulate::Triangulate,
};
use fj_interop::model::Model;
use fj_math::{Aabb, Point};
use fj_math::{Aabb, Point, Scalar};

use crate::Args;

Expand All @@ -17,21 +18,39 @@ use crate::Args;
///
/// 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<M>(
model: impl Deref<Target = M>,
tolerance: impl Into<Tolerance>,
) -> Result
pub fn handle_model<M>(model: impl Deref<Target = M>) -> Result
where
for<'r> (&'r M, Tolerance): Triangulate,
M: BoundingVolume<3>,
{
let args = Args::parse();

let aabb = model.aabb().unwrap_or(Aabb {
min: Point::origin(),
max: Point::origin(),
});
let mesh = (model.deref(), tolerance.into()).triangulate();

let args = Args::parse();
let tolerance = match args.tolerance {
None => {
// Compute a reasonable default for the tolerance value. To do
// this, we just look at the smallest non-zero extent of the
// bounding box and divide that by some value.

let mut min_extent = Scalar::MAX;
for extent in aabb.size().components {
if extent > Scalar::ZERO && extent < min_extent {
min_extent = extent;
}
}

let tolerance = min_extent / Scalar::from_f64(1000.);
Tolerance::from_scalar(tolerance)?
}
Some(user_defined_tolerance) => user_defined_tolerance,
};

let mesh = (model.deref(), tolerance).triangulate();

if let Some(path) = args.export {
crate::export::export(&mesh, &path)?;
return Ok(());
Expand All @@ -57,4 +76,8 @@ pub enum Error {
/// Error exporting model
#[error("Error exporting model")]
Export(#[from] crate::export::Error),

/// Invalid tolerance
#[error(transparent)]
Tolerance(#[from] InvalidTolerance),
}
9 changes: 2 additions & 7 deletions models/cuboid/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
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 = 1.;
handle_model(cuboid, tolerance)?;

let model = cuboid::cuboid(3., 2., 1.);
handle_model(model)?;
Ok(())
}

0 comments on commit 2d490eb

Please sign in to comment.