Skip to content

Commit 48bf9a3

Browse files
committed
Remove distinction between input-file and input-sequence
1 parent fb7c3ec commit 48bf9a3

File tree

2 files changed

+77
-144
lines changed

2 files changed

+77
-144
lines changed

splashsurf/src/reconstruction.rs

Lines changed: 76 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,9 @@ static ARGS_OTHER: &str = "Remaining options";
3030
#[clap(group = clap::ArgGroup::new("input").required(true))]
3131
#[command(next_help_heading = ARGS_OTHER)]
3232
pub struct ReconstructSubcommandArgs {
33-
/// Path to the input file where the particle positions are stored (supported formats: VTK 4.2, VTU, binary f32 XYZ, PLY, BGEO)
34-
#[arg(help_heading = ARGS_IO, short = 'i', long, group = "input", value_parser = value_parser!(PathBuf))]
35-
pub input_file: Option<PathBuf>,
36-
/// Path to a sequence of particle files that should be processed, use "{}" in the filename to indicate a placeholder. To specify an output format, use e.g. --output_file="filename_{}.obj".
37-
#[arg(help_heading = ARGS_IO, short = 's', long, group = "input", value_parser = value_parser!(PathBuf))]
38-
pub input_sequence: Option<PathBuf>,
33+
/// Path to the input file where the particle positions are stored (supported formats: VTK 4.2, VTU, binary f32 XYZ, PLY, BGEO), use "{}" in the filename to indicate a placeholder for a sequence.
34+
#[arg(help_heading = ARGS_IO, group = "input", value_parser = value_parser!(PathBuf))]
35+
pub input_file_or_sequence: PathBuf,
3936
/// Filename for writing the reconstructed surface to disk (default: "{original_filename}_surface.vtk")
4037
#[arg(help_heading = ARGS_IO, short = 'o', long, value_parser = value_parser!(PathBuf))]
4138
pub output_file: Option<PathBuf>,
@@ -630,100 +627,95 @@ mod arguments {
630627
fn try_from(args: &ReconstructSubcommandArgs) -> Result<Self, Self::Error> {
631628
let output_suffix = "surface";
632629

633-
if let Some(input_file) = &args.input_file {
634-
if input_file.is_file() {
635-
// Use the user defined output file name if provided...
636-
let output_file = if let Some(output_file) = &args.output_file {
637-
output_file.clone()
638-
// ...otherwise, generate one based on the input filename
639-
} else {
640-
let input_stem = input_file.file_stem().unwrap().to_string_lossy();
641-
format!("{}_{}.vtk", input_stem, output_suffix).into()
642-
};
630+
// Make sure that the input path ends with a filename (and not with a path separator)
631+
let input_filename = match args.input_file_or_sequence.file_name() {
632+
Some(input_filename) => input_filename.to_string_lossy(),
633+
None => {
634+
return Err(anyhow!(
635+
"The input file path \"{}\" does not end with a filename",
636+
args.input_file_or_sequence.display()
637+
))
638+
}
639+
};
643640

644-
Self::try_new(
645-
false,
646-
input_file.clone(),
647-
args.output_dir.clone(),
648-
output_file,
649-
args.output_dm_points.clone(),
650-
args.output_dm_grid.clone(),
651-
args.output_octree.clone(),
652-
(args.start_index, args.end_index),
653-
args.normals.into_bool(),
654-
args.sph_normals.into_bool(),
655-
args.interpolate_attributes.clone(),
656-
)
657-
} else {
641+
// Make sure that the parent directory of the input path exists
642+
if let Some(input_dir) = args.input_file_or_sequence.parent() {
643+
if !input_dir.is_dir() && input_dir != Path::new("") {
658644
return Err(anyhow!(
659-
"Input file does not exist: \"{}\"",
660-
input_file.display()
645+
"The parent directory \"{}\" of the input file path \"{}\" does not exist",
646+
input_dir.display(),
647+
args.input_file_or_sequence.display()
661648
));
662649
}
663-
} else if let Some(input_pattern) = &args.input_sequence {
664-
// Make sure that the sequence pattern ends with a filename (and not with a path separator)
665-
let input_filename = match input_pattern.file_name() {
666-
Some(input_filename) => input_filename.to_string_lossy(),
667-
None => {
668-
return Err(anyhow!(
669-
"The input file path \"{}\" does not end with a filename",
670-
input_pattern.display()
671-
))
672-
}
673-
};
650+
}
651+
652+
let is_sequence: bool;
653+
let output_filename: PathBuf;
654+
655+
// Detect sequence pattern or existing input file
656+
if input_filename.contains("{}") {
657+
is_sequence = true;
674658

675-
// Make sure that the parent directory of the sequence pattern exists
676-
if let Some(input_dir) = input_pattern.parent() {
677-
if !input_dir.is_dir() && input_dir != Path::new("") {
659+
output_filename = if let Some(output_file) = &args.output_file {
660+
let output_pattern = output_file.to_string_lossy();
661+
if output_pattern.contains("{}") {
662+
output_pattern.to_string().into()
663+
} else {
678664
return Err(anyhow!(
679-
"The parent directory \"{}\" of the input file path \"{}\" does not exist",
680-
input_dir.display(),
681-
input_pattern.display()
665+
"The output filename \"{}\" does not contain a place holder \"{{}}\"",
666+
output_file.display()
682667
));
683668
}
684-
}
669+
} else {
670+
let input_stem = args
671+
.input_file_or_sequence
672+
.file_stem()
673+
.unwrap()
674+
.to_string_lossy();
675+
// Use VTK format as default fallback
676+
format!(
677+
"{}.vtk",
678+
input_stem.replace("{}", &format!("{}_{{}}", output_suffix))
679+
).into()
680+
};
681+
} else {
682+
is_sequence = false;
685683

686-
// Make sure that we have a placeholder "{}" in the filename part of the sequence pattern
687-
if input_filename.contains("{}") {
688-
let output_filename = if let Some(output_file) = &args.output_file {
689-
let output_pattern = output_file.to_string_lossy();
690-
if output_pattern.contains("{}") {
691-
output_pattern.to_string()
692-
} else {
693-
return Err(anyhow!("The output filename \"{}\" does not contain a place holder \"{{}}\"", output_file.display()));
694-
}
684+
// Make sure that the input file actually exists
685+
if args.input_file_or_sequence.is_file() {
686+
// Use the user defined output file name if provided...
687+
output_filename = if let Some(output_file) = &args.output_file {
688+
output_file.clone()
689+
// ...otherwise, generate one based on the input filename
695690
} else {
696-
let input_stem = input_pattern.file_stem().unwrap().to_string_lossy();
697-
// Use VTK format as default fallback
698-
format!(
699-
"{}.vtk",
700-
input_stem.replace("{}", &format!("{}_{{}}", output_suffix))
701-
)
691+
let input_stem = args
692+
.input_file_or_sequence
693+
.file_stem()
694+
.unwrap()
695+
.to_string_lossy();
696+
format!("{}_{}.vtk", input_stem, output_suffix).into()
702697
};
703-
704-
Self::try_new(
705-
true,
706-
input_pattern.clone(),
707-
args.output_dir.clone(),
708-
output_filename.into(),
709-
args.output_dm_points.clone(),
710-
args.output_dm_grid.clone(),
711-
args.output_octree.clone(),
712-
(args.start_index, args.end_index),
713-
args.normals.into_bool(),
714-
args.sph_normals.into_bool(),
715-
args.interpolate_attributes.clone(),
716-
)
717698
} else {
718699
return Err(anyhow!(
719-
"The input sequence pattern \"{}\" does not contain a place holder \"{{}}\"", input_pattern.display()
700+
"Input file does not exist: \"{}\"",
701+
args.input_file_or_sequence.display()
720702
));
721703
}
722-
} else {
723-
return Err(anyhow!(
724-
"Neither an input file path or input sequence pattern was provided"
725-
));
726704
}
705+
706+
Self::try_new(
707+
is_sequence,
708+
args.input_file_or_sequence.clone(),
709+
args.output_dir.clone(),
710+
output_filename,
711+
args.output_dm_points.clone(),
712+
args.output_dm_grid.clone(),
713+
args.output_octree.clone(),
714+
(args.start_index, args.end_index),
715+
args.normals.into_bool(),
716+
args.sph_normals.into_bool(),
717+
args.interpolate_attributes.clone(),
718+
)
727719
}
728720
}
729721

splashsurf/src/tests/cli.rs

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ fn test_main_cli() {
5252
if let Subcommand::Reconstruct(rec_args) = crate::CommandlineArgs::try_parse_from([
5353
"splashsurf",
5454
"reconstruct",
55-
"--input-file",
5655
"test.vtk",
5756
"--particle-radius=0.05",
5857
"--smoothing-length=3.0",
@@ -61,48 +60,13 @@ fn test_main_cli() {
6160
.expect("this command is supposed to work")
6261
.subcommand
6362
{
64-
assert_eq!(rec_args.input_file, Some(PathBuf::from("test.vtk")));
63+
assert_eq!(rec_args.input_file_or_sequence, PathBuf::from("test.vtk"));
6564
};
6665

67-
// Minimum arguments: input sequence
68-
if let Subcommand::Reconstruct(rec_args) = crate::CommandlineArgs::try_parse_from([
69-
"splashsurf",
70-
"reconstruct",
71-
"--input-sequence",
72-
"test.vtk",
73-
"--particle-radius=0.05",
74-
"--smoothing-length=3.0",
75-
"--cube-size=0.75",
76-
])
77-
.expect("this command is supposed to work")
78-
.subcommand
79-
{
80-
assert_eq!(rec_args.input_sequence, Some(PathBuf::from("test.vtk")));
81-
};
82-
83-
// Input file & sequence conflict
84-
assert_eq!(
85-
crate::CommandlineArgs::try_parse_from([
86-
"splashsurf",
87-
"reconstruct",
88-
"--input-file",
89-
"test.vtk",
90-
"--input-sequence",
91-
"test.vtk",
92-
"--particle-radius=0.05",
93-
"--smoothing-length=3.0",
94-
"--cube-size=0.75"
95-
])
96-
.expect_err("this command is supposed to fail")
97-
.kind(),
98-
clap::error::ErrorKind::ArgumentConflict
99-
);
100-
10166
// Test on/off switch
10267
if let Subcommand::Reconstruct(rec_args) = crate::CommandlineArgs::try_parse_from([
10368
"splashsurf",
10469
"reconstruct",
105-
"--input-file",
10670
"test.vtk",
10771
"--particle-radius=0.05",
10872
"--smoothing-length=3.0",
@@ -118,7 +82,6 @@ fn test_main_cli() {
11882
if let Subcommand::Reconstruct(rec_args) = crate::CommandlineArgs::try_parse_from([
11983
"splashsurf",
12084
"reconstruct",
121-
"--input-file",
12285
"test.vtk",
12386
"--particle-radius=0.05",
12487
"--smoothing-length=3.0",
@@ -131,29 +94,10 @@ fn test_main_cli() {
13194
assert_eq!(rec_args.normals, Switch::Off);
13295
};
13396

134-
assert_eq!(
135-
crate::CommandlineArgs::try_parse_from([
136-
"splashsurf",
137-
"reconstruct",
138-
"--input-file",
139-
"test.vtk",
140-
"--input-sequence",
141-
"test.vtk",
142-
"--particle-radius=0.05",
143-
"--smoothing-length=3.0",
144-
"--cube-size=0.75",
145-
"--normals"
146-
])
147-
.expect_err("this command is supposed to fail")
148-
.kind(),
149-
clap::error::ErrorKind::NoEquals
150-
);
151-
15297
// Test domain min/max: correct values
15398
if let Subcommand::Reconstruct(rec_args) = crate::CommandlineArgs::try_parse_from([
15499
"splashsurf",
155100
"reconstruct",
156-
"--input-file",
157101
"test.vtk",
158102
"--particle-radius=0.05",
159103
"--smoothing-length=3.0",
@@ -179,9 +123,6 @@ fn test_main_cli() {
179123
crate::CommandlineArgs::try_parse_from([
180124
"splashsurf",
181125
"reconstruct",
182-
"--input-file",
183-
"test.vtk",
184-
"--input-sequence",
185126
"test.vtk",
186127
"--particle-radius=0.05",
187128
"--smoothing-length=3.0",

0 commit comments

Comments
 (0)