las/header/
mod.rs

1//! A [Header] describes the configuration and properties of las data.
2//!
3//! # Reading
4//!
5//! A [Reader](crate::Reader) uses a [Header] to expose metadata:
6//!
7//! ```
8//! use las::Reader;
9//! let reader = Reader::from_path("tests/data/autzen.las").unwrap();
10//! let header = reader.header();
11//! println!("The file has {} points.", header.number_of_points());
12//! ```
13//!
14//! # Writing
15//!
16//! A [Writer](crate::Writer) uses a [Header] to configure how it will write
17//! points.  To create a las file, you can use a [Header] from another file, use
18//! the default [Header], or create one with a [Builder]:
19//!
20//! The default configuration writes to a [Cursor](std::io::Cursor):
21//!
22//! ```
23//! use las::Writer;
24//!
25//! let writer = Writer::default();
26//! ```
27//!
28//! You can copy configuration from an existing file:
29//!
30//! ```
31//! use std::io::Cursor;
32//! use las::{Writer, Reader};
33//!
34//! let header = Reader::from_path("tests/data/autzen.las").unwrap().header().clone();
35//! let writer = Writer::new(Cursor::new(Vec::new()), header).unwrap();
36//! ```
37//!
38//! Use a [Builder] to set your own configuration:
39//!
40//! ```
41//! use std::io::Cursor;
42//! use las::{Writer, Builder};
43//!
44//! let mut builder = Builder::from((1, 4));
45//! builder.system_identifier = "Synthetic points".to_string();
46//! let header = builder.into_header().unwrap();
47//! let writer = Writer::new(Cursor::new(Vec::new()), header).unwrap();
48//! ```
49//!
50//! # Into raw bytes
51//!
52//! A [Header] has a method to turn it into a [raw::Header], which maps directly
53//! onto the bytes of the las spec:
54//!
55//! ```
56//! use las::Header;
57//! let header = Header::default();
58//! let raw_header = header.into_raw().unwrap();
59//! assert_eq!(b"LASF", &raw_header.file_signature);
60//! ```
61
62pub use self::builder::Builder;
63use crate::{
64    point::Format, raw, utils::FromLasStr, Bounds, Error, GpsTimeType, Point, Result, Transform,
65    Vector, Version, Vlr,
66};
67use chrono::{Datelike, NaiveDate, Utc};
68use std::{
69    cmp::Ordering,
70    collections::HashMap,
71    io::{Read, Seek, SeekFrom, Write},
72    iter::Chain,
73    slice::Iter,
74};
75use thiserror::Error;
76use uuid::Uuid;
77
78mod builder;
79
80/// Metadata describing the layout, source, and interpretation of the points.
81///
82/// Headers include *all* las metadata, including regular and extended variable length records and
83/// any file padding (e.g. extra bytes after the header).
84#[derive(Clone, Debug, PartialEq)]
85pub struct Header {
86    bounds: Bounds,
87    date: Option<NaiveDate>,
88    pub(crate) evlrs: Vec<Vlr>,
89    file_source_id: u16,
90    generating_software: String,
91    gps_time_type: GpsTimeType,
92    guid: Uuid,
93    has_synthetic_return_numbers: bool,
94    pub(crate) has_wkt_crs: bool,
95    number_of_points: u64,
96    number_of_points_by_return: HashMap<u8, u64>,
97    padding: Vec<u8>,
98    point_format: Format,
99    point_padding: Vec<u8>,
100    start_of_first_evlr: Option<u64>,
101    system_identifier: String,
102    transforms: Vector<Transform>,
103    version: Version,
104    vlr_padding: Vec<u8>,
105    pub(crate) vlrs: Vec<Vlr>,
106}
107
108/// An iterator over a header's variable length records.
109///
110/// Get this iterator via [Header::vlrs] or [Header::evlrs].
111#[derive(Debug)]
112pub struct Vlrs<'a>(Chain<Iter<'a, Vlr>, Iter<'a, Vlr>>);
113
114impl Header {
115    /// Reads all header, vlr and evlr data from file and returns the complete header.
116    pub fn new<R: Read + Seek>(mut read: R) -> Result<Self> {
117        let raw_header = raw::Header::read_from(read.by_ref())?;
118        let mut position = u64::from(raw_header.header_size);
119        let number_of_variable_length_records = raw_header.number_of_variable_length_records;
120        let offset_to_point_data = u64::from(raw_header.offset_to_point_data);
121        let offset_to_end_of_points = raw_header.offset_to_end_of_points();
122        let evlr = raw_header.evlr;
123
124        let mut builder = Builder::new(raw_header)?;
125
126        for _ in 0..number_of_variable_length_records {
127            let vlr = raw::Vlr::read_from(read.by_ref(), false).map(Vlr::new)?;
128            position += vlr.len(false) as u64;
129            builder.vlrs.push(vlr);
130        }
131        match position.cmp(&offset_to_point_data) {
132            Ordering::Less => {
133                let _ = read
134                    .by_ref()
135                    .take(offset_to_point_data - position)
136                    .read_to_end(&mut builder.vlr_padding)?;
137            }
138            Ordering::Equal => {} // pass
139            Ordering::Greater => {
140                return Err(Error::OffsetToPointDataTooSmall(
141                    offset_to_point_data as u32,
142                ))
143            }
144        }
145
146        let _ = read.seek(SeekFrom::Start(offset_to_end_of_points))?;
147        if let Some(evlr) = evlr {
148            // Account for any padding between the end of the point data and the start of the ELVRs
149            //
150            // Ignore this case if the point format is compressed.
151            // See https://github.com/gadomski/las-rs/issues/39
152            //
153            // When reading a compressed file, evlr.start_of_first_evlr
154            // is a compressed byte offset, while offset_to_end_of_points
155            // is an uncompressed byte offset, which results in
156            // evlr.start_of_first_evlr < offset_to_end_of_points,
157            //
158            // In this case, we assume that the ELVRs follow the point
159            // record data directly and there is no point_padding to account for.
160            if !builder.point_format.is_compressed {
161                match evlr.start_of_first_evlr.cmp(&offset_to_end_of_points) {
162                    Ordering::Less => {
163                        return Err(Error::OffsetToEvlrsTooSmall(evlr.start_of_first_evlr));
164                    }
165                    Ordering::Equal => {} // pass
166                    Ordering::Greater => {
167                        let n = evlr.start_of_first_evlr - offset_to_end_of_points;
168                        let _ = read
169                            .by_ref()
170                            .take(n)
171                            .read_to_end(&mut builder.point_padding)?;
172                    }
173                }
174            }
175            let _ = read.seek(SeekFrom::Start(evlr.start_of_first_evlr))?;
176            builder
177                .evlrs
178                .push(raw::Vlr::read_from(read.by_ref(), true).map(Vlr::new)?);
179        }
180
181        let _ = read.seek(SeekFrom::Start(offset_to_point_data))?;
182
183        if let Some(version) = builder.minimum_supported_version()
184            && version > builder.version
185        {
186            log::warn!(
187                "upgrading las version to {} (from {})",
188                version,
189                builder.version
190            );
191            builder.version = version;
192        }
193        builder.into_header()
194    }
195    /// Creates a new header from a raw header.
196    ///
197    /// # Examples
198    ///
199    /// ```
200    /// use las::{raw, Header};
201    /// let raw_header = raw::Header::default();
202    /// let header = Header::from_raw(raw_header).unwrap();
203    /// ```
204    pub fn from_raw(raw_header: raw::Header) -> Result<Header> {
205        Builder::new(raw_header).and_then(|b| b.into_header())
206    }
207
208    /// Clears this header's point counts and bounds.
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// use las::{Header, Point, Bounds};
214    /// let mut header = Header::default();
215    /// header.add_point(&Point { return_number: 1, ..Default::default() });
216    /// assert_eq!(1, header.number_of_points());
217    /// assert_eq!(1, header.number_of_points_by_return(1).unwrap());
218    /// header.clear();
219    /// assert_eq!(0, header.number_of_points());
220    /// assert_eq!(None, header.number_of_points_by_return(1));
221    /// assert_eq!(Bounds::default(), header.bounds());
222    /// ```
223    pub fn clear(&mut self) {
224        self.number_of_points = 0;
225        self.number_of_points_by_return = Default::default();
226        self.bounds = Default::default();
227    }
228
229    /// Adds a point to this header, incrementing the point counts and growing the bounds.
230    ///
231    /// # Examples
232    ///
233    /// ```
234    /// use las::Header;
235    /// let mut header = Header::default();
236    /// header.add_point(&Default::default());
237    /// assert_eq!(1, header.number_of_points());
238    /// ```
239    pub fn add_point(&mut self, point: &Point) {
240        self.number_of_points += 1;
241        if point.return_number > 0 {
242            let entry = self
243                .number_of_points_by_return
244                .entry(point.return_number)
245                .or_insert(0);
246            *entry += 1;
247        }
248        self.bounds.grow(point);
249    }
250
251    /// Returns this header's file source id.
252    ///
253    /// For airborne data, this is often the flight line number.
254    ///
255    /// # Examples
256    ///
257    /// ```
258    /// use las::Header;
259    /// assert_eq!(0, Header::default().file_source_id());
260    /// ```
261    pub fn file_source_id(&self) -> u16 {
262        self.file_source_id
263    }
264
265    /// Returns the gps time type.
266    ///
267    /// This affects what the gps time values on points means.
268    /// [GpsTimeType::Week] means that the time values are seconds from the
269    /// start of the week. [GpsTimeType::Standard] means that the time values
270    /// are standard GPS time (satellite gps time) minus 10e9.
271    ///
272    /// # Examples
273    ///
274    /// ```
275    /// use las::{GpsTimeType, Header};
276    /// assert_eq!(GpsTimeType::Week, Header::default().gps_time_type());
277    /// ```
278    pub fn gps_time_type(&self) -> GpsTimeType {
279        self.gps_time_type
280    }
281
282    /// Returns true if the return numbers on the point data records have been synthetically
283    /// generated.
284    ///
285    /// Only supported in later las versions.
286    ///
287    /// # Examples
288    ///
289    /// ```
290    /// use las::Header;
291    /// assert!(!Header::default().has_synthetic_return_numbers());
292    pub fn has_synthetic_return_numbers(&self) -> bool {
293        self.has_synthetic_return_numbers
294    }
295
296    /// Returns true if the coordinate reference system is Well Known Text (WKT).
297    ///
298    /// Only supported in las 1.4.
299    ///
300    /// # Examples
301    ///
302    /// ```
303    /// use las::Header;
304    /// assert!(!Header::default().has_wkt_crs());
305    pub fn has_wkt_crs(&self) -> bool {
306        self.has_wkt_crs
307    }
308
309    /// Returns this header's guid.
310    ///
311    /// # Examples
312    ///
313    /// ```
314    /// use las::Header;
315    /// let guid = Header::default().guid();
316    /// ```
317    pub fn guid(&self) -> Uuid {
318        self.guid
319    }
320
321    /// Returns this header's version.
322    ///
323    /// # Examples
324    ///
325    /// ```
326    /// use las::{Header, Version};
327    /// assert_eq!(Version::new(1, 2), Header::default().version());
328    /// ```
329    pub fn version(&self) -> Version {
330        self.version
331    }
332
333    /// Returns this header's system identifier.
334    ///
335    /// Describes the source of the data, whether it is a sensor or a processing operation.
336    ///
337    /// # Examples
338    ///
339    /// ```
340    /// use las::Header;
341    /// println!("{}", Header::default().system_identifier());
342    /// ```
343    pub fn system_identifier(&self) -> &str {
344        &self.system_identifier
345    }
346
347    /// Returns this header's generating software.
348    ///
349    /// # Examples
350    ///
351    /// ```
352    /// use las::Header;
353    /// assert!(Header::default().generating_software().starts_with("las-rs"));
354    /// ```
355    pub fn generating_software(&self) -> &str {
356        &self.generating_software
357    }
358
359    /// Returns this header's file creation date.
360    ///
361    /// Can be `None`, which is against spec but happens with files in the wild.
362    ///
363    /// # Examples
364    ///
365    /// ```
366    /// use las::Header;
367    /// let date = Header::default().date().unwrap();
368    /// ```
369    pub fn date(&self) -> Option<NaiveDate> {
370        self.date
371    }
372
373    /// Returns this header's padding.
374    ///
375    /// These are bytes that are after the header but before the vlr. Not recommended to use.
376    ///
377    /// # Examples
378    ///
379    /// ```
380    /// use las::Header;
381    /// assert!(Header::default().padding().is_empty());
382    /// ```
383    pub fn padding(&self) -> &Vec<u8> {
384        &self.padding
385    }
386
387    /// Returns this header's point format.
388    ///
389    /// Point formats are used to describe the attributes and extra bytes of each point.
390    ///
391    /// # Examples
392    ///
393    /// ```
394    /// use las::Header;
395    /// let header = Header::default();
396    /// assert_eq!(0, header.point_format().to_u8().unwrap());
397    /// ```
398    pub fn point_format(&self) -> &Format {
399        &self.point_format
400    }
401
402    pub(crate) fn point_format_mut(&mut self) -> &mut Format {
403        &mut self.point_format
404    }
405
406    /// Returns this header's transforms.
407    ///
408    /// The transforms are the scales and offsets used to convert floating point numbers to `i16`.
409    /// Las data stores point coordinates as `i16`s internally.
410    ///
411    /// # Examples
412    ///
413    /// ```
414    /// use las::Header;
415    /// let header = Header::default();
416    /// let transforms = header.transforms();
417    /// assert_eq!(0.001, transforms.x.scale);
418    /// ```
419    pub fn transforms(&self) -> &Vector<Transform> {
420        &self.transforms
421    }
422
423    /// Returns the bounds of this header.
424    ///
425    /// The bounds describe the min and max values in each dimension.
426    ///
427    /// # Examples
428    ///
429    /// ```
430    /// use las::Header;
431    /// let bounds = Header::default().bounds();
432    /// ```
433    pub fn bounds(&self) -> Bounds {
434        self.bounds
435    }
436
437    /// Returns this header's number of points.
438    ///
439    /// # Examples
440    ///
441    /// ```
442    /// use las::Header;
443    /// let header = Header::default();
444    /// assert_eq!(0, header.number_of_points());
445    /// ```
446    pub fn number_of_points(&self) -> u64 {
447        self.number_of_points
448    }
449
450    /// Returns this header's number of points for a given return number.
451    ///
452    /// Note that return numbers are 1-indexed.
453    ///
454    /// # Examples
455    ///
456    /// ```
457    /// use las::Header;
458    /// let header = Header::default();
459    /// assert_eq!(None, header.number_of_points_by_return(1));
460    /// ```
461    pub fn number_of_points_by_return(&self, n: u8) -> Option<u64> {
462        self.number_of_points_by_return.get(&n).copied()
463    }
464
465    /// Returns a reference to this header's vlr padding.
466    ///
467    /// These are bytes after the vlrs but before the points. Again, not recommended for use.
468    ///
469    /// # Examples
470    ///
471    /// ```
472    /// use las::Header;
473    /// assert!(Header::default().vlr_padding().is_empty());
474    /// ```
475    pub fn vlr_padding(&self) -> &Vec<u8> {
476        &self.vlr_padding
477    }
478
479    /// Returns a reference to this header's point padding.
480    ///
481    /// These are the bytes after the points but before eof/any evlrs. Not recommended.
482    ///
483    /// # Examples
484    ///
485    /// ```
486    /// use las::Header;
487    /// assert!(Header::default().point_padding().is_empty());
488    /// ```
489    pub fn point_padding(&self) -> &Vec<u8> {
490        &self.point_padding
491    }
492
493    /// Returns a reference to this header's vlrs.
494    ///
495    /// # Examples
496    ///
497    /// ```
498    /// use las::{Vlr, Builder};
499    /// let mut builder = Builder::default();
500    /// builder.vlrs.push(Vlr::default());
501    /// let header = builder.into_header().unwrap();
502    /// assert_eq!(1, header.vlrs().len());
503    /// ```
504    pub fn vlrs(&self) -> &Vec<Vlr> {
505        &self.vlrs
506    }
507
508    /// Returns a reference to header's extended variable length records.
509    ///
510    /// # Examples
511    ///
512    /// ```
513    /// use las::{Vlr, Builder};
514    /// let mut builder = Builder::from((1, 4));
515    /// builder.evlrs.push(Vlr::default());
516    /// let header = builder.into_header().unwrap();
517    /// assert_eq!(1, header.evlrs().len());
518    /// ```
519    pub fn evlrs(&self) -> &Vec<Vlr> {
520        &self.evlrs
521    }
522
523    /// Returns an iterator over all this header's vlrs, both extended and regular.
524    ///
525    /// # Examples
526    ///
527    /// ```
528    /// use las::{Vlr, Builder};
529    /// let mut builder = Builder::from((1, 4));
530    /// builder.vlrs.push(Vlr::default());
531    /// builder.evlrs.push(Vlr::default());
532    /// let header = builder.into_header().unwrap();
533    /// assert_eq!(2, header.all_vlrs().count());
534    /// ```
535    pub fn all_vlrs(&self) -> Vlrs<'_> {
536        Vlrs(self.vlrs.iter().chain(&self.evlrs))
537    }
538
539    /// Returns whether or not this header has any CRS (E)VLRs
540    ///
541    /// # Examples
542    ///
543    /// ```
544    /// use las::Header;
545    /// let header = Header::default();
546    /// assert!(!header.has_crs_vlrs());
547    /// ```
548    pub fn has_crs_vlrs(&self) -> bool {
549        self.all_vlrs().any(|v| v.is_crs())
550    }
551
552    /// Converts this header into a raw header.
553    ///
554    /// # Examples
555    ///
556    /// ```
557    /// use las::Header;
558    /// let raw_header = Header::default().into_raw().unwrap();
559    /// ```
560    pub fn into_raw(self) -> Result<raw::Header> {
561        // Scale the bounding box properly
562        let bounds = self.bounds.adapt(&self.transforms)?;
563        Ok(raw::Header {
564            file_signature: raw::LASF,
565            file_source_id: self.file_source_id,
566            global_encoding: self.global_encoding(),
567            guid: *self.guid.as_bytes(),
568            version: self.version,
569            system_identifier: self.system_identifier_raw()?,
570            generating_software: self.generating_software_raw()?,
571            file_creation_day_of_year: self.date.map_or(0, |d| d.ordinal() as u16),
572            file_creation_year: self.date.map_or(0, |d| d.year() as u16),
573            header_size: self.header_size()?,
574            offset_to_point_data: self.offset_to_point_data()?,
575            number_of_variable_length_records: self.number_of_variable_length_records()?,
576            point_data_record_format: self.point_format.to_writable_u8()?,
577            point_data_record_length: self.point_format.len(),
578            number_of_point_records: self.number_of_points_raw()?,
579            number_of_points_by_return: self.number_of_points_by_return_raw()?,
580            x_scale_factor: self.transforms.x.scale,
581            y_scale_factor: self.transforms.y.scale,
582            z_scale_factor: self.transforms.z.scale,
583            x_offset: self.transforms.x.offset,
584            y_offset: self.transforms.y.offset,
585            z_offset: self.transforms.z.offset,
586            max_x: bounds.max.x,
587            min_x: bounds.min.x,
588            max_y: bounds.max.y,
589            min_y: bounds.min.y,
590            max_z: bounds.max.z,
591            min_z: bounds.min.z,
592            // FIXME waveforms
593            start_of_waveform_data_packet_record: None,
594            evlr: self.evlr()?,
595            large_file: self.large_file()?,
596            padding: self.padding,
597        })
598    }
599
600    /// Writes this header to a [Write].
601    ///
602    /// # Examples
603    ///
604    /// ```
605    /// use std::io::Cursor;
606    /// use las::Header;
607    ///
608    /// let header = Header::default();
609    /// let cursor = Cursor::new(Vec::new());
610    /// header.write_to(cursor).unwrap();
611    /// ```
612    pub fn write_to<W: Write>(&self, mut write: W) -> Result<()> {
613        self.clone()
614            .into_raw()
615            .and_then(|raw_header| raw_header.write_to(&mut write))?;
616        for vlr in self.vlrs() {
617            (*vlr)
618                .clone()
619                .into_raw(false)
620                .and_then(|raw_vlr| raw_vlr.write_to(&mut write))?;
621        }
622        if !self.vlr_padding().is_empty() {
623            write.write_all(self.vlr_padding())?;
624        }
625        Ok(())
626    }
627
628    pub(crate) fn set_start_of_first_evlr(&mut self, start_of_first_evlr: u64) {
629        self.start_of_first_evlr = Some(start_of_first_evlr);
630    }
631
632    fn global_encoding(&self) -> u16 {
633        let mut bits = self.gps_time_type.into();
634        if self.has_synthetic_return_numbers {
635            bits |= 8;
636        }
637        if self.has_wkt_crs || self.point_format.is_extended {
638            bits |= 16;
639        }
640        bits
641    }
642
643    fn system_identifier_raw(&self) -> Result<[u8; 32]> {
644        let mut system_identifier = [0; 32];
645        system_identifier
646            .as_mut()
647            .from_las_str(&self.system_identifier)?;
648        Ok(system_identifier)
649    }
650
651    fn generating_software_raw(&self) -> Result<[u8; 32]> {
652        let mut generating_software = [0; 32];
653        generating_software
654            .as_mut()
655            .from_las_str(&self.generating_software)?;
656        Ok(generating_software)
657    }
658
659    fn header_size(&self) -> Result<u16> {
660        let header_size = self.version.header_size() as usize + self.padding.len();
661        if header_size > u16::MAX as usize {
662            Err(Error::HeaderTooLarge(header_size))
663        } else {
664            Ok(header_size as u16)
665        }
666    }
667
668    fn offset_to_point_data(&self) -> Result<u32> {
669        let vlr_len = self.vlrs.iter().fold(0, |acc, vlr| acc + vlr.len(false));
670        let offset = self.header_size()? as usize + vlr_len + self.vlr_padding.len();
671        if offset > u32::MAX as usize {
672            Err(Error::OffsetToPointDataTooLarge(offset))
673        } else {
674            Ok(offset as u32)
675        }
676    }
677
678    fn number_of_variable_length_records(&self) -> Result<u32> {
679        let n = self.vlrs().len();
680        if n > u32::MAX as usize {
681            Err(Error::TooManyVlrs(n))
682        } else {
683            Ok(n as u32)
684        }
685    }
686
687    fn number_of_points_raw(&self) -> Result<u32> {
688        use crate::feature::LargeFiles;
689
690        if self.number_of_points > u64::from(u32::MAX) {
691            if self.version.supports::<LargeFiles>() {
692                Ok(0)
693            } else {
694                Err(Error::TooManyPoints {
695                    n: self.number_of_points,
696                    version: self.version,
697                })
698            }
699        } else {
700            Ok(self.number_of_points as u32)
701        }
702    }
703
704    fn number_of_points_by_return_raw(&self) -> Result<[u32; 5]> {
705        use crate::feature::LargeFiles;
706
707        let mut number_of_points_by_return = [0; 5];
708        for (&i, &n) in &self.number_of_points_by_return {
709            if i > 5 {
710                if !self.version.supports::<LargeFiles>() {
711                    return Err(Error::ReturnNumber {
712                        return_number: i,
713                        version: Some(self.version),
714                    });
715                }
716            } else if i > 0 {
717                if n > u64::from(u32::MAX) {
718                    if !self.version.supports::<LargeFiles>() {
719                        return Err(Error::TooManyPoints {
720                            n,
721                            version: self.version,
722                        });
723                    }
724                } else {
725                    number_of_points_by_return[i as usize - 1] = n as u32;
726                }
727            }
728        }
729        Ok(number_of_points_by_return)
730    }
731
732    fn evlr(&self) -> Result<Option<raw::header::Evlr>> {
733        let n = self.evlrs.len();
734        if n == 0 {
735            Ok(None)
736        } else if n > u32::MAX as usize {
737            Err(Error::TooManyEvlrs(n))
738        } else {
739            let start_of_first_evlr = if let Some(start_of_fist_evlr) = self.start_of_first_evlr {
740                start_of_fist_evlr
741            } else {
742                self.point_data_len()
743                    + self.point_padding.len() as u64
744                    + u64::from(self.offset_to_point_data()?)
745            };
746            Ok(Some(raw::header::Evlr {
747                start_of_first_evlr,
748                number_of_evlrs: n as u32,
749            }))
750        }
751    }
752
753    fn large_file(&self) -> Result<Option<raw::header::LargeFile>> {
754        let mut number_of_points_by_return = [0; 15];
755        for (&i, &n) in &self.number_of_points_by_return {
756            if i > 15 {
757                return Err(Error::ReturnNumber {
758                    return_number: i,
759                    version: Some(self.version),
760                });
761            } else if i > 0 {
762                number_of_points_by_return[i as usize - 1] = n;
763            }
764        }
765        Ok(Some(raw::header::LargeFile {
766            number_of_point_records: self.number_of_points,
767            number_of_points_by_return,
768        }))
769    }
770
771    fn point_data_len(&self) -> u64 {
772        self.number_of_points * u64::from(self.point_format.len())
773    }
774}
775
776impl Default for Header {
777    fn default() -> Header {
778        Header {
779            bounds: Default::default(),
780            date: Some(Utc::now().date_naive()),
781            evlrs: Vec::new(),
782            file_source_id: 0,
783            generating_software: format!("las-rs {}", env!("CARGO_PKG_VERSION")),
784            gps_time_type: GpsTimeType::Week,
785            guid: Default::default(),
786            has_synthetic_return_numbers: false,
787            has_wkt_crs: false,
788            number_of_points: 0,
789            number_of_points_by_return: HashMap::new(),
790            padding: Vec::new(),
791            point_format: Default::default(),
792            point_padding: Vec::new(),
793            start_of_first_evlr: None,
794            system_identifier: "las-rs".to_string(),
795            transforms: Default::default(),
796            version: Default::default(),
797            vlr_padding: Vec::new(),
798            vlrs: Vec::new(),
799        }
800    }
801}
802
803impl<V: Into<Version>> From<V> for Header {
804    fn from(version: V) -> Header {
805        Builder::from(version)
806            .into_header()
807            .expect("Default builder could not be converted into a header")
808    }
809}
810
811impl<'a> Iterator for Vlrs<'a> {
812    type Item = &'a Vlr;
813    fn next(&mut self) -> Option<&'a Vlr> {
814        self.0.next()
815    }
816}
817
818#[cfg(test)]
819mod tests {
820    use super::*;
821
822    #[test]
823    fn number_of_points_by_return_zero_return_number() {
824        let mut header = Header::default();
825        header.add_point(&Default::default());
826        assert_eq!(
827            [0; 5],
828            header.into_raw().unwrap().number_of_points_by_return
829        );
830    }
831
832    #[test]
833    fn number_of_points_by_return_las_1_2() {
834        let mut header = Header::from((1, 2));
835        for i in 1..6 {
836            let point = Point {
837                return_number: i,
838                ..Default::default()
839            };
840            for _ in 0..42 {
841                header.add_point(&point);
842            }
843        }
844        assert_eq!(
845            [42; 5],
846            header.into_raw().unwrap().number_of_points_by_return
847        );
848    }
849
850    #[test]
851    fn number_of_points_by_return_las_1_2_return_6() {
852        let mut header = Header::from((1, 2));
853        header.add_point(&Point {
854            return_number: 6,
855            ..Default::default()
856        });
857        assert!(header.into_raw().is_err());
858    }
859
860    #[test]
861    fn synchronize_legacy_fields() {
862        let mut header = Header::from((1, 4));
863        let point = Point {
864            return_number: 2,
865            ..Default::default()
866        };
867        for _ in 0..42 {
868            header.add_point(&point);
869        }
870        let raw_header = header.into_raw().unwrap();
871        assert_eq!(42, raw_header.number_of_point_records);
872        assert_eq!([0, 42, 0, 0, 0], raw_header.number_of_points_by_return);
873        assert_eq!(42, raw_header.large_file.unwrap().number_of_point_records);
874        assert_eq!(
875            [0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
876            raw_header.large_file.unwrap().number_of_points_by_return
877        );
878    }
879
880    #[test]
881    fn zero_legacy_fields_when_too_large() {
882        let mut header = Header::from((1, 4));
883        header.number_of_points = u64::from(u32::MAX) + 1;
884        let _ = header.number_of_points_by_return.insert(6, 42);
885        let raw_header = header.into_raw().unwrap();
886        assert_eq!(0, raw_header.number_of_point_records);
887        assert_eq!(
888            u32::MAX as u64 + 1,
889            raw_header.large_file.unwrap().number_of_point_records
890        );
891        assert_eq!([0; 5], raw_header.number_of_points_by_return);
892        assert_eq!(
893            [0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0],
894            raw_header.large_file.unwrap().number_of_points_by_return
895        );
896    }
897
898    #[test]
899    fn prefer_legacy_fields() {
900        let mut raw_header = raw::Header {
901            version: (1, 4).into(),
902            number_of_point_records: 42,
903            number_of_points_by_return: [42, 0, 0, 0, 0],
904            ..Default::default()
905        };
906        let large_file = raw::header::LargeFile {
907            number_of_point_records: 43,
908            number_of_points_by_return: [43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
909        };
910        raw_header.large_file = Some(large_file);
911        let header = Header::from_raw(raw_header).unwrap();
912        assert_eq!(42, header.number_of_points());
913        assert_eq!(42, header.number_of_points_by_return(1).unwrap());
914    }
915
916    #[test]
917    fn number_of_points_large() {
918        let mut header = Header::from((1, 2));
919        header.number_of_points = u32::MAX as u64 + 1;
920        assert!(header.into_raw().is_err());
921
922        let mut header = Header::from((1, 4));
923        header.number_of_points = u32::MAX as u64 + 1;
924        let raw_header = header.into_raw().unwrap();
925        assert_eq!(0, raw_header.number_of_point_records);
926        assert_eq!(
927            u32::MAX as u64 + 1,
928            raw_header.large_file.unwrap().number_of_point_records
929        );
930
931        let header = Header::from_raw(raw_header).unwrap();
932        assert_eq!(u32::MAX as u64 + 1, header.number_of_points);
933    }
934
935    #[test]
936    fn number_of_points_by_return_large() {
937        let mut header = Header::from((1, 2));
938        let _ = header
939            .number_of_points_by_return
940            .insert(1, u32::MAX as u64 + 1);
941        assert!(header.into_raw().is_err());
942
943        let mut header = Header::from((1, 4));
944        let _ = header
945            .number_of_points_by_return
946            .insert(1, u32::MAX as u64 + 1);
947        let raw_header = header.into_raw().unwrap();
948        assert_eq!(0, raw_header.number_of_points_by_return[0]);
949        assert_eq!(
950            u32::MAX as u64 + 1,
951            raw_header.large_file.unwrap().number_of_points_by_return[0]
952        );
953    }
954
955    #[test]
956    fn wkt_bit() {
957        let mut header = Header::from((1, 4));
958        let raw_header = header.clone().into_raw().unwrap();
959        assert_eq!(0, raw_header.global_encoding);
960        header.has_wkt_crs = true;
961        let raw_header = header.clone().into_raw().unwrap();
962        assert_eq!(16, raw_header.global_encoding);
963        header.has_wkt_crs = false;
964        header.point_format = Format::new(6).unwrap();
965        let raw_header = header.into_raw().unwrap();
966        assert_eq!(16, raw_header.global_encoding);
967    }
968
969    #[test]
970    fn header_too_large() {
971        let builder = Builder::new(raw::Header {
972            padding: vec![0; u16::MAX as usize - 226],
973            version: (1, 2).into(),
974            ..Default::default()
975        })
976        .unwrap();
977        assert!(builder.into_header().unwrap().into_raw().is_err());
978    }
979
980    #[test]
981    fn offset_to_point_data_too_large() {
982        let mut builder = Builder::from((1, 2));
983        builder.vlr_padding = vec![0; u32::MAX as usize - 226];
984        assert!(builder.into_header().unwrap().into_raw().is_err());
985    }
986}