Skip to content

Commit 3570753

Browse files
committed
Move some CLI arguments to own post-processing struct
1 parent 039f02c commit 3570753

1 file changed

Lines changed: 66 additions & 73 deletions

File tree

splashsurf/src/reconstruction.rs

Lines changed: 66 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use splashsurf_lib::{density_map, Index, Real};
1515
use std::convert::TryFrom;
1616
use std::path::PathBuf;
1717

18+
use arguments::*;
19+
1820
// TODO: Detect smallest index type (i.e. check if ok to use i32 as index)
1921

2022
static ARGS_IO: &str = "Input/output";
@@ -317,46 +319,66 @@ mod arguments {
317319
use std::str::FromStr;
318320
use walkdir::WalkDir;
319321

322+
pub struct ReconstructionRunnerPostprocessingArgs {
323+
pub check_mesh: bool,
324+
pub compute_normals: bool,
325+
pub sph_normals: bool,
326+
pub interpolate_attributes: Vec<String>,
327+
}
328+
320329
/// All arguments that can be supplied to the surface reconstruction tool converted to useful types
321330
pub struct ReconstructionRunnerArgs {
322331
pub params: splashsurf_lib::Parameters<f64>,
323332
pub use_double_precision: bool,
324-
pub check_mesh: bool,
325333
pub io_params: io::FormatParameters,
334+
pub postprocessing: ReconstructionRunnerPostprocessingArgs,
335+
}
336+
337+
fn try_aabb_from_min_max(
338+
min: &Vec<f64>,
339+
max: &Vec<f64>,
340+
error_str: &'static str,
341+
) -> Result<Aabb3d<f64>, anyhow::Error> {
342+
// This should already be ensured by StructOpt parsing
343+
assert_eq!(min.len(), 3);
344+
assert_eq!(max.len(), 3);
345+
346+
let aabb = Aabb3d::new(
347+
Vector3::from_iterator(min.clone()),
348+
Vector3::from_iterator(max.clone()),
349+
);
350+
351+
if !aabb.is_consistent() {
352+
return Err(anyhow!("The user specified {error_str} min/max values are inconsistent! min: {:?} max: {:?}", aabb.min().as_slice(), aabb.max().as_slice()));
353+
}
354+
355+
if aabb.is_degenerate() {
356+
return Err(anyhow!(
357+
"The user specified {error_str} is degenerate! min: {:?} max: {:?}",
358+
aabb.min().as_slice(),
359+
aabb.max().as_slice()
360+
));
361+
}
362+
363+
Ok(aabb)
326364
}
327365

328366
// Convert raw command line arguments to more useful types
329367
impl TryFrom<&ReconstructSubcommandArgs> for ReconstructionRunnerArgs {
330368
type Error = anyhow::Error;
331369

332370
fn try_from(args: &ReconstructSubcommandArgs) -> Result<Self, Self::Error> {
333-
// Convert domain args to aabb
334-
let domain_aabb = match (&args.domain_min, &args.domain_max) {
335-
(Some(domain_min), Some(domain_max)) => {
336-
// This should already be ensured by StructOpt parsing
337-
assert_eq!(domain_min.len(), 3);
338-
assert_eq!(domain_max.len(), 3);
339-
340-
let aabb = Aabb3d::new(
341-
Vector3::from_iterator(domain_min.clone()),
342-
Vector3::from_iterator(domain_max.clone()),
343-
);
344-
345-
if !aabb.is_consistent() {
346-
return Err(anyhow!("The user specified domain min/max values are inconsistent! min: {:?} max: {:?}", aabb.min().as_slice(), aabb.max().as_slice()));
347-
}
348-
349-
if aabb.is_degenerate() {
350-
return Err(anyhow!(
351-
"The user specified domain is degenerate! min: {:?} max: {:?}",
352-
aabb.min().as_slice(),
353-
aabb.max().as_slice()
354-
));
355-
}
356-
357-
Some(aabb)
358-
}
359-
_ => None,
371+
// Convert particle domain args to aabb
372+
let domain_aabb = if let (Some(domain_min), Some(domain_max)) =
373+
(&args.domain_min, &args.domain_max)
374+
{
375+
Some(try_aabb_from_min_max(
376+
domain_min,
377+
domain_max,
378+
"particle AABB",
379+
)?)
380+
} else {
381+
None
360382
};
361383

362384
// Scale kernel radius and cube size by particle radius
@@ -421,11 +443,18 @@ mod arguments {
421443
splashsurf_lib::initialize_thread_pool(num_threads)?;
422444
}
423445

446+
let postprocessing = ReconstructionRunnerPostprocessingArgs {
447+
check_mesh: args.check_mesh.into_bool(),
448+
compute_normals: args.normals.into_bool(),
449+
sph_normals: args.sph_normals.into_bool(),
450+
interpolate_attributes: args.interpolate_attributes.clone(),
451+
};
452+
424453
Ok(ReconstructionRunnerArgs {
425454
params,
426455
use_double_precision: args.double_precision.into_bool(),
427-
check_mesh: args.check_mesh.into_bool(),
428456
io_params: io::FormatParameters::default(),
457+
postprocessing,
429458
})
430459
}
431460
}
@@ -439,12 +468,6 @@ mod arguments {
439468
output_density_map_grid_file: Option<PathBuf>,
440469
output_octree_file: Option<PathBuf>,
441470
sequence_range: (Option<usize>, Option<usize>),
442-
/// Whether to enable normal computation for all files
443-
compute_normals: bool,
444-
/// Whether to use SPH interpolation to compute the normals for all files
445-
sph_normals: bool,
446-
/// Additional attributes to load and interpolate to surface
447-
attributes: Vec<String>,
448471
}
449472

450473
impl ReconstructionRunnerPathCollection {
@@ -457,9 +480,6 @@ mod arguments {
457480
output_density_map_grid_file: Option<P>,
458481
output_octree_file: Option<P>,
459482
sequence_range: (Option<usize>, Option<usize>),
460-
compute_normals: bool,
461-
sph_normals: bool,
462-
attributes: Vec<String>,
463483
) -> Result<Self, anyhow::Error> {
464484
let input_file = input_file.into();
465485
let output_base_path = output_base_path.map(|p| p.into());
@@ -504,9 +524,6 @@ mod arguments {
504524
.map(|f| output_base_path.join(f)),
505525
output_octree_file: output_octree_file.map(|f| output_base_path.join(f)),
506526
sequence_range,
507-
compute_normals,
508-
sph_normals,
509-
attributes,
510527
})
511528
} else {
512529
Ok(Self {
@@ -517,9 +534,6 @@ mod arguments {
517534
output_density_map_grid_file,
518535
output_octree_file,
519536
sequence_range,
520-
compute_normals,
521-
sph_normals,
522-
attributes,
523537
})
524538
}
525539
}
@@ -605,9 +619,6 @@ mod arguments {
605619
None,
606620
None,
607621
None,
608-
self.compute_normals,
609-
self.sph_normals,
610-
self.attributes.clone(),
611622
));
612623
}
613624
}
@@ -634,9 +645,6 @@ mod arguments {
634645
self.output_density_map_points_file.clone(),
635646
self.output_density_map_grid_file.clone(),
636647
self.output_octree_file.clone(),
637-
self.compute_normals,
638-
self.sph_normals,
639-
self.attributes.clone(),
640648
);
641649
1
642650
]
@@ -737,9 +745,6 @@ mod arguments {
737745
args.output_dm_grid.clone(),
738746
args.output_octree.clone(),
739747
(args.start_index, args.end_index),
740-
args.normals.into_bool(),
741-
args.sph_normals.into_bool(),
742-
args.interpolate_attributes.clone(),
743748
)
744749
}
745750
}
@@ -752,12 +757,6 @@ mod arguments {
752757
pub output_density_map_points_file: Option<PathBuf>,
753758
pub output_density_map_grid_file: Option<PathBuf>,
754759
pub output_octree_file: Option<PathBuf>,
755-
/// Whether to enable normal computation
756-
pub compute_normals: bool,
757-
/// Whether to use SPH interpolation to compute the normals
758-
pub sph_normals: bool,
759-
/// Additional attributes to load and interpolate to surface
760-
pub attributes: Vec<String>,
761760
}
762761

