use crate::cluster_rgb::{ClusterRgbDecoder, ClusterRgbEncoder};
use crate::error::{LepccError, Result};
use crate::intensity::{IntensityDecoder, IntensityEncoder};
use crate::lepcc_xyz::{LepccDecoder, LepccEncoder};
use crate::types::{Point3D, RGB, BlobType};
pub fn compress_xyz(vertices: &[Point3D], max_x_err: f64, max_y_err: f64, max_z_err: f64) -> Result<Vec<u8>> {
if vertices.is_empty() {
return Err(LepccError::WrongParam("No vertices provided".to_string()));
}
let mut encoder = LepccEncoder::new();
encoder.compute_num_bytes_needed(vertices, max_x_err, max_y_err, max_z_err)?;
encoder.encode()
}
pub fn compress_xyz_array(xyz_array: &[f64], max_x_err: f64, max_y_err: f64, max_z_err: f64) -> Result<Vec<u8>> {
if xyz_array.is_empty() {
return Err(LepccError::WrongParam("No coordinates provided".to_string()));
}
if xyz_array.len() % 3 != 0 {
return Err(LepccError::WrongParam(
"XYZ array length must be a multiple of 3".to_string(),
));
}
let vertices: Vec<Point3D> = xyz_array
.chunks_exact(3)
.map(|chunk| Point3D::new(chunk[0], chunk[1], chunk[2]))
.collect();
compress_xyz(&vertices, max_x_err, max_y_err, max_z_err)
}
pub fn decompress_xyz(data: &[u8]) -> Result<Vec<Point3D>> {
LepccDecoder::decode(data)
}
pub fn decompress_xyz_array(data: &[u8]) -> Result<Vec<f64>> {
let points = decompress_xyz(data)?;
let mut result = Vec::with_capacity(points.len() * 3);
for point in points {
result.push(point.x);
result.push(point.y);
result.push(point.z);
}
Ok(result)
}
pub fn compress_rgb(colors: &[RGB]) -> Result<Vec<u8>> {
if colors.is_empty() {
return Err(LepccError::WrongParam("No colors provided".to_string()));
}
let mut encoder = ClusterRgbEncoder::new();
encoder.compute_num_bytes_needed(colors)?;
encoder.encode()
}
pub fn compress_rgb_array(rgb_array: &[u8]) -> Result<Vec<u8>> {
if rgb_array.is_empty() {
return Err(LepccError::WrongParam("No colors provided".to_string()));
}
if rgb_array.len() % 3 != 0 {
return Err(LepccError::WrongParam(
"RGB array length must be a multiple of 3".to_string(),
));
}
let colors: Vec<RGB> = rgb_array
.chunks_exact(3)
.map(|chunk| RGB {
r: chunk[0],
g: chunk[1],
b: chunk[2],
})
.collect();
compress_rgb(&colors)
}
pub fn decompress_rgb(data: &[u8]) -> Result<Vec<RGB>> {
ClusterRgbDecoder::decode(data)
}
pub fn decompress_rgb_array(data: &[u8]) -> Result<Vec<u8>> {
let colors = decompress_rgb(data)?;
let mut result = Vec::with_capacity(colors.len() * 3);
for color in colors {
result.push(color.r);
result.push(color.g);
result.push(color.b);
}
Ok(result)
}
pub fn compress_intensity(intensities: &[u16]) -> Result<Vec<u8>> {
if intensities.is_empty() {
return Err(LepccError::WrongParam("No intensities provided".to_string()));
}
let mut encoder = IntensityEncoder::new();
encoder.compute_num_bytes_needed(intensities)?;
encoder.encode(intensities)
}
pub fn decompress_intensity(data: &[u8]) -> Result<Vec<u16>> {
IntensityDecoder::decode(data)
}
pub fn compress_flag_bytes(flag_bytes: &[u8]) -> Result<Vec<u8>> {
if flag_bytes.is_empty() {
return Err(LepccError::WrongParam("No flag bytes provided".to_string()));
}
let mut encoder = super::flag_bytes::FlagBytesEncoder::new();
encoder.compute_num_bytes_needed(flag_bytes)?;
encoder.encode(flag_bytes)
}
pub fn decompress_flag_bytes(data: &[u8]) -> Result<Vec<u8>> {
super::flag_bytes::FlagBytesDecoder::decode(data)
}
pub fn get_blob_type(data: &[u8]) -> Result<BlobType> {
if data.len() >= 10 && &data[0..10] == b"LEPCC " {
return Ok(BlobType::Xyz);
}
if data.len() >= 10 && &data[0..10] == b"ClusterRGB" {
return Ok(BlobType::Rgb);
}
if data.len() >= 10 && &data[0..10] == b"Intensity " {
return Ok(BlobType::Intensity);
}
if data.len() >= 10 && &data[0..10] == b"FlagBytes " {
return Ok(BlobType::FlagBytes);
}
Err(LepccError::NotLepcc("Unknown blob type".to_string()))
}
pub fn get_blob_size(data: &[u8]) -> Result<u32> {
let blob_type = get_blob_type(data)?;
match blob_type {
BlobType::Xyz => LepccDecoder::get_blob_size(data),
BlobType::Rgb => ClusterRgbDecoder::get_blob_size(data),
BlobType::Intensity => IntensityDecoder::get_blob_size(data),
BlobType::FlagBytes => super::flag_bytes::FlagBytesDecoder::get_blob_size(data),
}
}
pub fn get_num_points(data: &[u8]) -> Result<u32> {
let blob_type = get_blob_type(data)?;
match blob_type {
BlobType::Xyz => LepccDecoder::get_num_points(data),
BlobType::Rgb => ClusterRgbDecoder::get_num_points(data),
BlobType::Intensity => IntensityDecoder::get_num_points(data),
BlobType::FlagBytes => super::flag_bytes::FlagBytesDecoder::get_num_points(data),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compress_decompress_xyz_array() {
let xyz_array = vec![
0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 0.0, 1.0, ];
let compressed = compress_xyz_array(&xyz_array, 0.01, 0.01, 0.01).unwrap();
let decompressed = decompress_xyz_array(&compressed).unwrap();
assert_eq!(decompressed.len(), xyz_array.len());
}
#[test]
fn test_compress_decompress_rgb_array() {
let rgb_array = vec![
255, 0, 0, 0, 255, 0, 0, 0, 255, ];
let compressed = compress_rgb_array(&rgb_array).unwrap();
let decompressed = decompress_rgb_array(&compressed).unwrap();
assert_eq!(decompressed.len(), rgb_array.len());
}
#[test]
fn test_get_blob_type_xyz() {
let vertices = vec![Point3D::origin()];
let compressed = compress_xyz(&vertices, 0.01, 0.01, 0.01).unwrap();
let blob_type = get_blob_type(&compressed).unwrap();
assert_eq!(blob_type, BlobType::Xyz);
}
#[test]
fn test_get_blob_type_rgb() {
let colors = vec![RGB::new(255, 0, 0)];
let compressed = compress_rgb(&colors).unwrap();
let blob_type = get_blob_type(&compressed).unwrap();
assert_eq!(blob_type, BlobType::Rgb);
}
#[test]
fn test_invalid_array_length_xyz() {
let invalid_array = vec![0.0, 0.0];
let result = compress_xyz_array(&invalid_array, 0.01, 0.01, 0.01);
assert!(result.is_err());
}
#[test]
fn test_invalid_array_length_rgb() {
let invalid_array = vec![255u8, 0];
let result = compress_rgb_array(&invalid_array);
assert!(result.is_err());
}
}