trajectory_tracking/
trajectory_tracking.rs

1use spatio::{Point, SetOptions, Spatio};
2use std::time::Duration;
3
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("Spatio - Trajectory Tracking Example");
6    println!("========================================");
7
8    // Create an in-memory database
9    let db = Spatio::memory()?;
10    println!("Created in-memory database");
11
12    // === VEHICLE TRAJECTORY TRACKING ===
13    println!("\n--- Vehicle Trajectory Tracking ---");
14
15    // Simulate a delivery truck route through Manhattan
16    let delivery_truck_route = vec![
17        (Point::new(40.7128, -74.0060), 1640995200), // Start: Financial District
18        (Point::new(40.7180, -74.0020), 1640995260), // Move north
19        (Point::new(40.7230, -73.9980), 1640995320), // Continue north
20        (Point::new(40.7280, -73.9940), 1640995380), // Midtown approach
21        (Point::new(40.7330, -73.9900), 1640995440), // Midtown
22        (Point::new(40.7380, -73.9860), 1640995500), // Times Square area
23        (Point::new(40.7430, -73.9820), 1640995560), // Continue north
24        (Point::new(40.7480, -73.9780), 1640995620), // Central Park area
25        (Point::new(40.7530, -73.9740), 1640995680), // Upper West Side
26        (Point::new(40.7580, -73.9700), 1640995740), // End: Upper Manhattan
27    ];
28
29    db.insert_trajectory("vehicle:truck001", &delivery_truck_route, None)?;
30    println!(
31        "Inserted delivery truck trajectory with {} waypoints",
32        delivery_truck_route.len()
33    );
34
35    // Simulate a taxi route with more frequent updates
36    let taxi_route = vec![
37        (Point::new(40.7484, -73.9857), 1640995200), // Times Square
38        (Point::new(40.7490, -73.9850), 1640995210), // 10 seconds later
39        (Point::new(40.7496, -73.9843), 1640995220), // Moving northeast
40        (Point::new(40.7502, -73.9836), 1640995230), // Continuing
41        (Point::new(40.7508, -73.9829), 1640995240), // Heading to Central Park
42        (Point::new(40.7514, -73.9822), 1640995250), // Almost there
43        (Point::new(40.7520, -73.9815), 1640995260), // At Central Park South
44        (Point::new(40.7526, -73.9808), 1640995270), // Into the park area
45        (Point::new(40.7532, -73.9801), 1640995280), // Deeper into park
46        (Point::new(40.7538, -73.9794), 1640995290), // End point
47    ];
48
49    db.insert_trajectory("vehicle:taxi042", &taxi_route, None)?;
50    println!(
51        "Inserted taxi trajectory with {} high-frequency waypoints",
52        taxi_route.len()
53    );
54
55    // === DRONE FLIGHT PATH ===
56    println!("\n--- Drone Flight Path ---");
57
58    // Simulate a drone surveillance pattern
59    let drone_pattern = vec![
60        (Point::new(40.7589, -73.9851), 1640995300), // Start: Bryant Park
61        (Point::new(40.7600, -73.9851), 1640995330), // North
62        (Point::new(40.7600, -73.9840), 1640995360), // East
63        (Point::new(40.7589, -73.9840), 1640995390), // South
64        (Point::new(40.7589, -73.9851), 1640995420), // Back to start
65        (Point::new(40.7600, -73.9851), 1640995450), // Repeat pattern
66        (Point::new(40.7600, -73.9840), 1640995480), // East again
67        (Point::new(40.7589, -73.9840), 1640995510), // South again
68        (Point::new(40.7589, -73.9851), 1640995540), // Complete square
69    ];
70
71    db.insert_trajectory("drone:survey001", &drone_pattern, None)?;
72    println!(
73        "Inserted drone surveillance pattern with {} waypoints",
74        drone_pattern.len()
75    );
76
77    // === PEDESTRIAN TRACKING ===
78    println!("\n--- Pedestrian Tracking ---");
79
80    // Simulate a jogger's route through Central Park
81    let jogger_route = vec![
82        (Point::new(40.7679, -73.9781), 1640995600), // Enter at 72nd St
83        (Point::new(40.7700, -73.9770), 1640995660), // Move into park
84        (Point::new(40.7720, -73.9750), 1640995720), // North along path
85        (Point::new(40.7740, -73.9730), 1640995780), // Continue north
86        (Point::new(40.7760, -73.9710), 1640995840), // Reservoir area
87        (Point::new(40.7780, -73.9730), 1640995900), // Around reservoir
88        (Point::new(40.7800, -73.9750), 1640995960), // North side
89        (Point::new(40.7820, -73.9770), 1640996020), // Continue around
90        (Point::new(40.7800, -73.9790), 1640996080), // West side
91        (Point::new(40.7780, -73.9810), 1640996140), // Complete loop
92    ];
93
94    let ttl_opts = Some(SetOptions::with_ttl(Duration::from_secs(3600))); // 1 hour TTL
95    db.insert_trajectory("pedestrian:jogger123", &jogger_route, ttl_opts)?;
96    println!(
97        "Inserted jogger trajectory with {} waypoints (1-hour TTL)",
98        jogger_route.len()
99    );
100
101    // === TRAJECTORY QUERIES ===
102    println!("\n--- Trajectory Queries ---");
103
104    // Query full trajectories
105    let truck_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995740)?;
106    println!("Retrieved truck trajectory: {} points", truck_path.len());
107
108    let taxi_path = db.query_trajectory("vehicle:taxi042", 1640995200, 1640995290)?;
109    println!("Retrieved taxi trajectory: {} points", taxi_path.len());
110
111    // Query partial trajectories (time windows)
112    let truck_midjourney = db.query_trajectory("vehicle:truck001", 1640995320, 1640995560)?;
113    println!(
114        "Truck mid-journey segment: {} points",
115        truck_midjourney.len()
116    );
117
118    let taxi_start = db.query_trajectory("vehicle:taxi042", 1640995200, 1640995240)?;
119    println!("Taxi first 40 seconds: {} points", taxi_start.len());
120
121    // === TRAJECTORY ANALYSIS ===
122    println!("\n--- Trajectory Analysis ---");
123
124    // Calculate trajectory distances
125    println!("Calculating trajectory metrics...");
126
127    // Truck route analysis
128    let mut truck_total_distance = 0.0;
129    for i in 1..delivery_truck_route.len() {
130        let distance = delivery_truck_route[i - 1]
131            .0
132            .distance_to(&delivery_truck_route[i].0);
133        truck_total_distance += distance;
134    }
135    let truck_duration =
136        delivery_truck_route.last().unwrap().1 - delivery_truck_route.first().unwrap().1;
137    let truck_avg_speed = (truck_total_distance / truck_duration as f64) * 3.6; // km/h
138
139    println!("Delivery Truck Analysis:");
140    println!("  Total distance: {:.2} km", truck_total_distance / 1000.0);
141    println!("  Duration: {} seconds", truck_duration);
142    println!("  Average speed: {:.1} km/h", truck_avg_speed);
143
144    // Taxi route analysis
145    let mut taxi_total_distance = 0.0;
146    for i in 1..taxi_route.len() {
147        let distance = taxi_route[i - 1].0.distance_to(&taxi_route[i].0);
148        taxi_total_distance += distance;
149    }
150    let taxi_duration = taxi_route.last().unwrap().1 - taxi_route.first().unwrap().1;
151    let taxi_avg_speed = (taxi_total_distance / taxi_duration as f64) * 3.6; // km/h
152
153    println!("\nTaxi Analysis:");
154    println!("  Total distance: {:.2} km", taxi_total_distance / 1000.0);
155    println!("  Duration: {} seconds", taxi_duration);
156    println!("  Average speed: {:.1} km/h", taxi_avg_speed);
157
158    // === REAL-TIME TRACKING SIMULATION ===
159    println!("\n--- Real-Time Tracking Simulation ---");
160
161    // Simulate a bike messenger with real-time updates
162    let current_time = 1640996200u64;
163    let bike_positions = [
164        Point::new(40.7505, -73.9934), // Start
165        Point::new(40.7510, -73.9930), // Moving
166        Point::new(40.7515, -73.9926), // Moving
167        Point::new(40.7520, -73.9922), // Moving
168        Point::new(40.7525, -73.9918), // End
169    ];
170
171    for (i, position) in bike_positions.iter().enumerate() {
172        let timestamp = current_time + (i as u64 * 30); // 30-second intervals
173        let single_point_trajectory = vec![(*position, timestamp)];
174
175        // In real-time, you would append to existing trajectory
176        db.insert_trajectory(
177            &format!("vehicle:bike007:segment_{}", i),
178            &single_point_trajectory,
179            Some(SetOptions::with_ttl(Duration::from_secs(1800))), // 30-minute TTL
180        )?;
181    }
182    println!("Inserted real-time bike messenger updates");
183
184    // === GEOFENCING AND ALERTS ===
185    println!("\n--- Geofencing and Alerts ---");
186
187    // Define a restricted zone (e.g., around a hospital)
188    let restricted_center = Point::new(40.7614, -73.9776); // Near Central Park
189    let restricted_radius = 200.0; // 200 meters
190
191    println!("Checking trajectories for geofence violations...");
192    println!(
193        "Restricted zone: {:.4}°N, {:.4}°E (radius: {}m)",
194        restricted_center.lat, restricted_center.lon, restricted_radius
195    );
196
197    // Check each trajectory for violations
198    let trajectories = [
199        ("vehicle:truck001", &delivery_truck_route),
200        ("vehicle:taxi042", &taxi_route),
201        ("drone:survey001", &drone_pattern),
202        ("pedestrian:jogger123", &jogger_route),
203    ];
204
205    for (vehicle_id, trajectory) in &trajectories {
206        let mut violations = 0;
207        for (point, timestamp) in trajectory.iter() {
208            let distance = point.distance_to(&restricted_center);
209            if distance <= restricted_radius {
210                violations += 1;
211                if violations == 1 {
212                    println!(
213                        "WARNING: {} entered restricted zone at timestamp {}",
214                        vehicle_id, timestamp
215                    );
216                }
217            }
218        }
219        if violations == 0 {
220            println!("{} stayed outside restricted zone", vehicle_id);
221        } else {
222            println!(
223                "   {} had {} geofence violations total",
224                vehicle_id, violations
225            );
226        }
227    }
228
229    // === TRAJECTORY INTERSECTIONS ===
230    println!("\n--- Trajectory Intersections ---");
231
232    // Find where vehicles came close to each other
233    println!("Analyzing trajectory intersections (within 100m)...");
234
235    let proximity_threshold = 100.0; // meters
236    let mut intersections_found = 0;
237
238    for (truck_point, truck_time) in &delivery_truck_route {
239        for (taxi_point, taxi_time) in &taxi_route {
240            let distance = truck_point.distance_to(taxi_point);
241            let time_diff = truck_time.abs_diff(*taxi_time);
242
243            if distance <= proximity_threshold && time_diff <= 60 {
244                intersections_found += 1;
245                println!(
246                    "   Truck and taxi within {:.0}m at times {} and {} ({}s apart)",
247                    distance, truck_time, taxi_time, time_diff
248                );
249            }
250        }
251    }
252
253    if intersections_found == 0 {
254        println!("   No close encounters found between truck and taxi");
255    }
256
257    // === DATABASE STATISTICS ===
258    println!("\n--- Database Statistics ---");
259
260    let stats = db.stats()?;
261
262    println!("Total database keys: {}", stats.key_count);
263
264    // Note: In a real application, you could track trajectory keys separately
265    println!("Trajectory-related operations completed successfully");
266
267    println!("\nTrajectory tracking example completed successfully!");
268    println!("\nKey capabilities demonstrated:");
269    println!("- Multi-vehicle trajectory storage and retrieval");
270    println!("- Time-windowed trajectory queries");
271    println!("- Real-time position updates with TTL");
272    println!("- Trajectory analysis (distance, speed, duration)");
273    println!("- Geofencing and violation detection");
274    println!("- Trajectory intersection analysis");
275    println!("- Mixed vehicle types (truck, taxi, drone, pedestrian, bike)");
276
277    Ok(())
278}