use std::io::{Read, Seek, Write};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crate::byteslice::{ChunksIrregular, ChunksIrregularMut};
use crate::decoders;
use crate::encoders;
use crate::las;
use crate::las::selective::DecompressionSelection;
use crate::laszip::{LazItem, LazItemType};
use crate::LasZipError;
pub trait FieldDecompressor<R: Read> {
fn size_of_field(&self) -> usize;
fn decompress_first(&mut self, src: &mut R, first_point: &mut [u8]) -> std::io::Result<()>;
fn decompress_with(
&mut self,
decoder: &mut decoders::ArithmeticDecoder<R>,
buf: &mut [u8],
) -> std::io::Result<()>;
}
pub trait LayeredFieldDecompressor<R: Read> {
fn size_of_field(&self) -> usize;
fn set_selection(&mut self, selection: DecompressionSelection);
fn init_first_point(
&mut self,
src: &mut R,
first_point: &mut [u8],
context: &mut usize,
) -> std::io::Result<()>;
fn decompress_field_with(
&mut self,
current_point: &mut [u8],
context: &mut usize,
) -> std::io::Result<()>;
fn read_layers_sizes(&mut self, src: &mut R) -> std::io::Result<()>;
fn read_layers(&mut self, src: &mut R) -> std::io::Result<()>;
}
pub trait RecordDecompressor<R> {
fn set_fields_from(&mut self, laz_items: &Vec<LazItem>) -> crate::Result<()>;
fn record_size(&self) -> usize;
fn record_count(&self) -> u64 {
0
}
fn set_selection(&mut self, selection: DecompressionSelection);
fn decompress_next(&mut self, out: &mut [u8]) -> std::io::Result<()>;
#[inline]
fn decompress_many(&mut self, out: &mut [u8]) -> std::io::Result<()> {
for point_buf in out.chunks_exact_mut(self.record_size()) {
self.decompress_next(point_buf)?;
}
Ok(())
}
#[inline]
fn decompress_until_end_of_file(&mut self, out: &mut [u8]) -> std::io::Result<usize> {
for (i, point) in out.chunks_exact_mut(self.record_size()).enumerate() {
if let Err(error) = self.decompress_next(point) {
if error.kind() == std::io::ErrorKind::UnexpectedEof {
return Ok(i * self.record_size());
} else {
return Err(error.into());
}
}
}
Ok(out.len())
}
fn reset(&mut self);
fn get_mut(&mut self) -> &mut R;
fn get(&self) -> &R;
fn into_inner(self) -> R;
fn box_into_inner(self: Box<Self>) -> R;
}
pub struct SequentialPointRecordDecompressor<'a, R: Read> {
field_decompressors: Vec<Box<dyn FieldDecompressor<R> + 'a + Send + Sync>>,
decoder: decoders::ArithmeticDecoder<R>,
is_first_decompression: bool,
record_size: usize,
fields_sizes: Vec<usize>,
}
impl<'a, R: Read> SequentialPointRecordDecompressor<'a, R> {
pub fn new(input: R) -> Self {
Self {
field_decompressors: vec![],
decoder: decoders::ArithmeticDecoder::new(input),
is_first_decompression: true,
record_size: 0,
fields_sizes: vec![],
}
}
pub fn add_field_decompressor<T: FieldDecompressor<R> + 'a + Send + Sync>(&mut self, field: T) {
let field_size = field.size_of_field();
self.record_size += field_size;
self.fields_sizes.push(field_size);
self.field_decompressors.push(Box::new(field));
}
#[allow(dead_code)]
pub(crate) fn add_boxed_decompressor(
&mut self,
d: Box<dyn FieldDecompressor<R> + Send + Sync>,
) {
let field_size = d.size_of_field();
self.record_size += field_size;
self.fields_sizes.push(field_size);
self.field_decompressors.push(d);
}
}
impl<'a, R: Read> RecordDecompressor<R> for SequentialPointRecordDecompressor<'a, R> {
fn set_fields_from(&mut self, laz_items: &Vec<LazItem>) -> crate::Result<()> {
for record_item in laz_items {
match record_item.version {
1 => match record_item.item_type {
LazItemType::Point10 => {
self.add_field_decompressor(las::v1::LasPoint0Decompressor::default())
}
LazItemType::GpsTime => {
self.add_field_decompressor(las::v1::LasGpsTimeDecompressor::default())
}
LazItemType::RGB12 => {
self.add_field_decompressor(las::v1::LasRGBDecompressor::default())
}
LazItemType::Byte(_) => self.add_field_decompressor(
las::v1::LasExtraByteDecompressor::new(record_item.size as usize),
),
LazItemType::WavePacket13 => {
self.add_field_decompressor(las::v1::LasWavepacketDecompressor::default())
}
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
record_item.item_type,
record_item.version,
));
}
},
2 => match record_item.item_type {
LazItemType::Point10 => {
self.add_field_decompressor(las::v2::LasPoint0Decompressor::default())
}
LazItemType::GpsTime => {
self.add_field_decompressor(las::v2::GpsTimeDecompressor::default())
}
LazItemType::RGB12 => {
self.add_field_decompressor(las::v2::LasRGBDecompressor::default())
}
LazItemType::Byte(_) => self.add_field_decompressor(
las::v2::LasExtraByteDecompressor::new(record_item.size as usize),
),
LazItemType::WavePacket13 => {
self.add_field_decompressor(las::v1::LasWavepacketDecompressor::default())
}
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
record_item.item_type,
record_item.version,
));
}
},
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
record_item.item_type,
record_item.version,
));
}
}
}
Ok(())
}
fn record_size(&self) -> usize {
self.record_size
}
fn set_selection(&mut self, _selection: DecompressionSelection) {
}
fn decompress_next(&mut self, out: &mut [u8]) -> std::io::Result<()> {
let decompressors_and_data =
self.field_decompressors
.iter_mut()
.zip(ChunksIrregularMut::new(
out,
self.fields_sizes.iter().copied(),
));
if self.is_first_decompression {
for (fields_decompressor, out_field_data) in decompressors_and_data {
fields_decompressor
.decompress_first(&mut self.decoder.get_mut(), out_field_data)?;
}
self.is_first_decompression = false;
self.decoder.read_init_bytes()?;
} else {
for (fields_decompressor, field_chunk) in decompressors_and_data {
fields_decompressor.decompress_with(&mut self.decoder, field_chunk)?;
}
}
Ok(())
}
fn reset(&mut self) {
self.decoder.reset();
self.is_first_decompression = true;
self.field_decompressors.clear();
self.record_size = 0;
self.fields_sizes.clear();
}
fn get_mut(&mut self) -> &mut R {
self.decoder.get_mut()
}
fn get(&self) -> &R {
self.decoder.get_ref()
}
fn into_inner(self) -> R {
self.decoder.into_inner()
}
fn box_into_inner(self: Box<Self>) -> R {
self.decoder.into_inner()
}
}
pub struct LayeredPointRecordDecompressor<'a, R: Read + Seek> {
field_decompressors: Vec<Box<dyn LayeredFieldDecompressor<R> + 'a + Send + Sync>>,
input: R,
is_first_decompression: bool,
fields_sizes: Vec<usize>,
record_size: usize,
context: usize,
}
impl<'a, R: Read + Seek> LayeredPointRecordDecompressor<'a, R> {
pub fn new(input: R) -> Self {
Self {
field_decompressors: vec![],
input,
is_first_decompression: true,
fields_sizes: vec![],
record_size: 0,
context: 0,
}
}
pub fn add_field_decompressor<T: 'static + LayeredFieldDecompressor<R> + Send + Sync>(
&mut self,
field: T,
) {
let size = field.size_of_field();
self.record_size += size;
self.fields_sizes.push(size);
self.field_decompressors.push(Box::new(field));
}
}
impl<'a, R: Read + Seek> RecordDecompressor<R> for LayeredPointRecordDecompressor<'a, R> {
fn set_fields_from(&mut self, laz_items: &Vec<LazItem>) -> crate::Result<()> {
for record_item in laz_items {
match record_item.version {
3 => match record_item.item_type {
LazItemType::Point14 => {
self.add_field_decompressor(las::v3::LasPoint6Decompressor::default())
}
LazItemType::RGB14 => {
self.add_field_decompressor(las::v3::LasRGBDecompressor::default())
}
LazItemType::RGBNIR14 => {
self.add_field_decompressor(las::v3::LasRGBDecompressor::default());
self.add_field_decompressor(las::v3::LasNIRDecompressor::default());
}
LazItemType::Byte14(count) => self.add_field_decompressor(
las::v3::LasExtraByteDecompressor::new(count as usize),
),
LazItemType::WavePacket14 => {
self.add_field_decompressor(las::v3::LasWavepacketDecompressor::default())
}
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
record_item.item_type,
record_item.version,
));
}
},
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
record_item.item_type,
record_item.version,
));
}
}
}
Ok(())
}
fn set_selection(&mut self, selection: DecompressionSelection) {
if self.is_first_decompression == true {
for field_decompressor in &mut self.field_decompressors {
field_decompressor.set_selection(selection)
}
}
}
fn record_size(&self) -> usize {
self.record_size
}
fn decompress_next(&mut self, out: &mut [u8]) -> std::io::Result<()> {
let decompressors_and_data =
self.field_decompressors
.iter_mut()
.zip(ChunksIrregularMut::new(
out,
self.fields_sizes.iter().copied(),
));
if self.is_first_decompression {
for (field_decompressor, out_field_data) in decompressors_and_data {
field_decompressor.init_first_point(
&mut self.input,
out_field_data,
&mut self.context,
)?;
}
let _count = self.input.read_u32::<LittleEndian>()?;
for field in &mut self.field_decompressors {
field.read_layers_sizes(&mut self.input)?;
}
for field in &mut self.field_decompressors {
field.read_layers(&mut self.input)?;
}
self.is_first_decompression = false;
} else {
self.context = 0;
for (field_decompressor, out_field_data) in decompressors_and_data {
field_decompressor.decompress_field_with(out_field_data, &mut self.context)?;
}
}
Ok(())
}
fn reset(&mut self) {
self.is_first_decompression = true;
self.field_decompressors.clear();
self.record_size = 0;
self.fields_sizes.clear();
}
fn get_mut(&mut self) -> &mut R {
&mut self.input
}
fn get(&self) -> &R {
&self.input
}
fn into_inner(self) -> R {
self.input
}
fn box_into_inner(self: Box<Self>) -> R {
self.input
}
}
pub trait FieldCompressor<W: Write> {
fn size_of_field(&self) -> usize;
fn compress_first(&mut self, dst: &mut W, buf: &[u8]) -> std::io::Result<()>;
fn compress_with(
&mut self,
encoder: &mut encoders::ArithmeticEncoder<W>,
buf: &[u8],
) -> std::io::Result<()>;
}
pub trait LayeredFieldCompressor<W: Write> {
fn size_of_field(&self) -> usize;
fn init_first_point(
&mut self,
dst: &mut W,
first_point: &[u8],
context: &mut usize,
) -> std::io::Result<()>;
fn compress_field_with(
&mut self,
current_point: &[u8],
context: &mut usize,
) -> std::io::Result<()>;
fn write_layers_sizes(&mut self, dst: &mut W) -> std::io::Result<()>;
fn write_layers(&mut self, dst: &mut W) -> std::io::Result<()>;
}
pub trait RecordCompressor<W> {
fn set_fields_from(&mut self, laz_items: &Vec<LazItem>) -> crate::Result<()>;
fn record_size(&self) -> usize;
fn compress_next(&mut self, input: &[u8]) -> std::io::Result<()>;
#[inline]
fn compress_many(&mut self, input: &[u8]) -> std::io::Result<()> {
for point_buf in input.chunks_exact(self.record_size()) {
self.compress_next(point_buf)?;
}
Ok(())
}
fn done(&mut self) -> std::io::Result<()>;
fn reset(&mut self);
fn get_mut(&mut self) -> &mut W;
fn get(&self) -> &W;
fn into_inner(self) -> W;
fn box_into_inner(self: Box<Self>) -> W;
}
pub struct SequentialPointRecordCompressor<'a, W: Write> {
is_first_compression: bool,
field_compressors: Vec<Box<dyn FieldCompressor<W> + Send + Sync + 'a>>,
encoder: encoders::ArithmeticEncoder<W>,
record_size: usize,
fields_sizes: Vec<usize>,
}
impl<'a, W: Write> SequentialPointRecordCompressor<'a, W> {
pub fn new(output: W) -> Self {
Self {
is_first_compression: true,
field_compressors: vec![],
encoder: encoders::ArithmeticEncoder::new(output),
record_size: 0,
fields_sizes: vec![],
}
}
pub fn add_field_compressor<T: FieldCompressor<W> + Send + Sync + 'a>(&mut self, field: T) {
let size = field.size_of_field();
self.record_size += size;
self.fields_sizes.push(size);
self.field_compressors.push(Box::new(field));
}
#[allow(dead_code)]
pub(crate) fn add_boxed_compressor(&mut self, c: Box<dyn FieldCompressor<W> + Send + Sync>) {
let size = c.size_of_field();
self.record_size += size;
self.fields_sizes.push(size);
self.field_compressors.push(c);
}
}
impl<'a, W: Write> RecordCompressor<W> for SequentialPointRecordCompressor<'a, W> {
fn set_fields_from(&mut self, laz_items: &Vec<LazItem>) -> crate::Result<()> {
for record_item in laz_items {
match record_item.version {
1 => match record_item.item_type {
LazItemType::Point10 => {
self.add_field_compressor(las::v1::LasPoint0Compressor::default())
}
LazItemType::GpsTime => {
self.add_field_compressor(las::v1::LasGpsTimeCompressor::default())
}
LazItemType::RGB12 => {
self.add_field_compressor(las::v1::LasRGBCompressor::default())
}
LazItemType::Byte(_) => self.add_field_compressor(
las::v1::LasExtraByteCompressor::new(record_item.size as usize),
),
LazItemType::WavePacket13 => {
self.add_field_compressor(las::v1::LasWavepacketCompressor::default())
}
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
record_item.item_type,
record_item.version,
));
}
},
2 => match record_item.item_type {
LazItemType::Point10 => {
self.add_field_compressor(las::v2::LasPoint0Compressor::default())
}
LazItemType::GpsTime => {
self.add_field_compressor(las::v2::GpsTimeCompressor::default())
}
LazItemType::RGB12 => {
self.add_field_compressor(las::v2::LasRGBCompressor::default())
}
LazItemType::Byte(_) => self.add_field_compressor(
las::v2::LasExtraByteCompressor::new(record_item.size as usize),
),
LazItemType::WavePacket13 => {
self.add_field_compressor(las::v2::LasWavepacketCompressor::default())
}
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
record_item.item_type,
record_item.version,
));
}
},
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
record_item.item_type,
record_item.version,
));
}
}
}
Ok(())
}
fn record_size(&self) -> usize {
self.record_size
}
fn compress_next(&mut self, input: &[u8]) -> std::io::Result<()> {
let field_compressors_and_data = self.field_compressors.iter_mut().zip(
ChunksIrregular::new(input, self.fields_sizes.iter().copied()),
);
if self.is_first_compression {
for (field_compressor, field_data) in field_compressors_and_data {
field_compressor.compress_first(self.encoder.get_mut(), field_data)?;
}
self.is_first_compression = false;
} else {
for (field_compressor, field_data) in field_compressors_and_data {
field_compressor.compress_with(&mut self.encoder, field_data)?;
}
}
Ok(())
}
fn done(&mut self) -> std::io::Result<()> {
self.encoder.done()
}
fn reset(&mut self) {
self.is_first_compression = true;
self.encoder.reset();
self.field_compressors.clear();
self.fields_sizes.clear();
self.record_size = 0;
}
fn get_mut(&mut self) -> &mut W {
self.encoder.get_mut()
}
fn get(&self) -> &W {
self.encoder.get_ref()
}
fn into_inner(self) -> W {
self.encoder.into_inner()
}
fn box_into_inner(self: Box<Self>) -> W {
self.encoder.into_inner()
}
}
pub struct LayeredPointRecordCompressor<'a, W: Write> {
field_compressors: Vec<Box<dyn LayeredFieldCompressor<W> + Send + Sync + 'a>>,
point_count: u32,
dst: W,
record_size: usize,
fields_sizes: Vec<usize>,
}
impl<'a, W: Write> LayeredPointRecordCompressor<'a, W> {
pub fn new(dst: W) -> Self {
Self {
field_compressors: vec![],
record_size: 0,
point_count: 0,
dst,
fields_sizes: vec![],
}
}
pub fn add_field_compressor<T: LayeredFieldCompressor<W> + Send + Sync + 'a>(
&mut self,
field: T,
) {
let size = field.size_of_field();
self.record_size += size;
self.fields_sizes.push(size);
self.field_compressors.push(Box::new(field));
}
}
impl<'a, W: Write> RecordCompressor<W> for LayeredPointRecordCompressor<'a, W> {
fn set_fields_from(&mut self, laz_items: &Vec<LazItem>) -> crate::Result<()> {
for item in laz_items {
match item.version {
3 => match item.item_type {
LazItemType::Point14 => {
self.add_field_compressor(las::v3::LasPoint6Compressor::default())
}
LazItemType::RGB14 => {
self.add_field_compressor(las::v3::LasRGBCompressor::default())
}
LazItemType::RGBNIR14 => {
self.add_field_compressor(las::v3::LasRGBCompressor::default());
self.add_field_compressor(las::v3::LasNIRCompressor::default());
}
LazItemType::Byte14(n) => {
self.add_field_compressor(las::v3::LasExtraByteCompressor::new(n as usize));
}
LazItemType::WavePacket14 => {
self.add_field_compressor(las::v3::LasWavepacketCompressor::default());
}
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
item.item_type,
item.version,
));
}
},
_ => {
return Err(LasZipError::UnsupportedLazItemVersion(
item.item_type,
item.version,
));
}
}
}
Ok(())
}
fn record_size(&self) -> usize {
self.record_size
}
fn compress_next(&mut self, point: &[u8]) -> std::io::Result<()> {
let mut context = 0usize;
let compressors_and_data = self.field_compressors.iter_mut().zip(ChunksIrregular::new(
point,
self.fields_sizes.iter().copied(),
));
if self.point_count == 0 {
for (field_compressor, field_data) in compressors_and_data {
field_compressor.init_first_point(&mut self.dst, field_data, &mut context)?;
}
} else {
for (field_compressor, field_data) in compressors_and_data {
field_compressor.compress_field_with(field_data, &mut context)?;
}
}
self.point_count += 1;
Ok(())
}
fn done(&mut self) -> std::io::Result<()> {
if self.point_count > 0 {
self.dst.write_u32::<LittleEndian>(self.point_count)?;
for compressor in &mut self.field_compressors {
compressor.write_layers_sizes(&mut self.dst)?;
}
for compressor in &mut self.field_compressors {
compressor.write_layers(&mut self.dst)?;
}
}
Ok(())
}
fn reset(&mut self) {
self.point_count = 0;
self.record_size = 0;
self.fields_sizes.clear();
self.field_compressors.clear();
}
fn get_mut(&mut self) -> &mut W {
&mut self.dst
}
fn get(&self) -> &W {
&self.dst
}
fn into_inner(self) -> W {
self.dst
}
fn box_into_inner(self: Box<Self>) -> W {
self.dst
}
}