1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use anyhow::{Context, Result};
use pasture_core::containers::BorrowedBuffer;
use pasture_core::containers::MakeBufferFromLayout;
use pasture_core::containers::OwningBuffer;

mod reader;
use std::path::Path;

pub use self::reader::*;

mod writer;
pub use self::writer::*;

mod seek;
pub use self::seek::*;

mod io_factory;
pub use self::io_factory::*;

/// Try to read all points in the given point cloud file. This function uses the default `IOFactory` to determine the
/// file type from the file extension of `path`. If this succeeds, an appropriate reader is created and all points are
/// read into an implementation-defined `PointBuffer` type. If you want to use a specific type of `PointBuffer`, use
/// `read_all_into` instead!
pub fn read_all<'a, B: MakeBufferFromLayout<'a> + OwningBuffer<'a> + 'a, P: AsRef<Path>>(
    path: P,
) -> Result<B> {
    let mut reader = GenericPointReader::open_file(path.as_ref()).context(format!(
        "Could not create appropriate reader for point cloud file {}",
        path.as_ref().display()
    ))?;
    // While not pretty, it is allowed to call `read_into` with a value larger than the total number of points
    // By falling back to `usize::MAX` for unknown point counts, we guarantee that we always read the whole
    // point cloud
    let num_points = reader.point_count().unwrap_or(usize::MAX);
    reader.read::<B>(num_points)
}

/// Try to read all points in the given point cloud file into the given `buffer`. All points are appended to the end of
/// the `buffer`. Otherwise behaves exactly like `read_all`.
pub fn read_all_into<'a, B: OwningBuffer<'a>, P: AsRef<Path>>(
    buffer: &'a mut B,
    path: P,
) -> Result<usize> {
    let mut reader = GenericPointReader::open_file(path.as_ref()).context(format!(
        "Could not create appropriate reader for point cloud file {}",
        path.as_ref().display()
    ))?;
    let num_points = reader.point_count().context(format!(
        "Could not determine number of points in point cloud file {}",
        path.as_ref().display()
    ))?;
    reader.read_into(buffer, num_points)
}

/// Writes all points in the given `buffer` into the file at `path`
pub fn write_all<'a, B: BorrowedBuffer<'a>, P: AsRef<Path>>(buffer: &'a B, path: P) -> Result<()> {
    let mut writer =
        GenericPointWriter::open_file(path.as_ref(), buffer.point_layout()).context(format!(
            "Could not create appropriate writer for point cloud file {}",
            path.as_ref().display()
        ))?;
    writer.write(buffer).context(format!(
        "Failed to write points to file {}",
        path.as_ref().display()
    ))?;
    writer.flush().context(format!(
        "Failed to flush points to file {}",
        path.as_ref().display()
    ))?;
    Ok(())
}