use crate::sensor::SensorData;
use carla_sys::carla_rust::sensor::data::FfiOpticalFlowImage;
use cxx::SharedPtr;
use derivative::Derivative;
use ndarray::ArrayView2;
use std::slice;
pub use carla_sys::carla_rust::sensor::data::FfiOpticalFlowPixel as OpticalFlowPixel;
#[derive(Clone, Derivative)]
#[derivative(Debug)]
#[repr(transparent)]
pub struct OpticalFlowImage {
#[derivative(Debug = "ignore")]
inner: SharedPtr<FfiOpticalFlowImage>,
}
impl OpticalFlowImage {
pub fn height(&self) -> usize {
self.inner.GetHeight()
}
pub fn width(&self) -> usize {
self.inner.GetWidth()
}
pub fn len(&self) -> usize {
self.inner.size()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn fov_angle(&self) -> f32 {
self.inner.GetFOVAngle()
}
pub fn as_slice(&self) -> &[OpticalFlowPixel] {
let ptr = self.inner.data();
let len = self.len();
debug_assert!(!ptr.is_null(), "Optical flow data pointer is null");
debug_assert!(
(ptr as usize).is_multiple_of(std::mem::align_of::<OpticalFlowPixel>()),
"Optical flow data pointer not properly aligned"
);
unsafe { slice::from_raw_parts(ptr, len) }
}
pub fn as_array(&self) -> ArrayView2<'_, OpticalFlowPixel> {
let width = self.width();
let height = self.height();
let len = self.len();
assert!(
width * height == len,
"Optical flow image dimensions mismatch: {}x{} = {} but data length is {}",
width,
height,
width * height,
len
);
ArrayView2::from_shape((width, height), self.as_slice())
.expect("Failed to create array view with validated dimensions")
}
pub fn get(&self, index: usize) -> Option<&OpticalFlowPixel> {
if index < self.len() {
Some(self.inner.at(index))
} else {
None
}
}
pub fn flow_to_pixels(&self, flow: &OpticalFlowPixel) -> (f32, f32) {
let width = self.width() as f32;
let height = self.height() as f32;
(flow.x * width, flow.y * height)
}
pub(crate) fn from_cxx(ptr: SharedPtr<FfiOpticalFlowImage>) -> Option<Self> {
if ptr.is_null() {
None
} else {
Some(Self { inner: ptr })
}
}
}
impl TryFrom<SensorData> for OpticalFlowImage {
type Error = SensorData;
fn try_from(value: SensorData) -> Result<Self, Self::Error> {
let ptr = value.inner.to_optical_flow_image();
Self::from_cxx(ptr).ok_or(value)
}
}
unsafe impl Send for OpticalFlowImage {}
unsafe impl Sync for OpticalFlowImage {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_flow_to_pixels() {
let pixel = OpticalFlowPixel { x: 1.0, y: -0.5 };
let width = 800.0;
let height = 600.0;
let (vx, vy) = (pixel.x * width, pixel.y * height);
assert_eq!(vx, 800.0);
assert_eq!(vy, -300.0);
}
#[test]
fn test_optical_flow_pixel_size() {
assert_eq!(std::mem::size_of::<OpticalFlowPixel>(), 8);
}
}