use std::fmt;
pub type Byte = u8;
pub type U16 = u16;
pub type U32 = u32;
pub type U64 = u64;
pub type I64 = i64;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct RGB {
pub r: u8,
pub g: u8,
pub b: u8,
}
impl RGB {
pub fn new(r: u8, g: u8, b: u8) -> Self {
RGB { r, g, b }
}
pub fn black() -> Self {
RGB::new(0, 0, 0)
}
pub fn white() -> Self {
RGB::new(255, 255, 255)
}
}
impl Default for RGB {
fn default() -> Self {
RGB::new(0, 0, 0)
}
}
impl fmt::Display for RGB {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RGB({}, {}, {})", self.r, self.g, self.b)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Point3D {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Point3D {
pub fn new(x: f64, y: f64, z: f64) -> Self {
Point3D { x, y, z }
}
pub fn origin() -> Self {
Point3D::new(0.0, 0.0, 0.0)
}
pub fn from_xyz_array(arr: &[f64]) -> Self {
Point3D {
x: arr[0],
y: arr[1],
z: arr[2],
}
}
pub fn to_xyz_array(&self) -> [f64; 3] {
[self.x, self.y, self.z]
}
}
impl Default for Point3D {
fn default() -> Self {
Point3D::origin()
}
}
impl std::ops::Sub for Point3D {
type Output = Self;
fn sub(self, other: Self) -> Self {
Point3D {
x: self.x - other.x,
y: self.y - other.y,
z: self.z - other.z,
}
}
}
impl fmt::Display for Point3D {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {}, {})", self.x, self.y, self.z)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Extent3D {
pub lower: Point3D,
pub upper: Point3D,
}
impl Extent3D {
pub fn new(lower: Point3D, upper: Point3D) -> Self {
Extent3D { lower, upper }
}
pub fn empty() -> Self {
let origin = Point3D::origin();
Extent3D {
lower: origin,
upper: origin,
}
}
pub fn contains(&self, point: &Point3D) -> bool {
point.x >= self.lower.x
&& point.x <= self.upper.x
&& point.y >= self.lower.y
&& point.y <= self.upper.y
&& point.z >= self.lower.z
&& point.z <= self.upper.z
}
pub fn size(&self) -> Point3D {
Point3D {
x: self.upper.x - self.lower.x,
y: self.upper.y - self.lower.y,
z: self.upper.z - self.lower.z,
}
}
}
impl Default for Extent3D {
fn default() -> Self {
Extent3D::empty()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrCode {
Ok = 0,
Failed = 1,
WrongParam = 2,
WrongVersion = 3,
WrongChecksum = 4,
NotLepcc = 5,
NotClusterRgb = 6,
NotIntensity = 7,
NotFlagBytes = 8,
BufferTooSmall = 9,
OutArrayTooSmall = 10,
QuantizeVirtualRasterTooBig = 11,
QuantizeIndexOutOfRange = 12,
}
impl fmt::Display for ErrCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
ErrCode::Ok => "Ok",
ErrCode::Failed => "Failed",
ErrCode::WrongParam => "Wrong Parameter",
ErrCode::WrongVersion => "Wrong Version",
ErrCode::WrongChecksum => "Wrong Checksum",
ErrCode::NotLepcc => "Not LEPCC data",
ErrCode::NotClusterRgb => "Not ClusterRGB data",
ErrCode::NotIntensity => "Not Intensity data",
ErrCode::NotFlagBytes => "Not FlagBytes data",
ErrCode::BufferTooSmall => "Buffer Too Small",
ErrCode::OutArrayTooSmall => "Output Array Too Small",
ErrCode::QuantizeVirtualRasterTooBig => "Quantize Virtual Raster Too Big",
ErrCode::QuantizeIndexOutOfRange => "Quantize Index Out Of Range",
};
write!(f, "{}", msg)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlobType {
Xyz = 0,
Rgb = 1,
Intensity = 2,
FlagBytes = 3,
}
impl fmt::Display for BlobType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self {
BlobType::Xyz => "XYZ",
BlobType::Rgb => "RGB",
BlobType::Intensity => "Intensity",
BlobType::FlagBytes => "FlagBytes",
};
write!(f, "{}", name)
}
}
impl TryFrom<u32> for BlobType {
type Error = ErrCode;
fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
match value {
0 => Ok(BlobType::Xyz),
1 => Ok(BlobType::Rgb),
2 => Ok(BlobType::Intensity),
3 => Ok(BlobType::FlagBytes),
_ => Err(ErrCode::WrongParam),
}
}
}
impl From<BlobType> for u32 {
fn from(blob_type: BlobType) -> Self {
blob_type as u32
}
}
pub struct FlatXyzSlice<'a> {
pub data: &'a [f64],
}
impl<'a> FlatXyzSlice<'a> {
pub fn from_slice(data: &'a [f64]) -> Self {
Self { data }
}
pub fn len(&self) -> usize {
self.data.len() / 3
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, index: usize) -> Option<Point3D> {
if index * 3 + 2 < self.data.len() {
Some(Point3D {
x: self.data[index * 3],
y: self.data[index * 3 + 1],
z: self.data[index * 3 + 2],
})
} else {
None
}
}
pub fn iter(&'a self) -> FlatXyzIter<'a> {
FlatXyzIter {
data: self.data,
index: 0,
}
}
}
pub struct FlatXyzIter<'a> {
data: &'a [f64],
index: usize,
}
impl<'a> Iterator for FlatXyzIter<'a> {
type Item = Point3D;
fn next(&mut self) -> Option<Self::Item> {
if self.index * 3 + 2 < self.data.len() {
let result = Point3D {
x: self.data[self.index * 3],
y: self.data[self.index * 3 + 1],
z: self.data[self.index * 3 + 2],
};
self.index += 1;
Some(result)
} else {
None
}
}
}
pub struct FlatRgbSlice<'a> {
pub data: &'a [u8],
}
impl<'a> FlatRgbSlice<'a> {
pub fn from_slice(data: &'a [u8]) -> Self {
Self { data }
}
pub fn len(&self) -> usize {
self.data.len() / 3
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, index: usize) -> Option<RGB> {
if index * 3 + 2 < self.data.len() {
Some(RGB {
r: self.data[index * 3],
g: self.data[index * 3 + 1],
b: self.data[index * 3 + 2],
})
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rgb_eq() {
let rgb1 = RGB { r: 255, g: 0, b: 0 };
let rgb2 = RGB { r: 255, g: 0, b: 0 };
let rgb3 = RGB { r: 0, g: 255, b: 0 };
assert_eq!(rgb1, rgb2);
assert_ne!(rgb1, rgb3);
}
#[test]
fn test_point3d_sub() {
let p1 = Point3D::new(5.0, 4.0, 3.0);
let p2 = Point3D::new(1.0, 2.0, 1.0);
let diff = p1 - p2;
assert_eq!(diff.x, 4.0);
assert_eq!(diff.y, 2.0);
assert_eq!(diff.z, 2.0);
}
#[test]
fn test_extent_contains() {
let extent = Extent3D::new(
Point3D::new(0.0, 0.0, 0.0),
Point3D::new(10.0, 10.0, 10.0),
);
assert!(extent.contains(&Point3D::new(5.0, 5.0, 5.0)));
assert!(!extent.contains(&Point3D::new(-1.0, 5.0, 5.0)));
assert!(!extent.contains(&Point3D::new(11.0, 5.0, 5.0)));
}
#[test]
fn test_flat_xyz_iter() {
let data = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0];
let slice = FlatXyzSlice::from_slice(&data);
assert_eq!(slice.len(), 2);
let points: Vec<Point3D> = slice.iter().collect();
assert_eq!(points.len(), 2);
assert_eq!(points[0], Point3D::new(0.0, 1.0, 2.0));
assert_eq!(points[1], Point3D::new(3.0, 4.0, 5.0));
}
#[test]
fn test_blob_type_conversion() {
assert_eq!(BlobType::try_from(0).unwrap(), BlobType::Xyz);
assert_eq!(BlobType::try_from(1).unwrap(), BlobType::Rgb);
assert_eq!(BlobType::try_from(2).unwrap(), BlobType::Intensity);
assert_eq!(BlobType::try_from(3).unwrap(), BlobType::FlagBytes);
assert!(BlobType::try_from(4).is_err());
assert_eq!(u32::from(BlobType::Xyz), 0);
assert_eq!(u32::from(BlobType::Rgb), 1);
assert_eq!(u32::from(BlobType::Intensity), 2);
assert_eq!(u32::from(BlobType::FlagBytes), 3);
}
}