Skip to main content

las/
laz.rs

1//! Utility functions for working with laszip compressed data.
2
3use crate::{Error, Header, Result, Vlr};
4use laz::{LazItemRecordBuilder, LazItemType, LazVlr};
5use std::io::Cursor;
6
7/// Returns true if this [Vlr] is the laszip Vlr.
8///
9/// # Examples
10///
11/// ```
12/// #[cfg(feature = "laz")]
13/// {
14/// use las::{laz, Vlr};
15///
16/// let mut vlr = Vlr::default();
17/// assert!(!laz::is_laszip_vlr(&vlr));
18/// vlr.user_id = "laszip encoded".to_string();
19/// vlr.record_id = 22204;
20/// assert!(laz::is_laszip_vlr(&vlr));
21/// }
22/// ```
23pub fn is_laszip_vlr(vlr: &Vlr) -> bool {
24    vlr.user_id == LazVlr::USER_ID && vlr.record_id == LazVlr::RECORD_ID
25}
26
27impl Header {
28    /// Adds a new laszip vlr to this header.
29    ///
30    /// Ensures that there's only one laszip vlr, as well.
31    ///
32    /// # Examples
33    ///
34    /// ```
35    /// use las::Header;
36    ///
37    /// let mut header = Header::default();
38    /// #[cfg(feature = "laz")]
39    /// header.add_laz_vlr().unwrap();
40    /// ```
41    pub fn add_laz_vlr(&mut self) -> Result<()> {
42        let point_format = self.point_format();
43        let mut laz_items = LazItemRecordBuilder::new();
44        if !point_format.is_extended {
45            let _ = laz_items.add_item(LazItemType::Point10);
46
47            if point_format.has_gps_time {
48                let _ = laz_items.add_item(LazItemType::GpsTime);
49            }
50
51            if point_format.has_color {
52                let _ = laz_items.add_item(LazItemType::RGB12);
53            }
54
55            if point_format.has_waveform {
56                let _ = laz_items.add_item(LazItemType::WavePacket13);
57            }
58
59            if point_format.extra_bytes > 0 {
60                let _ = laz_items.add_item(LazItemType::Byte(point_format.extra_bytes));
61            }
62        } else {
63            let _ = laz_items.add_item(LazItemType::Point14);
64
65            if point_format.has_color {
66                // Point format 7 & 8 both have RGB
67                if point_format.has_nir {
68                    let _ = laz_items.add_item(LazItemType::RGBNIR14);
69                } else {
70                    let _ = laz_items.add_item(LazItemType::RGB14);
71                }
72            }
73
74            if point_format.has_waveform {
75                let _ = laz_items.add_item(LazItemType::WavePacket14);
76            }
77
78            if point_format.extra_bytes > 0 {
79                let _ = laz_items.add_item(LazItemType::Byte14(point_format.extra_bytes));
80            }
81        }
82        let laz_vlr = LazVlr::from_laz_items(laz_items.build());
83        let mut cursor = Cursor::new(Vec::<u8>::new());
84        laz_vlr.write_to(&mut cursor)?;
85        let vlr = Vlr {
86            user_id: LazVlr::USER_ID.to_owned(),
87            record_id: LazVlr::RECORD_ID,
88            description: LazVlr::DESCRIPTION.to_owned(),
89            data: cursor.into_inner(),
90        };
91        self.vlrs.push(vlr);
92        Ok(())
93    }
94
95    /// Returns header's [LazVlr], or `Error::LasZipVlrNotFound` if none is found.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// use las::Header;
101    ///
102    /// let mut header = Header::default();
103    ///
104    /// #[cfg(feature = "laz")]
105    /// {
106    /// assert!(header.laz_vlr().is_err());
107    /// header.add_laz_vlr();
108    /// assert!(header.laz_vlr().is_ok());
109    /// }
110    /// ```
111    pub fn laz_vlr(&self) -> Result<LazVlr> {
112        self.vlrs
113            .iter()
114            .find(|vlr| is_laszip_vlr(vlr))
115            .map_or(Err(Error::LasZipVlrNotFound), |vlr| vlr.try_into())
116    }
117}
118
119impl TryFrom<&Vlr> for LazVlr {
120    type Error = Error;
121
122    fn try_from(vlr: &Vlr) -> Result<LazVlr> {
123        LazVlr::from_buffer(&vlr.data).map_err(Error::from)
124    }
125}