1pub mod config;
7pub mod converters;
8pub mod gaussian;
9pub mod indexing;
10pub mod pipeline;
11pub mod search;
12
13use serde::{Deserialize, Serialize};
14
15pub use config::{BridgeConfig, DistanceMetric};
17pub use converters::ConversionError;
18pub use gaussian::{GaussianConfig, GaussianSplat, GaussianSplatCloud};
19pub use indexing::{IndexError, SpatialIndex};
20pub use pipeline::{PerceptionResult, PipelineConfig, PipelineStats};
21pub use search::{AlertSeverity, Neighbor, ObstacleAlert, SearchResult};
22
23#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
29pub struct Point3D {
30 pub x: f32,
31 pub y: f32,
32 pub z: f32,
33}
34
35impl Point3D {
36 pub fn new(x: f32, y: f32, z: f32) -> Self {
37 Self { x, y, z }
38 }
39
40 pub fn distance_to(&self, other: &Point3D) -> f32 {
41 let dx = self.x - other.x;
42 let dy = self.y - other.y;
43 let dz = self.z - other.z;
44 (dx * dx + dy * dy + dz * dz).sqrt()
45 }
46
47 pub fn as_f64_array(&self) -> [f64; 3] {
48 [self.x as f64, self.y as f64, self.z as f64]
49 }
50
51 pub fn from_f64_array(arr: &[f64; 3]) -> Self {
52 Self {
53 x: arr[0] as f32,
54 y: arr[1] as f32,
55 z: arr[2] as f32,
56 }
57 }
58
59 pub fn to_vec(&self) -> Vec<f32> {
60 vec![self.x, self.y, self.z]
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
66pub struct Quaternion {
67 pub x: f64,
68 pub y: f64,
69 pub z: f64,
70 pub w: f64,
71}
72
73impl Default for Quaternion {
74 fn default() -> Self {
75 Self { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }
76 }
77}
78
79impl Quaternion {
80 pub fn identity() -> Self {
81 Self::default()
82 }
83
84 pub fn new(x: f64, y: f64, z: f64, w: f64) -> Self {
85 Self { x, y, z, w }
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
91pub struct Pose {
92 pub position: [f64; 3],
93 pub orientation: Quaternion,
94 pub frame_id: String,
95}
96
97impl Default for Pose {
98 fn default() -> Self {
99 Self {
100 position: [0.0; 3],
101 orientation: Quaternion::identity(),
102 frame_id: String::new(),
103 }
104 }
105}
106
107#[derive(Debug, Clone, Default, Serialize, Deserialize)]
109pub struct PointCloud {
110 pub points: Vec<Point3D>,
111 pub intensities: Vec<f32>,
112 pub normals: Option<Vec<Point3D>>,
113 pub timestamp_us: i64,
114 pub frame_id: String,
115}
116
117impl PointCloud {
118 pub fn new(points: Vec<Point3D>, timestamp: i64) -> Self {
119 let len = points.len();
120 Self {
121 points,
122 intensities: vec![1.0; len],
123 normals: None,
124 timestamp_us: timestamp,
125 frame_id: String::new(),
126 }
127 }
128
129 pub fn len(&self) -> usize {
130 self.points.len()
131 }
132
133 pub fn is_empty(&self) -> bool {
134 self.points.is_empty()
135 }
136
137 pub fn timestamp(&self) -> i64 {
138 self.timestamp_us
139 }
140}
141
142#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
144pub struct RobotState {
145 pub position: [f64; 3],
146 pub velocity: [f64; 3],
147 pub acceleration: [f64; 3],
148 pub timestamp_us: i64,
149}
150
151impl Default for RobotState {
152 fn default() -> Self {
153 Self {
154 position: [0.0; 3],
155 velocity: [0.0; 3],
156 acceleration: [0.0; 3],
157 timestamp_us: 0,
158 }
159 }
160}
161
162#[derive(Debug, Clone, Default, Serialize, Deserialize)]
164pub struct SensorFrame {
165 pub cloud: Option<PointCloud>,
166 pub state: Option<RobotState>,
167 pub pose: Option<Pose>,
168 pub timestamp_us: i64,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct OccupancyGrid {
174 pub width: usize,
175 pub height: usize,
176 pub resolution: f64,
177 pub data: Vec<f32>,
178 pub origin: [f64; 3],
179}
180
181impl OccupancyGrid {
182 pub fn new(width: usize, height: usize, resolution: f64) -> Self {
183 let size = width.checked_mul(height).expect("grid size overflow");
184 Self {
185 width,
186 height,
187 resolution,
188 data: vec![0.0; size],
189 origin: [0.0; 3],
190 }
191 }
192
193 pub fn get(&self, x: usize, y: usize) -> Option<f32> {
195 if x < self.width && y < self.height {
196 Some(self.data[y * self.width + x])
197 } else {
198 None
199 }
200 }
201
202 pub fn set(&mut self, x: usize, y: usize, value: f32) {
204 if x < self.width && y < self.height {
205 self.data[y * self.width + x] = value;
206 }
207 }
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct SceneObject {
213 pub id: usize,
214 pub center: [f64; 3],
215 pub extent: [f64; 3],
216 pub confidence: f32,
217 pub label: String,
218 pub velocity: Option<[f64; 3]>,
219}
220
221impl SceneObject {
222 pub fn new(id: usize, center: [f64; 3], extent: [f64; 3]) -> Self {
223 Self {
224 id,
225 center,
226 extent,
227 confidence: 1.0,
228 label: String::new(),
229 velocity: None,
230 }
231 }
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct SceneEdge {
237 pub from: usize,
238 pub to: usize,
239 pub distance: f64,
240 pub relation: String,
241}
242
243#[derive(Debug, Clone, Default, Serialize, Deserialize)]
245pub struct SceneGraph {
246 pub objects: Vec<SceneObject>,
247 pub edges: Vec<SceneEdge>,
248 pub timestamp: i64,
249}
250
251impl SceneGraph {
252 pub fn new(objects: Vec<SceneObject>, edges: Vec<SceneEdge>, timestamp: i64) -> Self {
253 Self { objects, edges, timestamp }
254 }
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct Trajectory {
260 pub waypoints: Vec<[f64; 3]>,
261 pub timestamps: Vec<i64>,
262 pub confidence: f64,
263}
264
265impl Trajectory {
266 pub fn new(waypoints: Vec<[f64; 3]>, timestamps: Vec<i64>, confidence: f64) -> Self {
267 Self { waypoints, timestamps, confidence }
268 }
269
270 pub fn len(&self) -> usize {
271 self.waypoints.len()
272 }
273
274 pub fn is_empty(&self) -> bool {
275 self.waypoints.is_empty()
276 }
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct Obstacle {
282 pub id: u64,
283 pub position: [f64; 3],
284 pub distance: f64,
285 pub radius: f64,
286 pub label: String,
287 pub confidence: f32,
288}
289
290#[derive(Debug, thiserror::Error)]
292pub enum BridgeError {
293 #[error("Invalid data: {0}")]
294 InvalidData(String),
295 #[error("Conversion error: {0}")]
296 ConversionError(String),
297 #[error("Serialization error: {0}")]
298 SerializationError(#[from] serde_json::Error),
299}
300
301pub type Result<T> = std::result::Result<T, BridgeError>;
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306
307 #[test]
308 fn test_point3d_distance() {
309 let a = Point3D::new(0.0, 0.0, 0.0);
310 let b = Point3D::new(3.0, 4.0, 0.0);
311 assert!((a.distance_to(&b) - 5.0).abs() < 1e-6);
312 }
313
314 #[test]
315 fn test_point_cloud() {
316 let cloud = PointCloud::new(vec![Point3D::new(1.0, 2.0, 3.0)], 100);
317 assert_eq!(cloud.len(), 1);
318 assert_eq!(cloud.timestamp(), 100);
319 }
320
321 #[test]
322 fn test_robot_state_default() {
323 let state = RobotState::default();
324 assert_eq!(state.position, [0.0; 3]);
325 assert_eq!(state.velocity, [0.0; 3]);
326 }
327
328 #[test]
329 fn test_scene_graph() {
330 let obj = SceneObject::new(0, [1.0, 2.0, 3.0], [0.5, 0.5, 0.5]);
331 let graph = SceneGraph::new(vec![obj], vec![], 0);
332 assert_eq!(graph.objects.len(), 1);
333 }
334
335 #[test]
336 fn test_quaternion_identity() {
337 let q = Quaternion::identity();
338 assert_eq!(q.w, 1.0);
339 assert_eq!(q.x, 0.0);
340 }
341
342 #[test]
343 fn test_pose_default() {
344 let p = Pose::default();
345 assert_eq!(p.position, [0.0; 3]);
346 assert_eq!(p.orientation.w, 1.0);
347 }
348
349 #[test]
350 fn test_sensor_frame_default() {
351 let f = SensorFrame::default();
352 assert!(f.cloud.is_none());
353 assert!(f.state.is_none());
354 assert!(f.pose.is_none());
355 }
356
357 #[test]
358 fn test_occupancy_grid() {
359 let mut grid = OccupancyGrid::new(10, 10, 0.05);
360 grid.set(3, 4, 0.8);
361 assert!((grid.get(3, 4).unwrap() - 0.8).abs() < f32::EPSILON);
362 assert!(grid.get(10, 10).is_none()); }
364
365 #[test]
366 fn test_trajectory() {
367 let t = Trajectory::new(
368 vec![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]],
369 vec![100, 200],
370 0.95,
371 );
372 assert_eq!(t.len(), 2);
373 assert!(!t.is_empty());
374 }
375
376 #[test]
377 fn test_serde_roundtrip() {
378 let obj = SceneObject::new(0, [1.0, 2.0, 3.0], [0.5, 0.5, 0.5]);
379 let json = serde_json::to_string(&obj).unwrap();
380 let obj2: SceneObject = serde_json::from_str(&json).unwrap();
381 assert_eq!(obj.id, obj2.id);
382 }
383}