use std::{error::Error as _, fmt};
use fj_core::{
algorithms::{
approx::{InvalidTolerance, Tolerance},
bounding_volume::BoundingVolume,
triangulate::Triangulate,
},
validation::{ValidationConfig, ValidationErrors},
Core,
};
use fj_interop::Model;
use fj_math::{Aabb, Point, Scalar};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use crate::Args;
#[derive(Default)]
pub struct Instance {
pub core: Core,
}
impl Instance {
pub fn new() -> Self {
Self::default()
}
pub fn with_validation_config(config: ValidationConfig) -> Self {
let core = fj_core::Core::with_validation_config(config);
Self { core }
}
pub fn process_model<M>(&mut self, model: &M) -> Result
where
for<'r> (&'r M, Tolerance): Triangulate,
M: BoundingVolume<3>,
{
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer())
.with(tracing_subscriber::EnvFilter::from_default_env())
.init();
let args = Args::parse();
if !args.ignore_validation {
self.core.layers.validation.take_errors()?;
}
let aabb = model.aabb(&self.core.layers.geometry).unwrap_or(Aabb {
min: Point::origin(),
max: Point::origin(),
});
let tolerance = match args.tolerance {
None => {
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, tolerance).triangulate(&mut self.core);
if let Some(path) = args.export {
crate::export::export(&mesh, &path)?;
return Ok(());
}
let model = Model { mesh, aabb };
crate::window::display(model, false)?;
Ok(())
}
}
pub type Result = std::result::Result<(), Error>;
#[derive(thiserror::Error)]
pub enum Error {
#[error("Failed to set up logger")]
Tracing(#[from] tracing::subscriber::SetGlobalDefaultError),
#[error("Error displaying model")]
Display(#[from] crate::window::Error),
#[error("Error exporting model")]
Export(#[from] crate::export::Error),
#[error(transparent)]
Tolerance(#[from] InvalidTolerance),
#[error(transparent)]
Validation(#[from] ValidationErrors),
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{self}")?;
let mut source = self.source();
if source.is_some() {
write!(f, "\n\nCaused by:")?;
}
let mut i = 0;
while let Some(s) = source {
write!(f, "\n {i}: {s}")?;
source = s.source();
i += 1;
}
Ok(())
}
}