Skip to main content

voxelaz/
lib.rs

1mod cancel;
2mod classification;
3mod error;
4mod pipeline;
5mod voxel_grid;
6
7pub use cancel::CancellationToken;
8pub use classification::ClassificationFilter;
9pub use error::{Result, VoxelizeError};
10pub use voxel_grid::{VoxelGrid, VoxelPoint, BOUNDED_QUEUE_CAPACITY, CHUNK_SIZE};
11
12use std::path::Path;
13
14use las::point::Format;
15use las::{Color, Point};
16
17use error::{join_consumer, join_producer};
18use pipeline::run_pipeline;
19
20pub struct VoxelizeConfig {
21    pub voxel_size: f64,
22    pub classification_filter: ClassificationFilter,
23    pub counts_as_intensity: bool,
24    pub cancel: Option<CancellationToken>,
25}
26
27impl VoxelizeConfig {
28    pub fn new(voxel_size: f64) -> Self {
29        Self {
30            voxel_size,
31            classification_filter: ClassificationFilter::all(),
32            counts_as_intensity: false,
33            cancel: None,
34        }
35    }
36}
37
38pub fn voxelize(input: &Path, output: &Path, config: &VoxelizeConfig) -> Result<()> {
39    if config.voxel_size <= 0.0 {
40        return Err(VoxelizeError::InvalidVoxelSize);
41    }
42
43    let header = {
44        let reader = las::Reader::from_path(input)?;
45        reader.header().clone()
46    };
47    let bounds = header.bounds();
48    let origin = [bounds.min.x, bounds.min.y, bounds.min.z];
49    let dimensions = [
50        bounds.max.x - bounds.min.x,
51        bounds.max.y - bounds.min.y,
52        bounds.max.z - bounds.min.z,
53    ];
54
55    let (producer, consumer) = run_pipeline(
56        input,
57        output.to_path_buf(),
58        header,
59        origin,
60        dimensions,
61        config.voxel_size,
62        config.classification_filter.clone(),
63        config.counts_as_intensity,
64        config.cancel.clone(),
65    );
66
67    let consumer_result = join_consumer(consumer);
68    let producer_result = join_producer(producer);
69
70    let cancelled = matches!(
71        (&consumer_result, &producer_result),
72        (Err(VoxelizeError::Cancelled), _) | (_, Err(VoxelizeError::Cancelled))
73    );
74
75    if cancelled {
76        let _ = std::fs::remove_file(output);
77        return Err(VoxelizeError::Cancelled);
78    }
79
80    consumer_result?;
81    producer_result?;
82
83    Ok(())
84}
85
86pub(crate) fn voxel_point_to_las_point(
87    voxel_point: &VoxelPoint,
88    format: &Format,
89    counts_as_intensity: bool,
90) -> Point {
91    let mut point = Point::default();
92    point.x = voxel_point.x;
93    point.y = voxel_point.y;
94    point.z = voxel_point.z;
95    if counts_as_intensity {
96        point.intensity = voxel_point.count;
97    }
98    if format.has_gps_time {
99        point.gps_time = Some(0.0);
100    }
101    if format.has_color {
102        point.color = Some(Color::default());
103    }
104    if format.has_waveform {
105        point.waveform = Some(Default::default());
106    }
107    if format.has_nir {
108        point.nir = Some(0);
109    }
110    if format.extra_bytes > 0 {
111        point.extra_bytes = vec![0; format.extra_bytes as usize];
112    }
113    point
114}