763762
impl ReconstructionRunnerPaths {
@@ -767,19 +766,13 @@ mod arguments {
767766
output_density_map_points_file: Option<PathBuf>,
768767
output_density_map_grid_file: Option<PathBuf>,
769768
output_octree_file: Option<PathBuf>,
770-
compute_normals: bool,
771-
sph_normals: bool,
772-
attributes: Vec<String>,
773769
) -> Self {
774770
ReconstructionRunnerPaths {
775771
input_file,
776772
output_file,
777773
output_density_map_points_file,
778774
output_density_map_grid_file,
779775
output_octree_file,
780-
compute_normals,
781-
sph_normals,
782-
attributes,
783776
}
784777
}
785778
}
@@ -796,7 +789,7 @@ pub(crate) fn reconstruction_pipeline(
796789
paths,
797790
&args.params,
798791
&args.io_params,
799-
args.check_mesh,
792+
&args.postprocessing,
800793
)?;
801794
} else {
802795
info!("Using single precision (f32) for surface reconstruction.");
@@ -806,7 +799,7 @@ pub(crate) fn reconstruction_pipeline(
806799
"Unable to convert surface reconstruction parameters from f64 to f32."
807800
))?,
808801
&args.io_params,
809-
args.check_mesh,
802+
&args.postprocessing,
810803
)?;
811804
}
812805

