use clap::{Parser, Subcommand};
use std::{
env::consts::{ARCH, OS},
time::Instant,
};
mod convert;
mod defeature;
mod diff;
mod error;
mod extract;
mod io;
mod log;
mod mesh;
mod metrics;
mod remesh;
mod segment;
mod smooth;
use convert::{ConvertSubcommand, convert_mesh, convert_segmentation};
use defeature::defeature;
use diff::diff;
use error::ErrorWrapper;
use extract::extract;
use mesh::{Element, MeshSubcommand};
use metrics::{MetricsArgs, metrics};
use remesh::{MeshRemeshCommands, remesh};
use segment::{SegmentArgs, segment};
use smooth::{SmoothArgs, smooth};
macro_rules! about {
() => {
format!(
"
@@@@@@@@@@@@@@@@
@@@@ @@@@@@@@@@
@@@@ @@@@@@@@@@@ \x1b[1;4m{}: Automatic mesh generation\x1b[0m
@@@@ @@@@@@@@@@@@
@@ @@ @@ {}
@@ @@ @@ {}
@@@@@@@@@@@@ @@@ {}
@@@@@@@@@@@ @@@@ {}
@@@@@@@@@@ @@@@@ @
@@@@@@@@@@@@@@@@",
env!("CARGO_PKG_NAME"),
format!("v{} {} {}", env!("CARGO_PKG_VERSION"), OS, ARCH),
format!(
"build {} {}",
option_env!("GIT_COMMIT_HASH").unwrap_or(""),
env!("BUILD_TIME"),
),
env!("CARGO_PKG_AUTHORS").split(':').next().unwrap_or(""),
env!("CARGO_PKG_AUTHORS").split(':').nth(1).unwrap_or(""),
)
};
}
#[derive(Parser)]
#[command(about = about!(), arg_required_else_help = true, version)]
struct Args {
#[command(subcommand)]
command: Option<Commands>,
#[arg(global = true, long, value_name = "FILE")]
log: Option<String>,
#[arg(action, global = true, long, short)]
quiet: bool,
}
#[derive(Subcommand)]
enum Commands {
Convert {
#[command(subcommand)]
subcommand: ConvertSubcommand,
},
Defeature {
#[arg(long, short, value_name = "FILE")]
input: String,
#[arg(long, short, value_name = "FILE")]
output: String,
#[arg(long, short, value_name = "MIN")]
min: usize,
#[arg(long, short = 'x', value_name = "NEL")]
nelx: Option<usize>,
#[arg(long, short = 'y', value_name = "NEL")]
nely: Option<usize>,
#[arg(long, short = 'z', value_name = "NEL")]
nelz: Option<usize>,
},
Diff {
#[arg(long, num_args = 2, short, value_delimiter = ' ', value_name = "FILE")]
input: Vec<String>,
#[arg(long, short, value_name = "FILE")]
output: String,
#[arg(long, short = 'x', value_name = "NEL")]
nelx: Option<usize>,
#[arg(long, short = 'y', value_name = "NEL")]
nely: Option<usize>,
#[arg(long, short = 'z', value_name = "NEL")]
nelz: Option<usize>,
},
Extract {
#[arg(long, short, value_name = "FILE")]
input: String,
#[arg(long, short, value_name = "FILE")]
output: String,
#[arg(long, short = 'x', value_name = "NEL")]
nelx: Option<usize>,
#[arg(long, short = 'y', value_name = "NEL")]
nely: Option<usize>,
#[arg(long, short = 'z', value_name = "NEL")]
nelz: Option<usize>,
#[arg(long, value_name = "MIN")]
xmin: usize,
#[arg(long, value_name = "MAX")]
xmax: usize,
#[arg(long, value_name = "MIN")]
ymin: usize,
#[arg(long, value_name = "MAX")]
ymax: usize,
#[arg(long, value_name = "MIN")]
zmin: usize,
#[arg(long, value_name = "MAX")]
zmax: usize,
},
Mesh {
#[command(subcommand)]
subcommand: MeshSubcommand,
},
Metrics(MetricsArgs),
Remesh {
#[arg(long, short, value_name = "FILE")]
input: String,
#[arg(long, short, value_name = "FILE")]
output: String,
#[command(subcommand)]
mode: Option<MeshRemeshCommands>,
},
Segment(SegmentArgs),
Smooth(SmoothArgs),
}
fn main() -> Result<(), ErrorWrapper> {
let time = Instant::now();
let args = Args::parse();
if let Some(path) = &args.log {
log::set_logfile(path)?;
log::write_log(&about!());
log::write_log("");
}
let quiet = args.quiet;
let result = match args.command {
Some(Commands::Convert { subcommand }) => match subcommand {
ConvertSubcommand::Mesh(args) => convert_mesh(args, quiet),
ConvertSubcommand::Segmentation(args) => convert_segmentation(
args.input,
args.output,
args.nelx,
args.nely,
args.nelz,
quiet,
),
},
Some(Commands::Defeature {
input,
output,
min,
nelx,
nely,
nelz,
}) => defeature(input, output, min, nelx, nely, nelz, quiet),
Some(Commands::Diff {
input,
output,
nelx,
nely,
nelz,
}) => diff(input, output, nelx, nely, nelz, quiet),
Some(Commands::Extract {
input,
output,
nelx,
nely,
nelz,
xmin,
xmax,
ymin,
ymax,
zmin,
zmax,
}) => extract(
input, output, nelx, nely, nelz, xmin, xmax, ymin, ymax, zmin, zmax, quiet,
),
Some(Commands::Mesh { subcommand }) => match subcommand {
MeshSubcommand::Hex(args) => mesh::mesh(Element::Hexahedra, args, quiet),
MeshSubcommand::Tri(args) => mesh::mesh(Element::Triangles, args, quiet),
},
Some(Commands::Metrics(args)) => metrics(args, quiet),
Some(Commands::Remesh {
input,
output,
mode,
}) => remesh(input, output, mode, quiet),
Some(Commands::Segment(args)) => segment(args, quiet),
Some(Commands::Smooth(args)) => smooth(args, quiet),
None => return Ok(()),
};
crate::echo!(quiet, " \x1b[1;98mTotal\x1b[0m {:?}", time.elapsed());
result
}