isaac_sim_bridge/lidar/
pointcloud.rs1use std::sync::OnceLock;
3
4use crate::channel::{channel_singleton, Channel};
5use crate::ffi::LidarPointCloudMeta;
6use crate::sensor::Sensor;
7
8pub struct LidarPointCloud;
10
11impl Sensor for LidarPointCloud {
12 const NAME: &'static str = "lidar_pointcloud";
13}
14
15pub type Callback = Box<dyn Fn(&str, &[f32], &LidarPointCloudMeta) + Send + Sync + 'static>;
16
17#[unsafe(no_mangle)]
18pub extern "C" fn isaac_sim_bridge_channel_lidar_pointcloud() -> *const Channel<Callback> {
19 static SLOT: OnceLock<Box<Channel<Callback>>> = OnceLock::new();
20 channel_singleton(&SLOT)
21}
22
23fn channel() -> &'static Channel<Callback> {
24 unsafe { &*isaac_sim_bridge_channel_lidar_pointcloud() }
25}
26
27pub fn register_lidar_pointcloud_consumer<F>(cb: F)
30where
31 F: Fn(&str, &[f32], &LidarPointCloudMeta) + Send + Sync + 'static,
32{
33 channel().register(Box::new(cb));
34}
35
36pub fn dispatch_lidar_pointcloud(source_id: &str, points: &[f32], meta: &LidarPointCloudMeta) {
38 channel().for_each(|cb| cb(source_id, points, meta));
39}
40
41pub fn lidar_pointcloud_consumer_count() -> usize {
43 channel().count()
44}
45
46pub fn forward_lidar_pointcloud(source_id: &str, points: &[f32], meta: &LidarPointCloudMeta) {
48 log::debug!(
49 "[isaac-sim-rs] forward_lidar_pointcloud: source='{}' n={} (floats={}, width={}, height={})",
50 source_id,
51 meta.num_points,
52 points.len(),
53 meta.width,
54 meta.height
55 );
56 dispatch_lidar_pointcloud(source_id, points, meta);
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use std::sync::atomic::{AtomicUsize, Ordering};
63 use std::sync::Arc;
64
65 #[test]
66 fn registered_consumer_receives_dispatch_with_source() {
67 let count = Arc::new(AtomicUsize::new(0));
68 let count_clone = Arc::clone(&count);
69 let n_baseline = lidar_pointcloud_consumer_count();
70
71 register_lidar_pointcloud_consumer(move |src, points, meta| {
72 assert_eq!(src, "/World/Carter/Lidar3D");
73 assert_eq!(points.len(), 9);
74 assert_eq!(meta.num_points, 3);
75 count_clone.fetch_add(1, Ordering::SeqCst);
76 });
77
78 assert_eq!(lidar_pointcloud_consumer_count(), n_baseline + 1);
79
80 let points = [
81 1.0_f32, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0,
84 ];
85 let meta = LidarPointCloudMeta {
86 num_points: 3,
87 width: 3,
88 height: 1,
89 };
90 dispatch_lidar_pointcloud("/World/Carter/Lidar3D", &points, &meta);
91
92 assert_eq!(count.load(Ordering::SeqCst), 1);
93 }
94}