@@ -818,14 +811,14 @@ pub(crate) fn reconstruction_pipeline_generic<I: Index, R: Real>(
818811
paths: &ReconstructionRunnerPaths,
819812
params: &splashsurf_lib::Parameters<R>,
820813
io_params: &io::FormatParameters,
821-
check_mesh: bool,
814+
postprocessing: &ReconstructionRunnerPostprocessingArgs,
822815
) -> Result<(), anyhow::Error> {
823816
profile!("surface reconstruction");
824817

825818
// Load particle positions and attributes to interpolate
826819
let (particle_positions, attributes) = io::read_particle_positions_with_attributes(
827820
&paths.input_file,
828-
&paths.attributes,
821+
&postprocessing.interpolate_attributes,
829822
&io_params.input,
830823
)
831824
.with_context(|| {
@@ -843,7 +836,7 @@ pub(crate) fn reconstruction_pipeline_generic<I: Index, R: Real>(
843836
let mesh = reconstruction.mesh();
844837

845838
// Add normals to mesh if requested
846-
let mesh = if paths.compute_normals || !attributes.is_empty() {
839+
let mesh = if postprocessing.compute_normals || !attributes.is_empty() {
847840
profile!("compute normals");
848841

849842
info!(
@@ -876,8 +869,8 @@ pub(crate) fn reconstruction_pipeline_generic<I: Index, R: Real>(
876869
let mut mesh_with_data = MeshWithData::new(mesh.clone());
877870

878871
// Compute normals if requested
879-
if paths.compute_normals {
880-
let normals = if paths.sph_normals {
872+
if postprocessing.compute_normals {
873+
let normals = if postprocessing.sph_normals {
881874
info!("Using SPH interpolation to compute surface normals");
882875

883876
let sph_normals = interpolator.interpolate_normals(mesh.vertices());
@@ -1028,7 +1021,7 @@ pub(crate) fn reconstruction_pipeline_generic<I: Index, R: Real>(
10281021
info!("Done.");
10291022
}
10301023

1031-
if check_mesh {
1024+
if postprocessing.check_mesh {
10321025
if let Err(err) = splashsurf_lib::marching_cubes::check_mesh_consistency(grid, &mesh.mesh) {
10331026
return Err(anyhow!("{}", err));
10341027
} else {

0 commit comments

Comments
 (0)