use bincode::{Decode, Encode};
use cu29::prelude::*;
use cu29::units::si::f32::{Length, Ratio};
use cu29::units::si::length::meter;
use cu29::units::si::ratio::percent;
use cu29_clock::CuTime;
use cu29_soa_derive::Soa;
use serde::{Deserialize, Serialize};
pub type Distance = Length;
pub type Reflectivity = Ratio;
#[derive(
Default, Clone, PartialEq, Debug, Soa, Serialize, Deserialize, Encode, Decode, Reflect,
)]
#[reflect(from_reflect = false)]
pub struct PointCloud {
pub tov: CuTime, pub x: Distance,
pub y: Distance,
pub z: Distance,
pub i: Reflectivity,
pub return_order: u8, }
impl PointCloud {
pub fn new(tov: CuTime, x: f32, y: f32, z: f32, i: f32, return_order: Option<u8>) -> Self {
Self {
tov,
x: Distance::new::<meter>(x),
y: Distance::new::<meter>(y),
z: Distance::new::<meter>(z),
i: Reflectivity::new::<percent>(i),
return_order: return_order.unwrap_or(0),
}
}
pub fn new_units(
tov: CuTime,
x: Length,
y: Length,
z: Length,
i: Ratio,
return_order: Option<u8>,
) -> Self {
Self {
tov,
x,
y,
z,
i,
return_order: return_order.unwrap_or(0),
}
}
}
impl<const N: usize> PointCloudSoa<N> {
pub fn sort(&mut self) {
self.quicksort(0, N - 1);
}
fn quicksort(&mut self, low: usize, high: usize) {
if low < high {
let pivot_index = self.partition(low, high);
if pivot_index > 0 {
self.quicksort(low, pivot_index - 1);
}
self.quicksort(pivot_index + 1, high);
}
}
fn partition(&mut self, low: usize, high: usize) -> usize {
let pivot = self.tov[high];
let mut i = low;
for j in low..high {
if self.tov[j] <= pivot {
self.swap(i, j);
i += 1;
}
}
self.swap(i, high);
i
}
pub fn swap(&mut self, a: usize, b: usize) {
self.tov.swap(a, b);
self.x.swap(a, b);
self.y.swap(a, b);
self.z.swap(a, b);
self.i.swap(a, b);
}
}
#[cfg(test)]
mod tests {
use super::*;
use cu29_clock::CuDuration;
#[test]
fn test_point_payload() {
let payload = PointCloud::new(CuDuration(1), 1.0, 2.0, 3.0, 0.0, None);
assert_eq!(payload.x.value, 1.0);
assert_eq!(payload.y.value, 2.0);
assert_eq!(payload.z.value, 3.0);
}
#[test]
fn test_length_add_sub() {
let a = Distance::new::<meter>(1.0);
let b = Distance::new::<meter>(2.0);
let c = a + b;
assert_eq!(c.value, 3.0);
let d = c - a;
assert_eq!(d.value, 2.0);
}
#[test]
fn test_encoding_length() {
let a = Distance::new::<meter>(1.0);
let mut encoded = vec![0u8; 1024];
let length =
bincode::encode_into_slice(a, &mut encoded, bincode::config::standard()).unwrap();
assert_eq!(length, 4);
}
}