1use crate::parsers::{Buffer, RGBA, Reader};
2use alloc::{string::String, vec, vec::Vec};
3use s2json::{BBox3D, MValue, ValuePrimitive, VectorPoint};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Default, Clone, PartialEq, Eq)]
10pub struct LASExtendedVariableLengthRecord {
11 pub reserved: u16,
13 pub user_id: String,
15 pub record_id: u16,
17 pub record_length: u64,
19 pub description: String,
21 pub data: Option<Vec<u8>>,
23}
24impl LASExtendedVariableLengthRecord {
25 pub fn from_reader<T: Reader>(reader: &T, offset: u64) -> Self {
27 let record_length = reader.uint16_le(Some(offset + 20)) as u64;
28 LASExtendedVariableLengthRecord {
29 reserved: reader.uint16_le(Some(offset)),
30 user_id: reader.parse_string(Some(offset + 2), Some(16)),
31 record_id: reader.uint16_le(Some(offset + 18)),
32 record_length,
33 description: reader.parse_string(Some(offset + 22), Some(32)),
34 data: if record_length > 0 {
35 Some(reader.slice(Some(offset + 54), Some(offset + 54 + record_length)))
36 } else {
37 None
38 },
39 }
40 }
41 pub fn from_reader_extended<T: Reader>(reader: &T, offset: u64) -> Self {
43 let record_length = reader.uint64_le(Some(offset + 20));
44 LASExtendedVariableLengthRecord {
45 reserved: reader.uint16_le(Some(offset)),
46 user_id: reader.parse_string(Some(offset + 2), Some(16)),
47 record_id: reader.uint16_le(Some(offset + 18)),
48 record_length,
49 description: reader.parse_string(Some(offset + 28), Some(32)),
50 data: if record_length > 0 {
51 Some(reader.slice(Some(offset + 60), Some(offset + 60 + record_length)))
52 } else {
53 None
54 },
55 }
56 }
57}
58
59#[derive(Debug, Default, Clone, PartialEq)]
62pub struct LASHeader {
63 pub signature: String,
68 pub source_id: u16,
76 pub encoding: u16,
84 pub project_id1: u32,
86 pub project_id2: u16,
88 pub project_id3: u16,
90 pub project_id4: String,
92 pub major_version: u8,
94 pub minor_version: u8,
96 pub system_identifier: String,
98 pub generating_software: String,
100 pub file_creation_day: u16,
105 pub file_creation_year: u16,
109 pub header_size: u16,
119 pub offset_to_points: u32,
125 pub num_variable_length_records: u32,
129 pub point_data_format_id: u8,
134 pub point_data_record_length: u16,
136 pub num_points: u32,
138 pub num_points_by_return: [u32; 5],
140 pub x_scale_factor: f64,
142 pub y_scale_factor: f64,
144 pub z_scale_factor: f64,
146 pub x_offset: f64,
148 pub y_offset: f64,
150 pub z_offset: f64,
152 pub max_x: f64,
154 pub min_x: f64,
156 pub max_y: f64,
158 pub min_y: f64,
160 pub max_z: f64,
162 pub min_z: f64,
164 pub waveform_data_packet_offset: u64,
166 pub extended_variable_length_record_offset: u64,
168 pub extended_variable_length_size: u32,
170 pub num_points_by_return_ll: [u64; 15],
172}
173impl LASHeader {
174 pub fn bbox(&self) -> BBox3D {
176 BBox3D::new(self.min_x, self.min_y, self.min_z, self.max_x, self.max_y, self.max_z)
177 }
178 pub fn from_reader<T: Reader>(reader: &T) -> Self {
180 let mut header = LASHeader {
181 signature: reader.parse_string(Some(0), Some(4)),
183 source_id: reader.uint16_le(Some(4)),
184 encoding: reader.uint16_le(Some(6)),
185 project_id1: reader.uint32_le(Some(8)),
186 project_id2: reader.uint16_le(Some(12)),
187 project_id3: reader.uint16_le(Some(14)),
188 project_id4: reader.parse_string(Some(16), Some(8)),
189 major_version: reader.uint8(Some(24)),
190 minor_version: reader.uint8(Some(25)),
191 system_identifier: reader.parse_string(Some(26), Some(32)),
192 generating_software: reader.parse_string(Some(58), Some(32)),
193 file_creation_day: reader.uint16_le(Some(90)),
194 file_creation_year: reader.uint16_le(Some(92)),
195 header_size: reader.uint16_le(Some(94)),
196 offset_to_points: reader.uint32_le(Some(96)),
197 num_variable_length_records: reader.uint32_le(Some(100)),
198 point_data_format_id: reader.uint8(Some(104)),
199 point_data_record_length: reader.uint16_le(Some(105)),
200 num_points: reader.uint32_le(Some(107)),
201 num_points_by_return: [
202 reader.uint32_le(Some(111)),
203 reader.uint32_le(Some(115)),
204 reader.uint32_le(Some(119)),
205 reader.uint32_le(Some(123)),
206 reader.uint32_le(Some(127)),
207 ],
208 x_scale_factor: reader.f64_le(Some(131)),
209 y_scale_factor: reader.f64_le(Some(139)),
210 z_scale_factor: reader.f64_le(Some(147)),
211 x_offset: reader.f64_le(Some(155)),
212 y_offset: reader.f64_le(Some(163)),
213 z_offset: reader.f64_le(Some(171)),
214 max_x: reader.f64_le(Some(179)),
215 min_x: reader.f64_le(Some(187)),
216 max_y: reader.f64_le(Some(195)),
217 min_y: reader.f64_le(Some(203)),
218 max_z: reader.f64_le(Some(211)),
219 min_z: reader.f64_le(Some(219)),
220 ..Default::default()
221 };
222 if header.header_size > 227 {
224 header.waveform_data_packet_offset = reader.uint64_le(Some(227));
225 }
226 if header.header_size > 235 {
227 header.extended_variable_length_record_offset = reader.uint64_le(Some(235));
228 }
229 if header.header_size > 243 {
230 header.extended_variable_length_size = reader.uint32_le(Some(243));
231 }
232 if header.header_size > 247 {
234 header.num_points = reader.uint32_le(Some(247));
235 }
236 if header.header_size > 251 {
238 let mut cur_offset = 251;
239 for i in 0..15 {
240 header.num_points_by_return_ll[i] = reader.uint64_le(Some(cur_offset));
241 cur_offset += 8;
242 }
243 }
244
245 header
246 }
247}
248
249#[repr(u8)]
253#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
254pub enum LAZHeaderItemType {
255 #[default]
257 Byte = 0,
258 Short = 1,
260 Int = 2,
262 Long = 3,
264 Float = 4,
266 Double = 5,
268 Point10 = 6,
271 GpsTime11 = 7,
274 Rgb12 = 8,
276 WavePacket13 = 9,
279 Point14 = 10,
282 Rgb14 = 11,
284 RgbNir14 = 12,
287 WavePacket14 = 13,
290 Byte14 = 14,
292}
293impl From<u16> for LAZHeaderItemType {
294 fn from(value: u16) -> Self {
295 match value {
296 1 => Self::Short,
297 2 => Self::Int,
298 3 => Self::Long,
299 4 => Self::Float,
300 5 => Self::Double,
301 6 => Self::Point10,
302 7 => Self::GpsTime11,
303 8 => Self::Rgb12,
304 9 => Self::WavePacket13,
305 10 => Self::Point14,
306 11 => Self::Rgb14,
307 12 => Self::RgbNir14,
308 13 => Self::WavePacket14,
309 14 => Self::Byte14,
310 _ => Self::Byte,
311 }
312 }
313}
314
315#[repr(u8)]
317#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
318pub enum LAZCompressor {
319 #[default]
321 None = 0,
322 Pointwise = 1,
324 PointwiseAndChunked = 2,
326 LayeredAndChunked = 3,
328}
329impl From<u16> for LAZCompressor {
330 fn from(value: u16) -> Self {
331 match value {
332 1 => Self::Pointwise,
333 2 => Self::PointwiseAndChunked,
334 3 => Self::LayeredAndChunked,
335 _ => Self::None,
336 }
337 }
338}
339
340#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
342pub struct LAZHeaderItem {
343 pub r#type: LAZHeaderItemType,
345 pub size: u16,
347 pub version: u16,
349}
350
351#[derive(Debug, Default, Clone, PartialEq, Eq)]
353pub struct LAZHeader {
354 pub compressor: LAZCompressor,
356 pub coder: u16,
358 pub version_major: u8,
360 pub version_minor: u8,
362 pub version_revision: u16,
364 pub options: u32,
366 pub chunk_size: u32,
368 pub num_special_evlrs: i64,
370 pub offset_special_evlrs: i64,
372 pub num_items: u16,
374 pub items: Vec<LAZHeaderItem>,
376}
377impl LAZHeader {
378 pub fn from_bytes(data: Vec<u8>) -> Self {
380 let mut raw_header = Buffer::from(data);
381 let mut header = LAZHeader {
382 compressor: LAZCompressor::from(raw_header.get_u16_at(0)),
383 coder: raw_header.get_u16_at(2),
384 version_major: raw_header.get_u8_at(4),
385 version_minor: raw_header.get_u8_at(5),
386 version_revision: raw_header.get_u16_at(6),
387 options: raw_header.get_u32_at(8),
388 chunk_size: raw_header.get_u32_at(12),
389 num_special_evlrs: raw_header.get_i64_at(16),
390 offset_special_evlrs: raw_header.get_i64_at(24),
391 num_items: raw_header.get_u16_at(32),
392 items: vec![],
393 };
394 for i in 0..header.num_items as usize {
396 header.items.push(LAZHeaderItem {
397 r#type: (raw_header.get_u16_at(34 + i * 6)).into(),
398 size: raw_header.get_u16_at(36 + i * 6),
399 version: raw_header.get_u16_at(38 + i * 6),
400 });
401 }
402
403 header
404 }
405}
406
407#[derive(Debug, Default, Clone, PartialEq, MValue, ValuePrimitive, Serialize, Deserialize)]
409pub struct WavePacket {
410 pub descriptor_index: u8,
412 pub offset: u64,
414 pub length: u32,
416 pub return_point: f32,
418 pub x_t: f32,
420 pub y_t: f32,
422 pub z_t: f32,
424}
425impl WavePacket {
426 pub fn from_reader<T: Reader>(reader: &T, offset: u64) -> Self {
428 WavePacket {
429 descriptor_index: reader.uint8(Some(offset)),
430 offset: reader.uint64_le(Some(offset + 1)),
431 length: reader.uint32_le(Some(offset + 9)),
432 return_point: reader.f32_le(Some(offset + 13)),
433 x_t: reader.f32_le(Some(offset + 17)),
434 y_t: reader.f32_le(Some(offset + 21)),
435 z_t: reader.f32_le(Some(offset + 25)),
436 }
437 }
438
439 pub fn to_bytes(&self) -> Vec<u8> {
441 let mut buf = Buffer::default();
442 buf.set_u8_at(0, self.descriptor_index);
443 buf.set_u64_at(1, self.offset);
444 buf.set_u32_at(9, self.length);
445 buf.set_f32_at(13, self.return_point);
446 buf.set_f32_at(17, self.x_t);
447 buf.set_f32_at(21, self.y_t);
448 buf.set_f32_at(25, self.z_t);
449 buf.take()
450 }
451}
452
453#[derive(Debug, Default, Clone, PartialEq)]
455pub enum ClassFlag {
456 Synthetic,
458 KeyPoint,
460 Withheld,
462 Overlap,
464 #[default]
466 Unknown,
467}
468impl From<u8> for ClassFlag {
469 fn from(class: u8) -> Self {
470 match class {
471 0 => ClassFlag::Synthetic,
472 1 => ClassFlag::KeyPoint,
473 2 => ClassFlag::Withheld,
474 3 => ClassFlag::Overlap,
475 _ => ClassFlag::Unknown,
476 }
477 }
478}
479
480#[derive(Debug, Default, Clone, PartialEq, MValue, Serialize, Deserialize)]
482pub struct LASPoint {
483 pub x: i32,
486 pub y: i32,
488 pub z: i32,
490 pub intensity: u16,
492 pub flags: u8,
494 pub return_number: u8,
497 pub number_of_returns: u8,
499 pub scan_direction_flag: bool,
501 pub edge_of_flight_line: bool,
503 pub classification: u8,
506 pub is_synthetic: bool,
509 pub is_key_point: bool,
511 pub is_withheld: bool,
513 pub scan_angle_rank: i8,
516 pub user_data: u8,
518 pub point_source_id: u16,
520
521 pub legacy_point_type: u8,
524 pub legacy_classification: u8,
526 pub legacy_return_number: u8,
528 pub legacy_number_of_returns: u8,
530 pub legacy_scan_angle_rank: i8,
532 pub scanner_channel: u8,
534 pub class_flag: u8,
536 pub scan_angle: i16,
540
541 pub gps_time_change: Option<u8>,
544 pub gps_time: Option<f64>,
546
547 pub rgba: Option<RGBA>,
550
551 pub wave_packet: Option<WavePacket>,
554
555 pub nir: Option<u16>,
558}
559impl LASPoint {
560 pub fn format0<T: Reader>(reader: &T, offset: u64) -> Self {
562 let mut res = LASPoint::default();
563 res.inject_point10(reader, offset);
564 res
565 }
566 pub fn format1<T: Reader>(reader: &T, offset: u64) -> Self {
568 let mut res = LASPoint::default();
569 res.inject_point10(reader, offset);
570 res.inject_gps_time(reader, offset + 20);
571 res
572 }
573 pub fn format2<T: Reader>(reader: &T, offset: u64) -> Self {
575 let mut res = LASPoint::default();
576 res.inject_point10(reader, offset);
577 res.inject_rgb(reader, offset + 20);
578 res
579 }
580 pub fn format3<T: Reader>(reader: &T, offset: u64) -> Self {
582 let mut res = LASPoint::default();
583 res.inject_point10(reader, offset);
584 res.inject_gps_time(reader, offset + 20);
585 res.inject_rgb(reader, offset + 28);
586 res
587 }
588 pub fn format4<T: Reader>(reader: &T, offset: u64) -> Self {
590 let mut res = LASPoint::default();
591 res.inject_point10(reader, offset);
592 res.inject_gps_time(reader, offset + 20);
593 res.inject_wave_packet(reader, offset + 28);
594 res
595 }
596 pub fn format5<T: Reader>(reader: &T, offset: u64) -> Self {
598 let mut res = LASPoint::default();
599 res.inject_point10(reader, offset);
600 res.inject_gps_time(reader, offset + 20);
601 res.inject_rgb(reader, offset + 28);
602 res.inject_wave_packet(reader, offset + 34);
603 res
604 }
605 pub fn format6<T: Reader>(reader: &T, offset: u64) -> Self {
607 let mut res = LASPoint::default();
608 res.inject_point14(reader, offset, false);
609 res
610 }
611 pub fn format7<T: Reader>(reader: &T, offset: u64) -> Self {
613 let mut res = LASPoint::default();
614 res.inject_point14(reader, offset, false);
615 res.inject_rgb(reader, offset + 30);
616 res
617 }
618 pub fn format8<T: Reader>(reader: &T, offset: u64) -> Self {
620 let mut res = LASPoint::default();
621 res.inject_point14(reader, offset, false);
622 res.inject_rgb_nir(reader, offset + 30);
623 res
624 }
625 pub fn format9<T: Reader>(reader: &T, offset: u64) -> Self {
627 let mut res = LASPoint::default();
628 res.inject_point14(reader, offset, false);
629 res.inject_wave_packet(reader, offset + 30);
630 res
631 }
632 pub fn format10<T: Reader>(reader: &T, offset: u64) -> Self {
634 let mut res = LASPoint::default();
635 res.inject_point14(reader, offset, false);
636 res.inject_rgb_nir(reader, offset + 30);
637 res.inject_wave_packet(reader, offset + 38);
638 res
639 }
640 pub fn inject_point10<T: Reader>(&mut self, reader: &T, offset: u64) {
642 let flags1 = reader.uint8(Some(offset + 14));
643 let flags2 = reader.uint8(Some(offset + 15));
644 self.x = reader.int32_le(Some(offset));
645 self.y = reader.int32_le(Some(offset + 4));
646 self.z = reader.int32_le(Some(offset + 8));
647 self.intensity = reader.uint16_le(Some(offset + 12));
648 self.set_flags(flags1, false);
649 self.set_flags2(flags2);
650 self.scan_angle_rank = reader.int8(Some(offset + 16));
651 self.user_data = reader.uint8(Some(offset + 17));
652 self.point_source_id = reader.uint16_le(Some(offset + 18));
653 }
654 pub fn inject_point14_temp<T: Reader>(&mut self, reader: &T, offset: u64) {
656 let flags1 = reader.uint8(Some(offset + 14));
657 let flags2 = reader.uint8(Some(offset + 15));
658 let flags3 = reader.uint8(Some(offset + 16));
659 self.x = reader.int32_le(Some(offset));
660 self.y = reader.int32_le(Some(offset + 4));
661 self.z = reader.int32_le(Some(offset + 8));
662 self.intensity = reader.uint16_le(Some(offset + 12));
663 self.flags = flags1;
664 self.return_number = flags1 & 0b0000_1111;
665 self.number_of_returns = (flags1 & 0b1111_0000) >> 4;
666 self.class_flag = flags2 & 0b0000_1111;
667 self.scanner_channel = (flags2 & 0b0011_0000) >> 4;
668 self.scan_direction_flag = (flags2 & 0b0100_0000) != 0;
669 self.edge_of_flight_line = (flags2 & 0b1000_0000) != 0;
670 self.classification = flags3;
671 self.user_data = reader.uint8(Some(offset + 17));
672 self.scan_angle = reader.int16_le(Some(offset + 18));
673 self.point_source_id = reader.uint16_le(Some(offset + 20));
674 }
675 pub fn inject_point14<T: Reader>(&mut self, reader: &T, offset: u64, compressed: bool) {
677 let flags1 = reader.uint8(Some(offset + 14));
678 let flags2 = reader.uint8(Some(offset + 15));
679 let flags3 = reader.uint8(Some(offset + 22));
680 self.x = reader.int32_le(Some(offset));
681 self.y = reader.int32_le(Some(offset + 4));
682 self.z = reader.int32_le(Some(offset + 8));
683 self.intensity = reader.uint16_le(Some(offset + 12));
684 self.set_flags(flags1, true);
685 self.set_classification(flags2);
686 self.set_flags3(flags3);
687 self.legacy_scan_angle_rank = reader.int8(Some(offset + 16));
688 self.user_data = reader.uint8(Some(offset + 17));
689 self.scan_angle = reader.int16_le(Some(offset + 18));
690 self.point_source_id = reader.uint16_le(Some(offset + 20));
691 if compressed {
693 self.classification = reader.uint8(Some(offset + 23));
694 let flags4 = reader.uint8(Some(offset + 24));
695 self.return_number = flags4 & 0b0000_1111;
696 self.number_of_returns = (flags4 & 0b1111_0000) >> 4;
697 self.gps_time_change = Some(reader.uint8(Some(offset + 28)));
698 self.gps_time = Some(reader.f64_le(Some(offset + 29)));
699 self.inject_rgb(reader, offset + 37);
700 }
701 }
702 pub fn set_flags(&mut self, flags: u8, point14: bool) {
704 self.flags = flags;
705 if point14 {
706 self.legacy_return_number = flags & 0b0000_0111; self.legacy_number_of_returns = (flags & 0b0011_1000) >> 2; } else {
709 self.return_number = flags & 0b0000_0111; self.number_of_returns = (flags & 0b0011_1000) >> 3; }
712 self.scan_direction_flag = (flags & 0b0100_0000) != 0; self.edge_of_flight_line = (flags & 0b1000_0000) != 0; }
715 pub fn set_flags2(&mut self, class: u8) {
717 self.classification = class;
718 self.class_flag = class & 0b1111; self.scanner_channel = (class & 0b0011_0000) >> 4; self.is_synthetic = (class & 0b0010_0000) != 0;
721 self.is_key_point = (class & 0b0100_0000) != 0;
722 self.is_withheld = (class & 0b1000_0000) != 0;
723 }
724 pub fn set_classification(&mut self, class: u8) {
726 self.legacy_classification = class & 0b1_1111;
727 self.is_synthetic = (class & 0b0010_0000) != 0;
728 self.is_key_point = (class & 0b0100_0000) != 0;
729 self.is_withheld = (class & 0b1000_0000) != 0;
730 }
731 pub fn class_flag(&self) -> ClassFlag {
733 self.class_flag.into()
734 }
735 pub fn class_type(&self, point14: bool) -> LASClassification {
737 if point14 { self.legacy_classification.into() } else { self.classification.into() }
738 }
739 pub fn class_type14(&self) -> LASClassification14 {
741 self.classification.into()
742 }
743 pub fn set_flags3(&mut self, class: u8) {
745 self.legacy_point_type = class & 0b11;
746 self.scanner_channel = (class & 0b1100) >> 2;
747 self.class_flag = (class & 0b1111_0000) >> 4;
748 }
749 pub fn inject_gps_time<T: Reader>(&mut self, reader: &T, offset: u64) {
751 self.gps_time = Some(reader.f64_le(Some(offset)));
752 }
753 pub fn inject_rgb<T: Reader>(&mut self, reader: &T, offset: u64) {
755 self.rgba = Some(RGBA::from_reader(reader, Some(offset)));
756 }
757 pub fn inject_nir<T: Reader>(&mut self, reader: &T, offset: u64) {
759 self.nir = Some(reader.uint16_le(Some(offset)));
760 }
761 pub fn inject_rgb_nir<T: Reader>(&mut self, reader: &T, offset: u64) {
763 self.inject_rgb(reader, offset);
764 self.inject_nir(reader, offset + 6);
765 }
766 pub fn inject_wave_packet<T: Reader>(&mut self, reader: &T, offset: u64) {
768 self.wave_packet = Some(WavePacket::from_reader(reader, offset));
769 }
770 pub fn to_vector_point(&self, header: &LASHeader) -> VectorPoint<LASPoint> {
772 let LASHeader {
773 x_offset,
774 y_offset,
775 z_offset,
776 x_scale_factor,
777 y_scale_factor,
778 z_scale_factor,
779 ..
780 } = header;
781 VectorPoint::new_xyz(
782 self.x as f64 * x_scale_factor + x_offset,
783 self.y as f64 * y_scale_factor + y_offset,
784 self.z as f64 * z_scale_factor + z_offset,
785 Some(self.clone()),
786 )
787 }
788 pub fn to_buffer_14(&self, compressed: bool) -> Vec<u8> {
790 let mut buf = Buffer::new(vec![0u8; 48]);
791 buf.set_i32_at(0, self.x);
792 buf.set_i32_at(4, self.y);
793 buf.set_i32_at(8, self.z);
794 buf.set_u16_at(12, self.intensity);
795 buf.set_u8_at(
796 14,
797 (self.return_number & 0b0000_0111)
798 | ((self.number_of_returns & 0b0000_0111) << 3)
799 | ((self.scan_direction_flag as u8) << 6)
800 | ((self.edge_of_flight_line as u8) << 7),
801 );
802 buf.set_u8_at(
803 15,
804 self.legacy_classification
805 | (self.is_synthetic as u8) << 5
806 | (self.is_key_point as u8) << 6
807 | (self.is_withheld as u8) << 7,
808 );
809 buf.set_i8_at(16, self.legacy_scan_angle_rank);
810 buf.set_u8_at(17, self.user_data);
811 buf.set_i16_at(18, self.scan_angle);
813 buf.set_u16_at(20, self.point_source_id);
814 if compressed {
815 buf.set_u8_at(
816 22,
817 self.legacy_point_type | (self.scanner_channel << 2) | (self.class_flag << 4),
818 );
819 buf.set_u8_at(23, self.classification);
820 buf.set_u8_at(24, self.return_number + (self.number_of_returns << 4));
821 buf.set_u8_at(28, self.gps_time_change.unwrap_or(0));
822 buf.set_f64_at(29, self.gps_time.unwrap_or(0.));
823 let (r, g, b, _) = self.rgba.unwrap_or_default().to_u16s();
824 buf.set_u16_at(37, r);
825 buf.set_u16_at(39, g);
826 buf.set_u16_at(41, b);
827 }
828 buf.take()
829 }
830}
831
832#[derive(Debug, Default, Clone, PartialEq)]
834pub enum LASClassification {
835 CreatedNeverClassified,
837 #[default]
839 Unclassified,
840 Ground,
842 LowVegetation,
844 MediumVegetation,
846 HighVegetation,
848 Building,
850 LowPointNoise,
852 ModelKeyPointMassPoint,
854 Water,
856 OverlapPoints,
858 Reserved,
860}
861impl From<u8> for LASClassification {
862 fn from(class: u8) -> Self {
863 match class {
864 0 => Self::CreatedNeverClassified,
865 1 => Self::Unclassified,
866 2 => Self::Ground,
867 3 => Self::LowVegetation,
868 4 => Self::MediumVegetation,
869 5 => Self::HighVegetation,
870 6 => Self::Building,
871 7 => Self::LowPointNoise,
872 8 => Self::ModelKeyPointMassPoint,
873 9 => Self::Water,
874 12 => Self::OverlapPoints,
875 _ => Self::Reserved,
876 }
877 }
878}
879
880#[derive(Debug, Default, Clone, PartialEq)]
882pub enum LASClassification14 {
883 CreatedNeverClassified,
885 #[default]
887 Unclassified,
888 Ground,
890 LowVegetation,
892 MediumVegetation,
894 HighVegetation,
896 Building,
898 LowPointNoise,
900 ModelKeyPointMassPoint,
902 Water,
904 Rail,
906 RoadSurface,
908 WireGuardShield,
910 WireConductorPhase,
912 TransmissionTower,
914 WireStructureConnector,
916 BridgeDeck,
918 HighNoise,
920 OverheadSructure,
922 IgnoredGround,
924 Snow,
926 TemporalExclusion,
929 Reserved,
931 UserDefinable,
933}
934impl From<u8> for LASClassification14 {
935 fn from(class: u8) -> Self {
936 match class {
937 0 => Self::CreatedNeverClassified,
938 1 => Self::Unclassified,
939 2 => Self::Ground,
940 3 => Self::LowVegetation,
941 4 => Self::MediumVegetation,
942 5 => Self::HighVegetation,
943 6 => Self::Building,
944 7 => Self::LowPointNoise,
945 8 => Self::ModelKeyPointMassPoint,
946 9 => Self::Water,
947 10 => Self::Rail,
948 11 => Self::RoadSurface,
949 13 => Self::WireGuardShield,
950 14 => Self::WireConductorPhase,
951 15 => Self::TransmissionTower,
952 16 => Self::WireStructureConnector,
953 17 => Self::BridgeDeck,
954 18 => Self::HighNoise,
955 19 => Self::OverheadSructure,
956 20 => Self::IgnoredGround,
957 21 => Self::Snow,
958 22 => Self::TemporalExclusion,
959 64..=255 => Self::UserDefinable,
961 _ => Self::Reserved,
962 }
963 }
964}