use glob;
use std::path::Path;
use std::io::BufReader;
#[cfg(feature = "parallel")]
use laz::checking::LasChecker;
#[cfg(feature = "parallel")]
use laz::las::file::read_header_and_vlrs;
#[cfg(feature = "parallel")]
use laz::las::laszip::par_decompress_all_from_file_greedy;
use std::fs::File;
#[cfg(feature = "parallel")]
#[derive(Copy, Clone)]
enum NumPointsPerIter {
All,
Value(u64),
}
#[cfg(feature = "parallel")]
#[derive(Copy, Clone)]
struct ProgramArgs<'a> {
laz_path: &'a str,
las_path: &'a str,
greedy: bool,
num_points_per_iter: NumPointsPerIter,
}
#[cfg(feature = "parallel")]
impl<'a> ProgramArgs<'a> {
fn new(args: &'a Vec<String>) -> Self {
let mut num_points_per_iter = NumPointsPerIter::Value(1_145_647);
let mut greedy = false;
let mut las_path = "";
let mut laz_path = "";
let mut positional_arg_pos = 0;
let mut args_iter = args.iter();
args_iter.next();
while let Some(arg) = args_iter.next() {
if arg == "--num_points_per_iter" {
match args_iter.next() {
Some(value_str) => {
if value_str.trim_start().chars().next().unwrap() == '-' {
num_points_per_iter = NumPointsPerIter::All
} else {
num_points_per_iter =
NumPointsPerIter::Value(value_str.parse::<u64>().unwrap())
}
}
None => {
println!("--num_points_per_iter expected a value, eg: '--num_points_per_iter 5_000_000");
std::process::exit(1);
}
};
} else if arg == "--greedy" {
greedy = true;
} else {
if positional_arg_pos == 0 {
laz_path = &arg;
positional_arg_pos += 1;
} else if positional_arg_pos == 1 {
las_path = &arg;
positional_arg_pos += 1;
} else {
println!("Too many positional arguments");
std::process::exit(1);
}
}
}
if positional_arg_pos < 2 {
println!("Usage: par_decompression LAZ_PATH LAS_PATH");
std::process::exit(1);
}
ProgramArgs {
las_path,
laz_path,
greedy,
num_points_per_iter,
}
}
}
#[cfg(feature = "parallel")]
fn run_check(program_args: &ProgramArgs) {
let mut laz_file = BufReader::new(File::open(program_args.laz_path).unwrap());
let (laz_header, laz_vlr) = read_header_and_vlrs(&mut laz_file).unwrap();
let laz_vlr = laz_vlr.expect("No LasZip Vlr in the laz file");
if program_args.greedy {
let mut all_points =
vec![0u8; laz_header.point_size as usize * laz_header.num_points as usize];
par_decompress_all_from_file_greedy(&mut laz_file, &mut all_points, &laz_vlr).unwrap();
let mut checker = LasChecker::from_path(&program_args.las_path).unwrap();
checker.check(&all_points);
} else {
let mut decompressor = laz::ParLasZipDecompressor::new(laz_file, laz_vlr).unwrap();
let num_points_per_iter = match program_args.num_points_per_iter {
NumPointsPerIter::All => laz_header.num_points as usize,
NumPointsPerIter::Value(v) => v as usize,
};
let mut num_points_left = laz_header.num_points as usize;
let mut decompressed_points =
vec![0u8; num_points_per_iter * laz_header.point_size as usize];
let mut checker = LasChecker::from_path(&program_args.las_path).unwrap();
while num_points_left > 0 {
let num_points_to_read = std::cmp::min(num_points_left, num_points_per_iter);
let points =
&mut decompressed_points[..num_points_to_read * laz_header.point_size as usize];
decompressor.decompress_many(points).unwrap();
checker.check(points);
num_points_left -= num_points_to_read;
}
}
}
#[cfg(feature = "parallel")]
fn main() {
let args = std::env::args().collect::<Vec<String>>();
let program_args = ProgramArgs::new(&args);
let (laz_path, las_path) = if args.len() == 3 {
(&args[1], &args[2])
} else if args.len() == 2 {
(&args[1], &args[1])
} else {
println!("Usage: check_decompression LAZ_PATH LAS_PATH");
println!("OR : check_decompression PATH");
std::process::exit(1);
};
if Path::new(laz_path).is_dir() && Path::new(las_path).is_dir() {
let laz_globber = glob::glob(&format!("{}/**/*.laz", laz_path)).unwrap();
let las_globber = glob::glob(&format!("{}/**/*.las", las_path)).unwrap();
for (las_entry, laz_entry) in las_globber.zip(laz_globber) {
let laz_path = laz_entry.unwrap();
let las_path = las_entry.unwrap();
println!("{:?} - {:?}", las_path, laz_path);
let mut args: ProgramArgs = program_args;
args.laz_path = laz_path.to_str().unwrap();
args.las_path = las_path.to_str().unwrap();
if las_path.file_stem().unwrap() == las_path.file_stem().unwrap() {
run_check(&args);
}
}
} else if Path::new(laz_path).is_file() & &Path::new(las_path).is_file() {
run_check(&program_args);
} else {
println!("Arguments must both be either path to file or path to directory");
}
}
#[cfg(not(feature = "parallel"))]
fn main() {
use laz::checking::check_decompression;
let args: Vec<String> = std::env::args().collect();
let (laz_path, las_path) = if args.len() == 3 {
(&args[1], &args[2])
} else if args.len() == 2 {
(&args[1], &args[1])
} else {
println!("Usage: check_decompression LAZ_PATH LAS_PATH");
println!("OR : check_decompression PATH");
std::process::exit(1);
};
if Path::new(laz_path).is_dir() && Path::new(las_path).is_dir() {
let laz_globber = glob::glob(&format!("{}/**/*.laz", laz_path)).unwrap();
let las_globber = glob::glob(&format!("{}/**/*.las", las_path)).unwrap();
for (las_entry, laz_entry) in las_globber.zip(laz_globber) {
let laz_path = laz_entry.unwrap();
let las_path = las_entry.unwrap();
println!("{:?} - {:?}", las_path, laz_path);
if las_path.file_stem().unwrap() == las_path.file_stem().unwrap() {
let laz_file = BufReader::new(File::open(laz_path).unwrap());
let las_file = BufReader::new(File::open(las_path).unwrap());
check_decompression(laz_file, las_file);
}
}
} else if Path::new(laz_path).is_file() && Path::new(las_path).is_file() {
let laz_file = BufReader::new(File::open(&args[1]).unwrap());
let las_file = BufReader::new(File::open(&args[2]).unwrap());
check_decompression(laz_file, las_file);
} else {
println!("Arguments must both be either path to file or path to directory");
}
}