1use crate::platforms::{
7 DeviceInfo, EyeTrackingData, HandTrackingData, PlatformCapabilities, PlatformIntegration,
8 PlatformTrackingData, PoseData, TrackingConfig, TrackingQuality, TrackingState,
9};
10use crate::position::{PlatformData, PlatformType};
11use crate::types::Position3D;
12use crate::{Error, Result};
13use async_trait::async_trait;
14use std::collections::HashMap;
15use tokio::time::Instant;
16
17pub struct GenericPlatform {
19 device_info: DeviceInfo,
20 capabilities: PlatformCapabilities,
21 tracking_active: bool,
22 config: TrackingConfig,
23
24 simulation_mode: SimulationMode,
26 motion_pattern: MotionPattern,
27 quality_degradation: f32,
28
29 start_time: Option<Instant>,
31 last_update: Option<Instant>,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq)]
36pub enum SimulationMode {
37 Static,
39 Circular,
41 RandomWalk,
43 Figure8,
45 Realistic,
47}
48
49#[derive(Debug, Clone)]
51pub struct MotionPattern {
52 pub speed: f32,
54 pub amplitude: f32,
56 pub base_position: Position3D,
58 pub rotation_speed: f32,
60 pub add_noise: bool,
62}
63
64impl Default for MotionPattern {
65 fn default() -> Self {
66 Self {
67 speed: 1.0,
68 amplitude: 1.0,
69 base_position: Position3D::new(0.0, 1.7, 0.0),
70 rotation_speed: 1.0,
71 add_noise: true,
72 }
73 }
74}
75
76impl GenericPlatform {
77 pub fn new() -> Self {
79 Self {
80 device_info: DeviceInfo {
81 name: "Generic Platform".to_string(),
82 manufacturer: "VoiRS".to_string(),
83 model: "Generic VR/AR Device".to_string(),
84 serial_number: "SIM-000001".to_string(),
85 firmware_version: "1.0.0".to_string(),
86 platform_version: "Generic 1.0".to_string(),
87 },
88 capabilities: PlatformCapabilities {
89 head_tracking_6dof: true,
90 hand_tracking: false,
91 eye_tracking: false,
92 controller_tracking: false,
93 room_scale: false,
94 passthrough: false,
95 refresh_rates: vec![60.0],
96 tracking_range: 5.0,
97 },
98 tracking_active: false,
99 config: TrackingConfig::default(),
100 simulation_mode: SimulationMode::Realistic,
101 motion_pattern: MotionPattern::default(),
102 quality_degradation: 0.0,
103 start_time: None,
104 last_update: None,
105 }
106 }
107
108 pub fn with_simulation_mode(simulation_mode: SimulationMode) -> Self {
110 let mut platform = Self::new();
111 platform.simulation_mode = simulation_mode;
112 platform
113 }
114
115 pub fn configure_motion(&mut self, pattern: MotionPattern) {
117 self.motion_pattern = pattern;
118 }
119
120 pub fn set_quality_degradation(&mut self, degradation: f32) {
122 self.quality_degradation = degradation.clamp(0.0, 1.0);
123 }
124
125 fn generate_tracking_data(&self) -> PlatformTrackingData {
127 let now = Instant::now();
128 let elapsed = if let Some(start_time) = self.start_time {
129 now.duration_since(start_time).as_secs_f32()
130 } else {
131 0.0
132 };
133
134 let head_pose = self.calculate_head_pose(elapsed);
135 let quality = self.calculate_tracking_quality(elapsed);
136
137 PlatformTrackingData {
138 head_pose,
139 left_controller: None, right_controller: None,
141 quality: quality.clone(),
142 timestamp: now,
143 raw_data: PlatformData {
144 device_id: "Generic".to_string(),
145 pose_data: vec![],
146 tracking_confidence: quality.overall_quality,
147 platform_timestamp: (elapsed * 1000.0) as u64,
148 properties: {
149 let mut props = HashMap::new();
150 props.insert(
151 "simulation_mode".to_string(),
152 format!("{:?}", self.simulation_mode),
153 );
154 props.insert("elapsed_time".to_string(), elapsed.to_string());
155 props.insert(
156 "quality_degradation".to_string(),
157 self.quality_degradation.to_string(),
158 );
159 props
160 },
161 },
162 }
163 }
164
165 fn calculate_head_pose(&self, time: f32) -> PoseData {
167 let position = match self.simulation_mode {
168 SimulationMode::Static => self.motion_pattern.base_position,
169 SimulationMode::Circular => self.calculate_circular_motion(time),
170 SimulationMode::RandomWalk => self.calculate_random_walk(time),
171 SimulationMode::Figure8 => self.calculate_figure8_motion(time),
172 SimulationMode::Realistic => self.calculate_realistic_motion(time),
173 };
174
175 let orientation = self.calculate_orientation(time);
176 let (linear_velocity, angular_velocity) = self.calculate_velocities(time);
177
178 PoseData {
179 position,
180 orientation,
181 linear_velocity,
182 angular_velocity,
183 confidence: 1.0 - self.quality_degradation,
184 }
185 }
186
187 fn calculate_circular_motion(&self, time: f32) -> Position3D {
189 let t = time * self.motion_pattern.speed;
190 let radius = self.motion_pattern.amplitude;
191
192 Position3D::new(
193 self.motion_pattern.base_position.x + radius * t.cos(),
194 self.motion_pattern.base_position.y,
195 self.motion_pattern.base_position.z + radius * t.sin(),
196 )
197 }
198
199 fn calculate_random_walk(&self, time: f32) -> Position3D {
201 let seed = (time * 100.0) as u32;
203 let noise_x = ((seed * 1299827) % 1000) as f32 / 1000.0 - 0.5;
204 let noise_z = ((seed * 1399831) % 1000) as f32 / 1000.0 - 0.5;
205
206 Position3D::new(
207 self.motion_pattern.base_position.x + noise_x * self.motion_pattern.amplitude * 0.1,
208 self.motion_pattern.base_position.y,
209 self.motion_pattern.base_position.z + noise_z * self.motion_pattern.amplitude * 0.1,
210 )
211 }
212
213 fn calculate_figure8_motion(&self, time: f32) -> Position3D {
215 let t = time * self.motion_pattern.speed * 0.5;
216 let scale = self.motion_pattern.amplitude;
217
218 Position3D::new(
219 self.motion_pattern.base_position.x + scale * (2.0 * t).sin(),
220 self.motion_pattern.base_position.y,
221 self.motion_pattern.base_position.z + scale * t.sin() * t.cos(),
222 )
223 }
224
225 fn calculate_realistic_motion(&self, time: f32) -> Position3D {
227 let slow_wave = (time * 0.1 * self.motion_pattern.speed).sin() * 0.05;
229 let medium_wave = (time * 0.3 * self.motion_pattern.speed).sin() * 0.02;
230 let fast_wave = (time * 0.8 * self.motion_pattern.speed).sin() * 0.01;
231
232 let x_offset = (slow_wave + medium_wave) * self.motion_pattern.amplitude;
233 let y_offset = (medium_wave + fast_wave) * self.motion_pattern.amplitude * 0.5;
234 let z_offset = slow_wave * self.motion_pattern.amplitude * 0.3;
235
236 let (noise_x, noise_y, noise_z) = if self.motion_pattern.add_noise {
238 let seed = (time * 1000.0) as u32;
239 (
240 ((seed * 1299827) % 1000) as f32 / 10000.0 - 0.05,
241 ((seed * 1399831) % 1000) as f32 / 10000.0 - 0.05,
242 ((seed * 1499833) % 1000) as f32 / 10000.0 - 0.05,
243 )
244 } else {
245 (0.0, 0.0, 0.0)
246 };
247
248 Position3D::new(
249 self.motion_pattern.base_position.x + x_offset + noise_x,
250 self.motion_pattern.base_position.y + y_offset + noise_y,
251 self.motion_pattern.base_position.z + z_offset + noise_z,
252 )
253 }
254
255 fn calculate_orientation(&self, time: f32) -> (f32, f32, f32, f32) {
257 let t = time * self.motion_pattern.rotation_speed;
258
259 let yaw = match self.simulation_mode {
261 SimulationMode::Static => 0.0,
262 SimulationMode::Circular => t * 0.5, SimulationMode::RandomWalk => (t * 0.1).sin() * 0.3,
264 SimulationMode::Figure8 => (t * 0.3).sin() * 0.4,
265 SimulationMode::Realistic => (t * 0.05).sin() * 0.2 + (t * 0.15).sin() * 0.1,
266 };
267
268 let pitch = match self.simulation_mode {
269 SimulationMode::Static => 0.0,
270 _ => (t * 0.07).sin() * 0.1, };
272
273 let roll = match self.simulation_mode {
274 SimulationMode::Static => 0.0,
275 _ => (t * 0.12).sin() * 0.05, };
277
278 let half_yaw = yaw * 0.5;
280 let half_pitch = pitch * 0.5;
281 let half_roll = roll * 0.5;
282
283 let cos_yaw = half_yaw.cos();
284 let sin_yaw = half_yaw.sin();
285 let cos_pitch = half_pitch.cos();
286 let sin_pitch = half_pitch.sin();
287 let cos_roll = half_roll.cos();
288 let sin_roll = half_roll.sin();
289
290 (
291 sin_roll * cos_pitch * cos_yaw - cos_roll * sin_pitch * sin_yaw,
292 cos_roll * sin_pitch * cos_yaw + sin_roll * cos_pitch * sin_yaw,
293 cos_roll * cos_pitch * sin_yaw - sin_roll * sin_pitch * cos_yaw,
294 cos_roll * cos_pitch * cos_yaw + sin_roll * sin_pitch * sin_yaw,
295 )
296 }
297
298 fn calculate_velocities(&self, time: f32) -> (Position3D, Position3D) {
300 let linear_speed = match self.simulation_mode {
302 SimulationMode::Static => 0.0,
303 SimulationMode::Circular => self.motion_pattern.speed * self.motion_pattern.amplitude,
304 SimulationMode::RandomWalk => 0.1,
305 SimulationMode::Figure8 => {
306 self.motion_pattern.speed * self.motion_pattern.amplitude * 0.8
307 }
308 SimulationMode::Realistic => 0.05,
309 };
310
311 let angular_speed = self.motion_pattern.rotation_speed * 0.1;
312
313 (
314 Position3D::new(linear_speed * 0.1, 0.0, linear_speed * 0.1),
315 Position3D::new(angular_speed * 0.05, angular_speed, angular_speed * 0.02),
316 )
317 }
318
319 fn calculate_tracking_quality(&self, time: f32) -> TrackingQuality {
321 let base_quality = 0.75; let time_degradation = if self.quality_degradation > 0.0 {
325 (time * 0.01).sin() * 0.1 * self.quality_degradation
326 } else {
327 0.0
328 };
329
330 let quality_variation = (time * 0.2).sin() * 0.05; let final_quality = (base_quality - time_degradation + quality_variation).clamp(0.1, 1.0);
332
333 let state = if final_quality > 0.8 {
334 TrackingState::Full
335 } else if final_quality > 0.5 {
336 TrackingState::Limited
337 } else if final_quality > 0.2 {
338 TrackingState::Lost
339 } else {
340 TrackingState::NotTracking
341 };
342
343 TrackingQuality {
344 overall_quality: final_quality,
345 position_quality: final_quality * 0.98,
346 orientation_quality: final_quality * 1.02,
347 feature_count: ((final_quality * 50.0) as u32).max(5),
348 state,
349 }
350 }
351}
352
353#[async_trait]
354impl PlatformIntegration for GenericPlatform {
355 async fn initialize(&mut self) -> Result<()> {
356 self.start_time = Some(Instant::now());
357 self.last_update = Some(Instant::now());
358 tracing::info!(
359 "Generic platform initialized with simulation mode: {:?}",
360 self.simulation_mode
361 );
362 Ok(())
363 }
364
365 async fn get_tracking_data(&self) -> Result<PlatformTrackingData> {
366 if !self.tracking_active {
367 return Err(Error::LegacyProcessing(
368 "Generic tracking not active".to_string(),
369 ));
370 }
371
372 Ok(self.generate_tracking_data())
373 }
374
375 async fn is_available(&self) -> bool {
376 true }
378
379 fn get_capabilities(&self) -> PlatformCapabilities {
380 self.capabilities.clone()
381 }
382
383 async fn configure_tracking(&mut self, config: TrackingConfig) -> Result<()> {
384 self.config = config;
385 tracing::info!("Configured generic tracking with config: {:?}", self.config);
386 Ok(())
387 }
388
389 fn get_device_info(&self) -> DeviceInfo {
390 self.device_info.clone()
391 }
392
393 async fn start_tracking(&mut self) -> Result<()> {
394 if self.start_time.is_none() {
395 return Err(Error::LegacyProcessing(
396 "Generic platform not initialized".to_string(),
397 ));
398 }
399
400 self.tracking_active = true;
401 self.last_update = Some(Instant::now());
402 tracing::info!("Started generic tracking");
403 Ok(())
404 }
405
406 async fn stop_tracking(&mut self) -> Result<()> {
407 self.tracking_active = false;
408 tracing::info!("Stopped generic tracking");
409 Ok(())
410 }
411
412 async fn get_hand_tracking(&self) -> Result<Option<HandTrackingData>> {
413 Ok(None)
415 }
416
417 async fn get_eye_tracking(&self) -> Result<Option<EyeTrackingData>> {
418 Ok(None)
420 }
421}
422
423impl Default for GenericPlatform {
424 fn default() -> Self {
425 Self::new()
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432
433 #[tokio::test]
434 async fn test_generic_platform_creation() {
435 let platform = GenericPlatform::new();
436 assert!(!platform.tracking_active);
437 assert_eq!(platform.simulation_mode, SimulationMode::Realistic);
438 assert_eq!(platform.device_info.manufacturer, "VoiRS");
439 }
440
441 #[tokio::test]
442 async fn test_generic_platform_always_available() {
443 let platform = GenericPlatform::new();
444 assert!(platform.is_available().await);
445 }
446
447 #[tokio::test]
448 async fn test_generic_platform_initialization() {
449 let mut platform = GenericPlatform::new();
450 assert!(platform.initialize().await.is_ok());
451 assert!(platform.start_time.is_some());
452 assert!(platform.last_update.is_some());
453 }
454
455 #[tokio::test]
456 async fn test_simulation_modes() {
457 for mode in [
458 SimulationMode::Static,
459 SimulationMode::Circular,
460 SimulationMode::RandomWalk,
461 SimulationMode::Figure8,
462 SimulationMode::Realistic,
463 ] {
464 let mut platform = GenericPlatform::with_simulation_mode(mode);
465 assert!(platform.initialize().await.is_ok());
466 assert!(platform.start_tracking().await.is_ok());
467
468 let tracking_data = platform.get_tracking_data().await;
469 assert!(tracking_data.is_ok());
470
471 let data = tracking_data.unwrap();
472 assert!(data.quality.overall_quality > 0.0);
473
474 if mode == SimulationMode::Static {
476 assert_eq!(
477 data.head_pose.position,
478 platform.motion_pattern.base_position
479 );
480 }
481 }
482 }
483
484 #[tokio::test]
485 async fn test_motion_pattern_configuration() {
486 let mut platform = GenericPlatform::new();
487 let custom_pattern = MotionPattern {
488 speed: 2.0,
489 amplitude: 0.5,
490 base_position: Position3D::new(1.0, 2.0, 3.0),
491 rotation_speed: 0.5,
492 add_noise: false,
493 };
494
495 platform.configure_motion(custom_pattern.clone());
496 assert_eq!(platform.motion_pattern.speed, 2.0);
497 assert_eq!(platform.motion_pattern.amplitude, 0.5);
498 assert_eq!(platform.motion_pattern.base_position.x, 1.0);
499 }
500
501 #[tokio::test]
502 async fn test_quality_degradation() {
503 let mut platform = GenericPlatform::new();
504 assert!(platform.initialize().await.is_ok());
505 assert!(platform.start_tracking().await.is_ok());
506
507 let normal_data = platform.get_tracking_data().await.unwrap();
509 let normal_quality = normal_data.quality.overall_quality;
510
511 platform.set_quality_degradation(0.5);
513 let degraded_data = platform.get_tracking_data().await.unwrap();
514 let degraded_quality = degraded_data.quality.overall_quality;
515
516 assert!(platform.quality_degradation > 0.0);
519 assert!(degraded_quality <= normal_quality + 0.1); }
521
522 #[tokio::test]
523 async fn test_tracking_properties() {
524 let mut platform = GenericPlatform::with_simulation_mode(SimulationMode::Figure8);
525 platform.set_quality_degradation(0.2);
526 assert!(platform.initialize().await.is_ok());
527 assert!(platform.start_tracking().await.is_ok());
528
529 let tracking_data = platform.get_tracking_data().await.unwrap();
530 let props = &tracking_data.raw_data.properties;
531
532 assert_eq!(props.get("simulation_mode").unwrap(), "Figure8");
533 assert_eq!(props.get("quality_degradation").unwrap(), "0.2");
534 assert!(props.contains_key("elapsed_time"));
535 }
536
537 #[tokio::test]
538 async fn test_pose_calculation_deterministic() {
539 let platform = GenericPlatform::with_simulation_mode(SimulationMode::Circular);
540
541 let pose1 = platform.calculate_head_pose(5.0);
543 let pose2 = platform.calculate_head_pose(5.0);
544
545 assert_eq!(pose1.position.x, pose2.position.x);
546 assert_eq!(pose1.position.y, pose2.position.y);
547 assert_eq!(pose1.position.z, pose2.position.z);
548 }
549
550 #[tokio::test]
551 async fn test_capabilities() {
552 let platform = GenericPlatform::new();
553 let capabilities = platform.get_capabilities();
554
555 assert!(capabilities.head_tracking_6dof);
556 assert!(!capabilities.hand_tracking);
557 assert!(!capabilities.eye_tracking);
558 assert!(!capabilities.controller_tracking);
559 assert_eq!(capabilities.refresh_rates, vec![60.0]);
560 }
561}