1pub 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#[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#[derive(Debug)]
112pub struct Vlrs<'a>(Chain<Iter<'a, Vlr>, Iter<'a, Vlr>>);
113
114impl Header {
115 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 => {} 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 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 => {} 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 pub fn from_raw(raw_header: raw::Header) -> Result<Header> {
205 Builder::new(raw_header).and_then(|b| b.into_header())
206 }
207
208 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 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 pub fn file_source_id(&self) -> u16 {
262 self.file_source_id
263 }
264
265 pub fn gps_time_type(&self) -> GpsTimeType {
279 self.gps_time_type
280 }
281
282 pub fn has_synthetic_return_numbers(&self) -> bool {
293 self.has_synthetic_return_numbers
294 }
295
296 pub fn has_wkt_crs(&self) -> bool {
306 self.has_wkt_crs
307 }
308
309 pub fn guid(&self) -> Uuid {
318 self.guid
319 }
320
321 pub fn version(&self) -> Version {
330 self.version
331 }
332
333 pub fn system_identifier(&self) -> &str {
344 &self.system_identifier
345 }
346
347 pub fn generating_software(&self) -> &str {
356 &self.generating_software
357 }
358
359 pub fn date(&self) -> Option<NaiveDate> {
370 self.date
371 }
372
373 pub fn padding(&self) -> &Vec<u8> {
384 &self.padding
385 }
386
387 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 pub fn transforms(&self) -> &Vector<Transform> {
420 &self.transforms
421 }
422
423 pub fn bounds(&self) -> Bounds {
434 self.bounds
435 }
436
437 pub fn number_of_points(&self) -> u64 {
447 self.number_of_points
448 }
449
450 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 pub fn vlr_padding(&self) -> &Vec<u8> {
476 &self.vlr_padding
477 }
478
479 pub fn point_padding(&self) -> &Vec<u8> {
490 &self.point_padding
491 }
492
493 pub fn vlrs(&self) -> &Vec<Vlr> {
505 &self.vlrs
506 }
507
508 pub fn evlrs(&self) -> &Vec<Vlr> {
520 &self.evlrs
521 }
522
523 pub fn all_vlrs(&self) -> Vlrs<'_> {
536 Vlrs(self.vlrs.iter().chain(&self.evlrs))
537 }
538
539 pub fn has_crs_vlrs(&self) -> bool {
549 self.all_vlrs().any(|v| v.is_crs())
550 }
551
552 pub fn into_raw(self) -> Result<raw::Header> {
561 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 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 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}