1use scirs2_core::ndarray::Array2;
7
8use crate::error::{Result, VisionError};
9
10#[non_exhaustive]
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
13pub enum Polarity {
14 On,
16 Off,
18}
19
20impl Polarity {
21 pub fn sign(self) -> f64 {
23 match self {
24 Polarity::On => 1.0,
25 Polarity::Off => -1.0,
26 }
27 }
28}
29
30#[derive(Clone, Copy, Debug)]
34pub struct Event {
35 pub x: u16,
37 pub y: u16,
39 pub timestamp: f64,
41 pub polarity: Polarity,
43}
44
45impl Event {
46 pub fn new(x: u16, y: u16, timestamp: f64, polarity: Polarity) -> Self {
48 Self {
49 x,
50 y,
51 timestamp,
52 polarity,
53 }
54 }
55}
56
57pub struct EventSlice {
62 events: Vec<Event>,
63 t_start: f64,
64 t_end: f64,
65 width: u16,
66 height: u16,
67}
68
69impl EventSlice {
70 pub fn new(mut events: Vec<Event>, width: u16, height: u16) -> Result<Self> {
75 if events.is_empty() {
76 return Err(VisionError::InvalidParameter(
77 "EventSlice requires at least one event".to_string(),
78 ));
79 }
80
81 for e in &events {
83 if e.x >= width || e.y >= height {
84 return Err(VisionError::InvalidParameter(format!(
85 "Event coordinate ({}, {}) exceeds sensor dimensions ({}x{})",
86 e.x, e.y, width, height
87 )));
88 }
89 }
90
91 events.sort_by(|a, b| {
93 a.timestamp
94 .partial_cmp(&b.timestamp)
95 .unwrap_or(std::cmp::Ordering::Equal)
96 });
97
98 let t_start = events.first().map(|e| e.timestamp).unwrap_or_default();
99 let t_end = events.last().map(|e| e.timestamp).unwrap_or_default();
100
101 Ok(Self {
102 events,
103 t_start,
104 t_end,
105 width,
106 height,
107 })
108 }
109
110 pub fn events(&self) -> &[Event] {
112 &self.events
113 }
114
115 pub fn time_range(&self) -> (f64, f64) {
117 (self.t_start, self.t_end)
118 }
119
120 pub fn width(&self) -> u16 {
122 self.width
123 }
124
125 pub fn height(&self) -> u16 {
127 self.height
128 }
129
130 pub fn filter_by_polarity(&self, polarity: Polarity) -> Result<Self> {
132 let filtered: Vec<Event> = self
133 .events
134 .iter()
135 .filter(|e| e.polarity == polarity)
136 .copied()
137 .collect();
138
139 if filtered.is_empty() {
140 return Err(VisionError::InvalidParameter(format!(
141 "No events with polarity {:?} found",
142 polarity
143 )));
144 }
145
146 Self::new(filtered, self.width, self.height)
147 }
148
149 pub fn split_at_time(&self, t: f64) -> Result<(Self, Self)> {
155 let before: Vec<Event> = self
156 .events
157 .iter()
158 .filter(|e| e.timestamp < t)
159 .copied()
160 .collect();
161 let after: Vec<Event> = self
162 .events
163 .iter()
164 .filter(|e| e.timestamp >= t)
165 .copied()
166 .collect();
167
168 if before.is_empty() {
169 return Err(VisionError::InvalidParameter(
170 "Split time is before all events; 'before' half would be empty".to_string(),
171 ));
172 }
173 if after.is_empty() {
174 return Err(VisionError::InvalidParameter(
175 "Split time is after all events; 'after' half would be empty".to_string(),
176 ));
177 }
178
179 Ok((
180 Self::new(before, self.width, self.height)?,
181 Self::new(after, self.width, self.height)?,
182 ))
183 }
184
185 pub fn event_rate(&self) -> f64 {
187 let duration = self.t_end - self.t_start;
188 if duration <= 0.0 {
189 return 0.0;
190 }
191 self.events.len() as f64 / duration
192 }
193
194 pub fn len(&self) -> usize {
196 self.events.len()
197 }
198
199 pub fn is_empty(&self) -> bool {
201 self.events.is_empty()
202 }
203
204 pub fn time_window(&self, t0: f64, t1: f64) -> Result<Self> {
206 let sub: Vec<Event> = self
207 .events
208 .iter()
209 .filter(|e| e.timestamp >= t0 && e.timestamp < t1)
210 .copied()
211 .collect();
212
213 if sub.is_empty() {
214 return Err(VisionError::InvalidParameter(format!(
215 "No events in time window [{}, {})",
216 t0, t1
217 )));
218 }
219
220 Self::new(sub, self.width, self.height)
221 }
222}
223
224pub struct EventFrame {
226 pub data: Array2<f64>,
228 pub t_start: f64,
230 pub t_end: f64,
232}
233
234pub struct EventProcessingConfig {
236 pub width: u16,
238 pub height: u16,
240 pub time_window: f64,
242 pub decay_rate: f64,
244 pub polarity_threshold: f64,
246}
247
248impl Default for EventProcessingConfig {
249 fn default() -> Self {
250 Self {
251 width: 240,
252 height: 180,
253 time_window: 0.033, decay_rate: 0.01, polarity_threshold: 0.5,
256 }
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 #[test]
265 fn test_event_creation() {
266 let e = Event::new(10, 20, 1.0, Polarity::On);
267 assert_eq!(e.x, 10);
268 assert_eq!(e.y, 20);
269 assert!((e.timestamp - 1.0).abs() < f64::EPSILON);
270 assert_eq!(e.polarity, Polarity::On);
271 }
272
273 #[test]
274 fn test_polarity_sign() {
275 assert!((Polarity::On.sign() - 1.0).abs() < f64::EPSILON);
276 assert!((Polarity::Off.sign() - (-1.0)).abs() < f64::EPSILON);
277 }
278
279 #[test]
280 fn test_event_slice_basic() {
281 let events = vec![
282 Event::new(0, 0, 0.002, Polarity::On),
283 Event::new(1, 1, 0.001, Polarity::Off),
284 Event::new(2, 2, 0.003, Polarity::On),
285 ];
286 let slice = EventSlice::new(events, 10, 10).expect("failed to create EventSlice");
287 assert_eq!(slice.len(), 3);
288 assert!(!slice.is_empty());
289 assert!(slice.events()[0].timestamp <= slice.events()[1].timestamp);
291 assert!(slice.events()[1].timestamp <= slice.events()[2].timestamp);
292 }
293
294 #[test]
295 fn test_event_slice_out_of_bounds() {
296 let events = vec![Event::new(10, 5, 0.0, Polarity::On)];
297 let result = EventSlice::new(events, 10, 10); assert!(result.is_err());
299 }
300
301 #[test]
302 fn test_event_slice_empty() {
303 let result = EventSlice::new(vec![], 10, 10);
304 assert!(result.is_err());
305 }
306
307 #[test]
308 fn test_filter_by_polarity() {
309 let events = vec![
310 Event::new(0, 0, 0.001, Polarity::On),
311 Event::new(1, 1, 0.002, Polarity::Off),
312 Event::new(2, 2, 0.003, Polarity::On),
313 ];
314 let slice = EventSlice::new(events, 10, 10).expect("failed");
315 let on_slice = slice.filter_by_polarity(Polarity::On).expect("failed");
316 assert_eq!(on_slice.len(), 2);
317 for e in on_slice.events() {
318 assert_eq!(e.polarity, Polarity::On);
319 }
320 }
321
322 #[test]
323 fn test_split_at_time() {
324 let events = vec![
325 Event::new(0, 0, 0.001, Polarity::On),
326 Event::new(1, 1, 0.002, Polarity::Off),
327 Event::new(2, 2, 0.003, Polarity::On),
328 Event::new(3, 3, 0.004, Polarity::Off),
329 ];
330 let slice = EventSlice::new(events, 10, 10).expect("failed");
331 let (before, after) = slice.split_at_time(0.0025).expect("failed");
332 assert_eq!(before.len(), 2);
333 assert_eq!(after.len(), 2);
334 }
335
336 #[test]
337 fn test_event_rate() {
338 let events = vec![
339 Event::new(0, 0, 0.0, Polarity::On),
340 Event::new(1, 1, 0.5, Polarity::Off),
341 Event::new(2, 2, 1.0, Polarity::On),
342 ];
343 let slice = EventSlice::new(events, 10, 10).expect("failed");
344 let rate = slice.event_rate();
345 assert!((rate - 3.0).abs() < 1e-9); }
347
348 #[test]
349 fn test_time_window() {
350 let events = vec![
351 Event::new(0, 0, 0.0, Polarity::On),
352 Event::new(1, 1, 0.5, Polarity::Off),
353 Event::new(2, 2, 1.0, Polarity::On),
354 Event::new(3, 3, 1.5, Polarity::Off),
355 ];
356 let slice = EventSlice::new(events, 10, 10).expect("failed");
357 let sub = slice.time_window(0.3, 1.2).expect("failed");
358 assert_eq!(sub.len(), 2); }
360}