lidar_utils/velodyne/
point.rs

1//! Point data types.
2
3use crate::common::*;
4
5pub use dual_return_point::*;
6pub use dynamic_return_points::*;
7pub use single_return_point::*;
8
9/// Generic point from Velodyne LiDAR device.
10pub trait VelodynePoint {
11    fn laser_id(&self) -> u32;
12    fn timestamp(&self) -> Time;
13    fn original_azimuth_angle(&self) -> Angle;
14    fn corrected_azimuth_angle(&self) -> Angle;
15}
16
17/// Point in strongest or last return mode.
18#[derive(Debug, Clone)]
19pub struct PointData {
20    pub distance: Length,
21    pub intensity: u8,
22    pub position: [Length; 3],
23}
24
25mod single_return_point {
26    use super::*;
27
28    /// Point in strongest or last return mode.
29    #[derive(Debug, Clone)]
30    pub struct SingleReturnPoint {
31        pub laser_id: u32,
32        pub timestamp: Time,
33        pub original_azimuth_angle: Angle,
34        pub corrected_azimuth_angle: Angle,
35        pub data: PointData,
36    }
37
38    impl VelodynePoint for SingleReturnPoint {
39        fn laser_id(&self) -> u32 {
40            self.laser_id
41        }
42
43        fn timestamp(&self) -> Time {
44            self.timestamp
45        }
46
47        fn original_azimuth_angle(&self) -> Angle {
48            self.original_azimuth_angle
49        }
50
51        fn corrected_azimuth_angle(&self) -> Angle {
52            self.corrected_azimuth_angle
53        }
54    }
55}
56
57mod dual_return_point {
58    use super::*;
59
60    /// Point in dual return mode.
61    #[derive(Debug, Clone)]
62    pub struct DualReturnPoint {
63        pub laser_id: u32,
64        pub timestamp: Time,
65        pub original_azimuth_angle: Angle,
66        pub corrected_azimuth_angle: Angle,
67        pub strongest_return_data: PointData,
68        pub last_return_data: PointData,
69    }
70
71    impl DualReturnPoint {
72        pub fn try_from_pair(
73            strongest_return_point: SingleReturnPoint,
74            last_return_point: SingleReturnPoint,
75        ) -> Result<Self> {
76            let SingleReturnPoint {
77                laser_id: laser_id_strongest,
78                timestamp: timestamp_strongest,
79                original_azimuth_angle: original_azimuth_angle_strongest,
80                corrected_azimuth_angle: corrected_azimuth_angle_strongest,
81                data: strongest_return_data,
82            } = strongest_return_point;
83
84            let SingleReturnPoint {
85                laser_id: laser_id_last,
86                timestamp: timestamp_last,
87                original_azimuth_angle: original_azimuth_angle_last,
88                corrected_azimuth_angle: corrected_azimuth_angle_last,
89                data: last_return_data,
90            } = last_return_point;
91
92            ensure!(
93                laser_id_strongest == laser_id_last,
94                "laser ID does not match"
95            );
96            ensure!(
97                timestamp_strongest == timestamp_last,
98                "timestamp does not match"
99            );
100            ensure!(
101                original_azimuth_angle_strongest == original_azimuth_angle_last,
102                "original azimuth angle does not match"
103            );
104            ensure!(
105                corrected_azimuth_angle_strongest == corrected_azimuth_angle_last,
106                "corrected azimuth angle does not match"
107            );
108
109            let dual_return_point = DualReturnPoint {
110                laser_id: laser_id_strongest,
111                timestamp: timestamp_strongest,
112                original_azimuth_angle: original_azimuth_angle_strongest,
113                corrected_azimuth_angle: corrected_azimuth_angle_strongest,
114                strongest_return_data,
115                last_return_data,
116            };
117
118            Ok(dual_return_point)
119        }
120    }
121
122    impl VelodynePoint for DualReturnPoint {
123        fn laser_id(&self) -> u32 {
124            self.laser_id
125        }
126
127        fn timestamp(&self) -> Time {
128            self.timestamp
129        }
130
131        fn original_azimuth_angle(&self) -> Angle {
132            self.original_azimuth_angle
133        }
134
135        fn corrected_azimuth_angle(&self) -> Angle {
136            self.corrected_azimuth_angle
137        }
138    }
139}
140
141mod dynamic_return_points {
142    use super::*;
143
144    /// Collection of points in either single return or dual return mode.
145    #[derive(Debug, Clone)]
146    pub enum DynamicReturnPoints {
147        Single(Vec<SingleReturnPoint>),
148        Dual(Vec<DualReturnPoint>),
149    }
150
151    impl DynamicReturnPoints {
152        pub fn is_empty(&self) -> bool {
153            match self {
154                Self::Single(points) => points.is_empty(),
155                Self::Dual(points) => points.is_empty(),
156            }
157        }
158
159        pub(crate) fn empty_like(&self) -> Self {
160            match self {
161                Self::Single(_) => Self::Single(vec![]),
162                Self::Dual(_) => Self::Dual(vec![]),
163            }
164        }
165    }
166
167    impl IntoIterator for DynamicReturnPoints {
168        type Item = DynamicReturnPoint;
169        type IntoIter = DynamicReturnPointsIter;
170
171        fn into_iter(self) -> Self::IntoIter {
172            let iter: Box<dyn Iterator<Item = DynamicReturnPoint> + Sync + Send> = match self {
173                Self::Single(points) => {
174                    Box::new(points.into_iter().map(DynamicReturnPoint::Single))
175                }
176                Self::Dual(points) => Box::new(points.into_iter().map(DynamicReturnPoint::Dual)),
177            };
178            Self::IntoIter { iter }
179        }
180    }
181
182    impl From<Vec<SingleReturnPoint>> for DynamicReturnPoints {
183        fn from(points: Vec<SingleReturnPoint>) -> Self {
184            Self::Single(points)
185        }
186    }
187
188    impl From<Vec<DualReturnPoint>> for DynamicReturnPoints {
189        fn from(points: Vec<DualReturnPoint>) -> Self {
190            Self::Dual(points)
191        }
192    }
193
194    /// Collection of points in either single return or dual return mode.
195    #[derive(Derivative)]
196    #[derivative(Debug)]
197    pub struct DynamicReturnPointsIter {
198        #[derivative(Debug = "ignore")]
199        iter: Box<dyn Iterator<Item = DynamicReturnPoint> + Sync + Send>,
200    }
201
202    impl Iterator for DynamicReturnPointsIter {
203        type Item = DynamicReturnPoint;
204
205        fn next(&mut self) -> Option<Self::Item> {
206            self.iter.next()
207        }
208    }
209
210    /// collection of points in either single return or dual return mode.
211    #[derive(Debug, Clone)]
212    pub enum DynamicReturnPoint {
213        Single(SingleReturnPoint),
214        Dual(DualReturnPoint),
215    }
216
217    impl DynamicReturnPoint {
218        pub fn laser_id(&self) -> u32 {
219            match self {
220                Self::Single(point) => point.laser_id,
221                Self::Dual(point) => point.laser_id,
222            }
223        }
224
225        pub fn timestamp(&self) -> Time {
226            match self {
227                Self::Single(point) => point.timestamp,
228                Self::Dual(point) => point.timestamp,
229            }
230        }
231
232        pub fn original_azimuth_angle(&self) -> Angle {
233            match self {
234                Self::Single(point) => point.original_azimuth_angle,
235                Self::Dual(point) => point.original_azimuth_angle,
236            }
237        }
238
239        pub fn corrected_azimuth_angle(&self) -> Angle {
240            match self {
241                Self::Single(point) => point.corrected_azimuth_angle,
242                Self::Dual(point) => point.corrected_azimuth_angle,
243            }
244        }
245    }
246}