Point

Struct Point 

Source
pub struct Point { /* private fields */ }
Expand description

A geographic point with longitude/latitude coordinates.

This wraps geo::Point and provides additional functionality for GeoJSON conversion, distance calculations, and other operations.

§Examples

use spatio_types::geo::Point;

let nyc = Point::new(-74.0060, 40.7128);
assert_eq!(nyc.x(), -74.0060);
assert_eq!(nyc.y(), 40.7128);

Implementations§

Source§

impl Point

Source

pub fn new(x: f64, y: f64) -> Point

Create a new point from x (longitude) and y (latitude) coordinates.

§Arguments
  • x - Longitude in degrees (typically -180 to 180)
  • y - Latitude in degrees (typically -90 to 90)
§Examples
use spatio_types::geo::Point;

let point = Point::new(-74.0060, 40.7128);
Examples found in repository?
examples/getting_started.rs (line 32)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    // Initialize logging (set RUST_LOG=debug to see detailed logs)
6    env_logger::init();
7
8    println!("=== Spatio - Getting Started ===\n");
9
10    // Create an in-memory database
11    let mut db = Spatio::memory()?;
12    println!("✓ Created in-memory database\n");
13
14    // === BASIC KEY-VALUE STORAGE ===
15    println!("1. Basic Key-Value Storage");
16    println!("---------------------------");
17
18    db.insert("user:123", b"John Doe", None)?;
19    let value = db.get("user:123")?.unwrap();
20    println!("   Stored: user:123 = {}", String::from_utf8_lossy(&value));
21
22    // Store data with TTL (time-to-live)
23    let ttl_options = SetOptions::with_ttl(Duration::from_secs(5));
24    db.insert("session:abc", b"expires_soon", Some(ttl_options))?;
25    println!("   Stored session data with 5-second TTL\n");
26
27    // === SPATIAL OPERATIONS ===
28    println!("2. Spatial Point Storage");
29    println!("------------------------");
30
31    // Store geographic points (lon, lat format)
32    let nyc = Point::new(-74.0060, 40.7128);
33    let london = Point::new(-0.1278, 51.5074);
34    let paris = Point::new(2.3522, 48.8566);
35
36    db.insert_point("cities", &nyc, b"New York", None)?;
37    db.insert_point("cities", &london, b"London", None)?;
38    db.insert_point("cities", &paris, b"Paris", None)?;
39    println!("   Stored 3 cities with automatic spatial indexing");
40
41    // Find nearby cities within radius (in meters)
42    let nearby = db.query_within_radius("cities", &london, 500_000.0, 10)?;
43    println!("   Found {} cities within 500km of London:", nearby.len());
44    for (_, data, _) in &nearby {
45        println!("     - {}", String::from_utf8_lossy(data));
46    }
47    println!();
48
49    // === SPATIAL QUERY METHODS ===
50    println!("3. Spatial Query Methods");
51    println!("------------------------");
52
53    // Check if any points exist within radius
54    let has_nearby = db.intersects_radius("cities", &paris, 1_000_000.0)?;
55    println!("   Cities within 1000km of Paris: {}", has_nearby);
56
57    // Count points within radius
58    let count = db.count_within_radius("cities", &nyc, 6_000_000.0)?;
59    println!("   Cities within 6000km of NYC: {}", count);
60
61    // Find points within bounding box (min_lon, min_lat, max_lon, max_lat)
62    let results = db.find_within_bounds("cities", -10.0, 40.0, 10.0, 55.0, 10)?;
63    println!("   Cities in European bounding box: {}", results.len());
64    for (_point, data) in results {
65        println!("     - {}", String::from_utf8_lossy(&data));
66    }
67    println!();
68
69    // === ATOMIC OPERATIONS ===
70    println!("4. Atomic Batch Operations");
71    println!("---------------------------");
72
73    db.atomic(|batch| {
74        batch.insert("sensor:temp", b"22.5C", None)?;
75        batch.insert("sensor:humidity", b"65%", None)?;
76        batch.insert("sensor:pressure", b"1013 hPa", None)?;
77        Ok(())
78    })?;
79    println!("   Atomically inserted 3 sensor readings\n");
80
81    // === TRAJECTORY TRACKING ===
82    println!("5. Trajectory Tracking");
83    println!("----------------------");
84
85    let vehicle_path = vec![
86        TemporalPoint {
87            point: Point::new(-74.0060, 40.7128),
88            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
89        },
90        TemporalPoint {
91            point: Point::new(-74.0040, 40.7150),
92            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260),
93        },
94        TemporalPoint {
95            point: Point::new(-74.0020, 40.7172),
96            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320),
97        },
98    ];
99
100    db.insert_trajectory("vehicle:truck001", &vehicle_path, None)?;
101    println!(
102        "   Stored vehicle trajectory with {} waypoints",
103        vehicle_path.len()
104    );
105
106    // Query trajectory for time range
107    let path_segment = db.query_trajectory("vehicle:truck001", 1640995200, 1640995320)?;
108    println!(
109        "   Retrieved {} waypoints from trajectory\n",
110        path_segment.len()
111    );
112
113    // === DATABASE STATS ===
114    println!("6. Database Statistics");
115    println!("----------------------");
116
117    let stats = db.stats();
118    println!("   Total keys stored: {}", stats.key_count);
119    println!("   Total operations: {}\n", stats.operations_count);
120
121    // === TTL DEMONSTRATION (LAZY) ===
122    println!("7. TTL Expiration (Lazy Deletion)");
123    println!("----------------------------------");
124    println!("   Waiting 6 seconds for TTL expiration...");
125    std::thread::sleep(Duration::from_secs(6));
126
127    match db.get("session:abc")? {
128        Some(_) => println!("   Session still active (unexpected)"),
129        None => println!("   ✓ Session expired (lazy check on read)"),
130    }
131
132    // Manual cleanup
133    let removed = db.cleanup_expired()?;
134    println!("   Cleaned up {} expired keys from storage\n", removed);
135
136    println!("=== Getting Started Complete! ===");
137    println!("\nKey Features Demonstrated:");
138    println!("  • Simple key-value storage");
139    println!("  • Automatic spatial indexing");
140    println!("  • Radius-based queries");
141    println!("  • Bounding box queries");
142    println!("  • Trajectory tracking");
143    println!("  • TTL support (lazy expiration + manual cleanup)");
144    println!("  • Atomic operations");
145    println!("\nNext: Try 'spatial_queries' example for more advanced queries");
146
147    Ok(())
148}
More examples
Hide additional examples
examples/comprehensive_demo.rs (line 53)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("=== Spatio - Comprehensive Demo ===\n");
6
7    let mut db = Spatio::memory()?;
8    println!("✓ Created in-memory database\n");
9
10    // === 1. BASIC KEY-VALUE OPERATIONS ===
11    println!("1. Basic Key-Value Operations");
12    println!("------------------------------");
13
14    db.insert("app:name", b"Spatio Demo", None)?;
15    db.insert("app:version", b"1.0.0", None)?;
16    db.insert("user:alice", b"Alice Johnson", None)?;
17
18    let app_name = db.get("app:name")?.unwrap();
19    println!("   Stored: {}", String::from_utf8_lossy(&app_name));
20
21    let count = db.stats().key_count;
22    println!("   Total keys: {}\n", count);
23
24    // === 2. TTL (TIME-TO-LIVE) ===
25    println!("2. TTL (Time-to-Live)");
26    println!("---------------------");
27
28    let session_opts = SetOptions::with_ttl(Duration::from_secs(10));
29    db.insert("session:temp", b"expires_soon", Some(session_opts))?;
30    println!("   Created session with 10-second TTL");
31
32    let cache_opts = SetOptions::with_ttl(Duration::from_secs(300));
33    db.insert("cache:weather", b"sunny, 22C", Some(cache_opts))?;
34    println!("   Cached data with 5-minute TTL\n");
35
36    // === 3. ATOMIC BATCH OPERATIONS ===
37    println!("3. Atomic Batch Operations");
38    println!("--------------------------");
39
40    db.atomic(|batch| {
41        batch.insert("sensor:temp", b"23.5", None)?;
42        batch.insert("sensor:humidity", b"68", None)?;
43        batch.insert("sensor:pressure", b"1013", None)?;
44        Ok(())
45    })?;
46    println!("   Atomically inserted 3 sensor readings\n");
47
48    // === 4. SPATIAL POINT STORAGE ===
49    println!("4. Spatial Point Storage");
50    println!("------------------------");
51
52    let cities = vec![
53        ("New York", Point::new(-74.0060, 40.7128)),
54        ("London", Point::new(-0.1278, 51.5074)),
55        ("Paris", Point::new(2.3522, 48.8566)),
56        ("Tokyo", Point::new(139.6503, 35.6762)),
57        ("Sydney", Point::new(151.2093, -33.8688)),
58    ];
59
60    for (name, point) in &cities {
61        db.insert_point("cities", point, name.as_bytes(), None)?;
62    }
63    println!("   Stored {} cities with spatial indexing", cities.len());
64
65    // Find nearby cities
66    let london = Point::new(-0.1278, 51.5074);
67    let nearby = db.query_within_radius("cities", &london, 1_000_000.0, 10)?;
68    println!("   Cities within 1000km of London: {}", nearby.len());
69    for (_, data, _) in &nearby {
70        println!("     - {}", String::from_utf8_lossy(data));
71    }
72    println!();
73
74    // === 5. SPATIAL QUERIES ===
75    println!("5. Spatial Query Methods");
76    println!("------------------------");
77
78    // Existence check
79    let has_nearby = db.intersects_radius("cities", &london, 500_000.0)?;
80    println!("   Cities within 500km of London exist: {}", has_nearby);
81
82    // Count points
83    let count = db.count_within_radius("cities", &london, 2_000_000.0)?;
84    println!("   Cities within 2000km of London: {}", count);
85
86    // Bounding box query (Europe)
87    let europe = db.find_within_bounds("cities", -10.0, 40.0, 20.0, 60.0, 10)?;
88    println!("   Cities in European bounding box: {}", europe.len());
89    for (_point, data) in europe {
90        println!("     - {}", String::from_utf8_lossy(&data));
91    }
92    println!();
93
94    // === 6. POINTS OF INTEREST ===
95    println!("6. Multiple Namespaces (POI)");
96    println!("----------------------------");
97
98    let landmarks = vec![
99        ("Big Ben", Point::new(-0.1245, 51.4994)),
100        ("Tower Bridge", Point::new(-0.0754, 51.5055)),
101        ("London Eye", Point::new(-0.1195, 51.5033)),
102    ];
103
104    for (name, point) in &landmarks {
105        db.insert_point("landmarks", point, name.as_bytes(), None)?;
106    }
107    println!("   Added {} London landmarks", landmarks.len());
108
109    // Query different namespaces
110    let nearby_landmarks = db.query_within_radius("landmarks", &london, 5_000.0, 10)?;
111    println!(
112        "   Landmarks within 5km of London: {}",
113        nearby_landmarks.len()
114    );
115    for (_, data, _) in &nearby_landmarks {
116        println!("     - {}", String::from_utf8_lossy(data));
117    }
118    println!();
119
120    // === 7. TRAJECTORY TRACKING ===
121    println!("7. Trajectory Tracking");
122    println!("----------------------");
123
124    let delivery_route = vec![
125        TemporalPoint {
126            point: Point::new(-0.1278, 51.5074),
127            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
128        },
129        TemporalPoint {
130            point: Point::new(-0.0931, 51.5055),
131            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260),
132        },
133        TemporalPoint {
134            point: Point::new(-0.0865, 51.5045),
135            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320),
136        },
137        TemporalPoint {
138            point: Point::new(-0.1245, 51.4994),
139            timestamp: UNIX_EPOCH + Duration::from_secs(1640995380),
140        },
141    ];
142
143    db.insert_trajectory("delivery:truck001", &delivery_route, None)?;
144    println!(
145        "   Stored delivery trajectory ({} waypoints)",
146        delivery_route.len()
147    );
148
149    // Query trajectory for time range
150    let path = db.query_trajectory("delivery:truck001", 1640995200, 1640995320)?;
151    println!(
152        "   Retrieved {} waypoints for first 2 minutes\n",
153        path.len()
154    );
155
156    // === 8. DATA UPDATES & DELETES ===
157    println!("8. Updates and Deletes");
158    println!("----------------------");
159
160    // Update existing key
161    db.insert("app:version", b"1.0.1", None)?;
162    let new_version = db.get("app:version")?.unwrap();
163    println!(
164        "   Updated version to: {}",
165        String::from_utf8_lossy(&new_version)
166    );
167
168    // Delete key
169    let deleted = db.delete("user:alice")?;
170    println!("   Deleted key: {}", deleted.is_some());
171    println!();
172
173    // === 9. DATABASE STATISTICS ===
174    println!("9. Database Statistics");
175    println!("----------------------");
176
177    let stats = db.stats();
178    println!("   Total keys: {}", stats.key_count);
179    println!("   Total operations: {}\n", stats.operations_count);
180
181    // === 10. TTL EXPIRATION DEMO (LAZY) ===
182    println!("10. TTL Expiration (lazy deletion)");
183    println!("-----------------------------------");
184
185    std::thread::sleep(Duration::from_secs(11));
186
187    match db.get("session:temp")? {
188        Some(_) => println!("   Session still active (unexpected)"),
189        None => println!("   ✓ Session expired (lazy check on read)\n"),
190    }
191
192    // === 11. MANUAL CLEANUP ===
193    println!("11. Manual Cleanup");
194    println!("------------------");
195    let removed = db.cleanup_expired()?;
196    println!("   Removed {} expired keys from storage\n", removed);
197
198    println!("=== Comprehensive Demo Complete! ===");
199    println!("\nFeatures Demonstrated:");
200    println!("  • Key-value storage");
201    println!("  • TTL (lazy expiration + manual cleanup)");
202    println!("  • Atomic batch operations");
203    println!("  • Spatial point indexing");
204    println!("  • Radius queries");
205    println!("  • Bounding box queries");
206    println!("  • Multiple namespaces");
207    println!("  • Trajectory tracking");
208    println!("  • Updates and deletes");
209    println!("  • Manual expired key cleanup");
210
211    Ok(())
212}
examples/spatial_queries.rs (line 13)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("=== Spatio - Spatial Queries ===\n");
5
6    let mut db = Spatio::memory()?;
7    println!("✓ Created in-memory database\n");
8
9    // === SETUP: Insert World Cities ===
10    println!("Setting up test data...");
11
12    let cities = vec![
13        ("New York", Point::new(-74.0060, 40.7128)),
14        ("London", Point::new(-0.1278, 51.5074)),
15        ("Paris", Point::new(2.3522, 48.8566)),
16        ("Berlin", Point::new(13.4050, 52.5200)),
17        ("Madrid", Point::new(-3.7038, 40.4168)),
18        ("Rome", Point::new(12.4964, 41.9028)),
19        ("Tokyo", Point::new(139.6503, 35.6762)),
20        ("Sydney", Point::new(151.2093, -33.8688)),
21        ("Mumbai", Point::new(72.8777, 19.0760)),
22        ("Cairo", Point::new(31.2357, 30.0444)),
23        ("São Paulo", Point::new(-46.6333, -23.5505)),
24        ("Mexico City", Point::new(-99.1332, 19.4326)),
25    ];
26
27    for (name, point) in &cities {
28        db.insert_point("world_cities", point, name.as_bytes(), None)?;
29    }
30    println!("   Added {} cities to spatial index\n", cities.len());
31
32    // === 1. RADIUS QUERIES ===
33    println!("1. Radius-Based Queries (query_within_radius)");
34    println!("----------------------------------------------");
35
36    let london = Point::new(-0.1278, 51.5074);
37
38    // Find cities within 500km of London
39    let nearby_500km = db.query_within_radius("world_cities", &london, 500_000.0, 10)?;
40    println!("   Cities within 500km of London: {}", nearby_500km.len());
41    for (_, data, _) in &nearby_500km {
42        println!("     - {}", String::from_utf8_lossy(data));
43    }
44
45    // Find cities within 2000km of London
46    let nearby_2000km = db.query_within_radius("world_cities", &london, 2_000_000.0, 10)?;
47    println!(
48        "\n   Cities within 2000km of London: {}",
49        nearby_2000km.len()
50    );
51    for (_, data, _) in &nearby_2000km {
52        println!("     - {}", String::from_utf8_lossy(data));
53    }
54
55    // Use limit to get only closest N cities
56    let closest_3 = db.query_within_radius("world_cities", &london, f64::INFINITY, 3)?;
57    println!("\n   Closest 3 cities to London:");
58    for (i, (_, data, _)) in closest_3.iter().enumerate() {
59        println!("     {}. {}", i + 1, String::from_utf8_lossy(data));
60    }
61    println!();
62
63    // === 2. EXISTENCE CHECKS ===
64    println!("2. Existence Checks (contains_point)");
65    println!("-------------------------------------");
66
67    let has_nearby_500km = db.intersects_radius("world_cities", &london, 500_000.0)?;
68    let has_nearby_100km = db.intersects_radius("world_cities", &london, 100_000.0)?;
69
70    println!("   Any cities within 500km of London? {}", has_nearby_500km);
71    println!("   Any cities within 100km of London? {}", has_nearby_100km);
72
73    // === 3. COUNTING POINTS ===
74    println!("3. Counting Points (count_within_radius)");
75    println!("----------------------------------------");
76
77    let count_500km = db.count_within_radius("world_cities", &london, 500_000.0)?;
78    let count_1000km = db.count_within_radius("world_cities", &london, 1_000_000.0)?;
79    let count_2000km = db.count_within_radius("world_cities", &london, 2_000_000.0)?;
80
81    println!("   Cities within 500km of London: {}", count_500km);
82    println!("   Cities within 1000km of London: {}", count_1000km);
83    println!("   Cities within 2000km of London: {}", count_2000km);
84    println!();
85
86    // === 4. BOUNDING BOX QUERIES ===
87    println!("4. Bounding Box Queries");
88    println!("-----------------------");
89
90    // European bounding box (min_lon, min_lat, max_lon, max_lat)
91    println!("   European region (lon: -10 to 20, lat: 40 to 60):");
92    let europe_cities = db.find_within_bounds("world_cities", -10.0, 40.0, 20.0, 60.0, 20)?;
93    println!("     Found {} cities:", europe_cities.len());
94    for (point, data) in &europe_cities {
95        println!(
96            "       - {} at ({:.2}°, {:.2}°)",
97            String::from_utf8_lossy(data),
98            point.x(),
99            point.y()
100        );
101    }
102
103    // Asia-Pacific region
104    println!("\n   Asia-Pacific region (lon: 70 to 180, lat: -40 to 40):");
105    let asia_cities = db.find_within_bounds("world_cities", 70.0, -40.0, 180.0, 40.0, 20)?;
106    println!("     Found {} cities:", asia_cities.len());
107    for (_, data) in &asia_cities {
108        println!("       - {}", String::from_utf8_lossy(data));
109    }
110
111    // Americas region
112    println!("\n   Americas region (lon: -130 to -30, lat: -60 to 60):");
113    let americas_cities = db.find_within_bounds("world_cities", -130.0, -60.0, -30.0, 60.0, 20)?;
114    println!("     Found {} cities:", americas_cities.len());
115    for (_, data) in &americas_cities {
116        println!("       - {}", String::from_utf8_lossy(data));
117    }
118    println!();
119
120    // === 5. BOUNDING BOX INTERSECTION ===
121    println!("5. Bounding Box Intersection (intersects_bounds)");
122    println!("------------------------------------------------");
123
124    let has_european = db.intersects_bounds("world_cities", -10.0, 40.0, 20.0, 60.0)?;
125    let has_antarctica = db.intersects_bounds("world_cities", -180.0, -90.0, 180.0, -60.0)?;
126
127    println!("   European region has cities? {}", has_european);
128    println!("   Antarctica region has cities? {}", has_antarctica);
129    println!();
130
131    // === 6. MULTIPLE NAMESPACES ===
132    println!("6. Multiple Namespaces");
133    println!("----------------------");
134
135    // Add some landmarks in London
136    let london_landmarks = vec![
137        ("Big Ben", Point::new(-0.1245, 51.4994)),
138        ("Tower Bridge", Point::new(-0.0754, 51.5055)),
139        ("London Eye", Point::new(-0.1195, 51.5033)),
140        ("Buckingham Palace", Point::new(-0.1419, 51.5014)),
141    ];
142
143    for (name, point) in &london_landmarks {
144        db.insert_point("landmarks", point, name.as_bytes(), None)?;
145    }
146
147    println!("   Added {} London landmarks", london_landmarks.len());
148
149    // Query different namespaces from same location
150    let center_london = Point::new(-0.1278, 51.5074);
151
152    let nearby_cities = db.query_within_radius("world_cities", &center_london, 10_000.0, 10)?;
153    let nearby_landmarks = db.query_within_radius("landmarks", &center_london, 10_000.0, 10)?;
154
155    println!("   Within 10km of center London:");
156    println!("     Cities: {}", nearby_cities.len());
157    println!("     Landmarks: {}", nearby_landmarks.len());
158
159    println!("\n   Landmarks within 2km:");
160    let close_landmarks = db.query_within_radius("landmarks", &center_london, 2_000.0, 10)?;
161    for (_, data, _) in &close_landmarks {
162        println!("     - {}", String::from_utf8_lossy(data));
163    }
164    println!();
165
166    // === 7. QUERY LIMITS ===
167    println!("7. Query Result Limiting");
168    println!("------------------------");
169
170    let all_cities = db.query_within_radius("world_cities", &london, f64::INFINITY, 100)?;
171    let top_5 = db.query_within_radius("world_cities", &london, f64::INFINITY, 5)?;
172    let top_3 = db.query_within_radius("world_cities", &london, f64::INFINITY, 3)?;
173
174    println!("   Total cities in database: {}", all_cities.len());
175    println!("   With limit=5: {} cities", top_5.len());
176    println!("   With limit=3: {} cities", top_3.len());
177    println!();
178
179    // === SUMMARY ===
180    let stats = db.stats();
181    println!("=== Query Summary ===");
182    println!("Database statistics:");
183    println!("  Total keys: {}", stats.key_count);
184    println!("  Operations: {}", stats.operations_count);
185
186    println!("\nSpatial query methods demonstrated:");
187    println!("  • query_within_radius - Find points within distance");
188    println!("  • contains_point - Check if points exist in radius");
189    println!("  • count_within_radius - Count points efficiently");
190    println!("  • find_within_bounds - Rectangular region queries");
191    println!("  • intersects_bounds - Check bounding box intersection");
192    println!("  • Multiple namespaces - Organize different point types");
193    println!("  • Result limiting - Control query result size");
194
195    Ok(())
196}
examples/trajectory_tracking.rs (line 17)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("=== Spatio - Trajectory Tracking ===\n");
6
7    let mut db = Spatio::memory()?;
8    println!("✓ Created in-memory database\n");
9
10    // === 1. BASIC TRAJECTORY STORAGE ===
11    println!("1. Basic Trajectory Storage");
12    println!("---------------------------");
13
14    // Create a simple delivery route
15    let delivery_route = vec![
16        TemporalPoint {
17            point: Point::new(-74.0060, 40.7128), // NYC
18            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
19        },
20        TemporalPoint {
21            point: Point::new(-74.0040, 40.7150),
22            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260), // +1 min
23        },
24        TemporalPoint {
25            point: Point::new(-74.0020, 40.7172),
26            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320), // +2 min
27        },
28        TemporalPoint {
29            point: Point::new(-74.0000, 40.7194),
30            timestamp: UNIX_EPOCH + Duration::from_secs(1640995380), // +3 min
31        },
32    ];
33
34    db.insert_trajectory("vehicle:truck001", &delivery_route, None)?;
35    println!(
36        "   Stored delivery truck trajectory with {} waypoints\n",
37        delivery_route.len()
38    );
39
40    // === 2. QUERY FULL TRAJECTORY ===
41    println!("2. Query Full Trajectory");
42    println!("------------------------");
43
44    let full_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995400)?;
45    println!("   Retrieved {} waypoints:", full_path.len());
46    for (i, tp) in full_path.iter().enumerate() {
47        println!(
48            "     {}. Point ({:.4}°, {:.4}°) at timestamp {}",
49            i + 1,
50            tp.point.x(),
51            tp.point.y(),
52            tp.timestamp.duration_since(UNIX_EPOCH).unwrap().as_secs()
53        );
54    }
55    println!();
56
57    // === 3. QUERY TIME RANGE ===
58    println!("3. Query Specific Time Range");
59    println!("----------------------------");
60
61    // Get only first 2 minutes of trajectory
62    let partial_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995320)?;
63    println!("   First 2 minutes: {} waypoints", partial_path.len());
64
65    // Get only middle segment
66    let middle_segment = db.query_trajectory("vehicle:truck001", 1640995260, 1640995320)?;
67    println!("   Middle segment: {} waypoints\n", middle_segment.len());
68
69    // === 4. MULTIPLE TRAJECTORIES ===
70    println!("4. Multiple Trajectories");
71    println!("------------------------");
72
73    // Add taxi route
74    let taxi_route = vec![
75        TemporalPoint {
76            point: Point::new(-0.1278, 51.5074), // London
77            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
78        },
79        TemporalPoint {
80            point: Point::new(-0.1195, 51.5033),
81            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260),
82        },
83        TemporalPoint {
84            point: Point::new(-0.1245, 51.4994),
85            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320),
86        },
87    ];
88
89    db.insert_trajectory("vehicle:taxi042", &taxi_route, None)?;
90    println!(
91        "   Stored taxi trajectory with {} waypoints",
92        taxi_route.len()
93    );
94
95    // Add bus route
96    let bus_route = vec![
97        TemporalPoint {
98            point: Point::new(2.3522, 48.8566), // Paris
99            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
100        },
101        TemporalPoint {
102            point: Point::new(2.3550, 48.8580),
103            timestamp: UNIX_EPOCH + Duration::from_secs(1640995300),
104        },
105        TemporalPoint {
106            point: Point::new(2.3580, 48.8600),
107            timestamp: UNIX_EPOCH + Duration::from_secs(1640995400),
108        },
109        TemporalPoint {
110            point: Point::new(2.3610, 48.8620),
111            timestamp: UNIX_EPOCH + Duration::from_secs(1640995500),
112        },
113        TemporalPoint {
114            point: Point::new(2.3640, 48.8640),
115            timestamp: UNIX_EPOCH + Duration::from_secs(1640995600),
116        },
117    ];
118
119    db.insert_trajectory("vehicle:bus123", &bus_route, None)?;
120    println!(
121        "   Stored bus trajectory with {} waypoints\n",
122        bus_route.len()
123    );
124
125    // === 5. QUERY DIFFERENT VEHICLES ===
126    println!("5. Query Different Vehicles");
127    println!("---------------------------");
128
129    let truck_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995400)?;
130    let taxi_path = db.query_trajectory("vehicle:taxi042", 1640995200, 1640995400)?;
131    let bus_path = db.query_trajectory("vehicle:bus123", 1640995200, 1640995700)?;
132
133    println!("   Truck waypoints: {}", truck_path.len());
134    println!("   Taxi waypoints: {}", taxi_path.len());
135    println!("   Bus waypoints: {}\n", bus_path.len());
136
137    // === 6. LONG-RUNNING TRAJECTORY ===
138    println!("6. Long-Running Trajectory (High Frequency)");
139    println!("-------------------------------------------");
140
141    // Simulate a drone with frequent position updates
142    let mut drone_path = Vec::new();
143    let start_time = 1641000000;
144
145    for i in 0..60 {
146        // 60 waypoints, 1 per second
147        drone_path.push(TemporalPoint {
148            point: Point::new(
149                -122.4194 + (i as f64 * 0.0001), // San Francisco area
150                37.7749 + (i as f64 * 0.0001),
151            ),
152            timestamp: UNIX_EPOCH + Duration::from_secs(start_time + i),
153        });
154    }
155
156    db.insert_trajectory("drone:delivery001", &drone_path, None)?;
157    println!(
158        "   Stored drone trajectory with {} waypoints",
159        drone_path.len()
160    );
161
162    // Query specific time window (10 seconds)
163    let window = db.query_trajectory("drone:delivery001", start_time, start_time + 10)?;
164    println!(
165        "   Retrieved 10-second window: {} waypoints\n",
166        window.len()
167    );
168
169    // === 7. TRAJECTORY UPDATES ===
170    println!("7. Trajectory Updates");
171    println!("---------------------");
172
173    // Add more waypoints to existing trajectory
174    let extended_route = vec![
175        TemporalPoint {
176            point: Point::new(-74.0060, 40.7128),
177            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
178        },
179        TemporalPoint {
180            point: Point::new(-74.0040, 40.7150),
181            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260),
182        },
183        TemporalPoint {
184            point: Point::new(-74.0020, 40.7172),
185            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320),
186        },
187        TemporalPoint {
188            point: Point::new(-74.0000, 40.7194),
189            timestamp: UNIX_EPOCH + Duration::from_secs(1640995380),
190        },
191        // New waypoints
192        TemporalPoint {
193            point: Point::new(-73.9980, 40.7216),
194            timestamp: UNIX_EPOCH + Duration::from_secs(1640995440),
195        },
196        TemporalPoint {
197            point: Point::new(-73.9960, 40.7238),
198            timestamp: UNIX_EPOCH + Duration::from_secs(1640995500),
199        },
200    ];
201
202    db.insert_trajectory("vehicle:truck001", &extended_route, None)?;
203    let updated_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995600)?;
204    println!(
205        "   Extended truck trajectory from 4 to {} waypoints\n",
206        updated_path.len()
207    );
208
209    // === 8. DATABASE STATISTICS ===
210    println!("8. Database Statistics");
211    println!("----------------------");
212
213    let stats = db.stats();
214    println!("   Total keys in database: {}", stats.key_count);
215    println!("   Total operations: {}\n", stats.operations_count);
216
217    // === 9. USE CASES ===
218    println!("=== Common Use Cases ===\n");
219
220    println!("Fleet Management:");
221    println!("  • Track multiple vehicles in real-time");
222    println!("  • Query historical routes for analysis");
223    println!("  • Retrieve specific time windows for incidents\n");
224
225    println!("Delivery Tracking:");
226    println!("  • Store complete delivery routes");
227    println!("  • Query progress during specific periods");
228    println!("  • Analyze route efficiency\n");
229
230    println!("Drone Operations:");
231    println!("  • High-frequency position updates");
232    println!("  • Flight path analysis");
233    println!("  • Time-based route queries\n");
234
235    println!("Asset Tracking:");
236    println!("  • Monitor movement of valuable items");
237    println!("  • Historical location queries");
238    println!("  • Route verification\n");
239
240    println!("=== Trajectory Tracking Complete! ===");
241    println!("\nKey Features Demonstrated:");
242    println!("  • Store trajectories with timestamps");
243    println!("  • Query full trajectories");
244    println!("  • Query specific time ranges");
245    println!("  • Track multiple vehicles/objects");
246    println!("  • High-frequency updates");
247    println!("  • Trajectory extensions/updates");
248
249    Ok(())
250}
examples/advanced_spatial.rs (line 26)
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15    println!("=== Advanced Spatial Operations Demo ===\n");
16
17    // Create an in-memory database
18    let mut db = Spatio::memory()?;
19
20    // ========================================
21    // 1. Distance Calculations
22    // ========================================
23    println!("1. Distance Calculations");
24    println!("{}", "=".repeat(50));
25
26    let new_york = Point::new(-74.0060, 40.7128);
27    let los_angeles = Point::new(-118.2437, 34.0522);
28    let london = Point::new(-0.1278, 51.5074);
29
30    // Calculate distances using different metrics
31    let dist_haversine = distance_between(&new_york, &los_angeles, DistanceMetric::Haversine);
32    let dist_geodesic = distance_between(&new_york, &los_angeles, DistanceMetric::Geodesic);
33    let dist_rhumb = distance_between(&new_york, &los_angeles, DistanceMetric::Rhumb);
34
35    println!("NYC to LA:");
36    println!("  Haversine:  {:.2} km", dist_haversine / 1000.0);
37    println!("  Geodesic:   {:.2} km", dist_geodesic / 1000.0);
38    println!("  Rhumb:      {:.2} km", dist_rhumb / 1000.0);
39
40    // Using the database method
41    let db_distance = db.distance_between(&new_york, &london, DistanceMetric::Haversine)?;
42    println!("\nNYC to London: {:.2} km", db_distance / 1000.0);
43
44    // ========================================
45    // 2. K-Nearest-Neighbors (KNN)
46    // ========================================
47    println!("\n2. K-Nearest-Neighbors Query");
48    println!("{}", "=".repeat(50));
49
50    // Insert major cities
51    let cities = vec![
52        (Point::new(-74.0060, 40.7128), "New York", "USA"),
53        (Point::new(-118.2437, 34.0522), "Los Angeles", "USA"),
54        (Point::new(-87.6298, 41.8781), "Chicago", "USA"),
55        (Point::new(-95.3698, 29.7604), "Houston", "USA"),
56        (Point::new(-75.1652, 39.9526), "Philadelphia", "USA"),
57        (Point::new(-122.4194, 37.7749), "San Francisco", "USA"),
58        (Point::new(-0.1278, 51.5074), "London", "UK"),
59        (Point::new(2.3522, 48.8566), "Paris", "France"),
60        (Point::new(139.6917, 35.6895), "Tokyo", "Japan"),
61    ];
62
63    for (point, name, country) in &cities {
64        let data = format!("{},{}", name, country);
65        db.insert_point("world_cities", point, data.as_bytes(), None)?;
66    }
67
68    // Find 3 nearest cities to a query point (somewhere in New Jersey)
69    let query_point = Point::new(-74.1719, 40.7357);
70    let nearest = db.knn(
71        "world_cities",
72        &query_point,
73        3,
74        500_000.0, // Search within 500km
75        DistanceMetric::Haversine,
76    )?;
77
78    println!("3 nearest cities to query point:");
79    for (i, (_point, data, distance)) in nearest.iter().enumerate() {
80        let city_info = String::from_utf8_lossy(data);
81        println!(
82            "  {}. {} ({:.2} km away)",
83            i + 1,
84            city_info,
85            distance / 1000.0
86        );
87    }
88
89    // ========================================
90    // 3. Polygon Queries
91    // ========================================
92    println!("\n3. Polygon Queries");
93    println!("{}", "=".repeat(50));
94
95    // Define a polygon covering parts of the eastern US
96    use geo::polygon;
97    let east_coast_polygon = polygon![
98        (x: -80.0, y: 35.0),  // South
99        (x: -70.0, y: 35.0),  // Southeast
100        (x: -70.0, y: 45.0),  // Northeast
101        (x: -80.0, y: 45.0),  // Northwest
102        (x: -80.0, y: 35.0),  // Close the polygon
103    ];
104    let east_coast_polygon: Polygon = east_coast_polygon.into();
105
106    let cities_in_polygon = db.query_within_polygon("world_cities", &east_coast_polygon, 100)?;
107
108    println!("Cities within East Coast polygon:");
109    for (point, data) in &cities_in_polygon {
110        let city_info = String::from_utf8_lossy(data);
111        println!("  - {} at ({:.4}, {:.4})", city_info, point.x(), point.y());
112    }
113
114    // ========================================
115    // 4. Bounding Box Operations
116    // ========================================
117    println!("\n4. Bounding Box Operations");
118    println!("{}", "=".repeat(50));
119
120    // Create a bounding box around the New York area
121    let ny_bbox = bounding_box(-74.5, 40.5, -73.5, 41.0)?;
122    println!("NY Area Bounding Box: {:?}", ny_bbox);
123
124    // Find cities in bounding box
125    let cities_in_bbox = db.find_within_bounds("world_cities", 40.5, -74.5, 41.0, -73.5, 100)?;
126    println!("\nCities in NY area bounding box:");
127    for (_point, data) in &cities_in_bbox {
128        let city_info = String::from_utf8_lossy(data);
129        println!("  - {}", city_info);
130    }
131
132    // ========================================
133    // 5. Convex Hull
134    // ========================================
135    println!("\n5. Convex Hull Calculation");
136    println!("{}", "=".repeat(50));
137
138    // Get all city points
139    let city_points: Vec<Point> = cities.iter().map(|(p, _, _)| *p).collect();
140
141    // Calculate convex hull
142    if let Some(hull) = convex_hull(&city_points) {
143        println!("Convex hull of all cities:");
144        println!("  Exterior points: {}", hull.exterior().0.len() - 1);
145        for coord in hull.exterior().0.iter().take(5) {
146            println!("    ({:.4}, {:.4})", coord.x, coord.y);
147        }
148    }
149
150    // ========================================
151    // 6. Bounding Rectangle
152    // ========================================
153    println!("\n6. Bounding Rectangle");
154    println!("{}", "=".repeat(50));
155
156    if let Some(bbox) = bounding_rect_for_points(&city_points) {
157        println!("Bounding rectangle of all cities:");
158        println!("  Min: ({:.4}, {:.4})", bbox.min().x, bbox.min().y);
159        println!("  Max: ({:.4}, {:.4})", bbox.max().x, bbox.max().y);
160        println!("  Width:  {:.2}°", bbox.max().x - bbox.min().x);
161        println!("  Height: {:.2}°", bbox.max().y - bbox.min().y);
162    }
163
164    // ========================================
165    // 7. Advanced Radius Queries
166    // ========================================
167    println!("\n7. Advanced Radius Queries");
168    println!("{}", "=".repeat(50));
169
170    // Count cities within 1000km of NYC
171    let count = db.count_within_radius("world_cities", &new_york, 1_000_000.0)?;
172    println!("Cities within 1000km of NYC: {}", count);
173
174    // Check if any cities exist within 100km
175    let has_nearby = db.intersects_radius("world_cities", &new_york, 100_000.0)?;
176    println!("Has cities within 100km of NYC: {}", has_nearby);
177
178    // Query with radius
179    let nearby = db.query_within_radius("world_cities", &new_york, 200_000.0, 10)?;
180    println!("\nCities within 200km of NYC:");
181    for (point, data, _distance) in &nearby {
182        let city_info = String::from_utf8_lossy(data);
183        let dist = distance_between(&new_york, point, DistanceMetric::Haversine);
184        println!("  - {} ({:.2} km)", city_info, dist / 1000.0);
185    }
186
187    // ========================================
188    // 8. Spatial Analytics
189    // ========================================
190    println!("\n8. Spatial Analytics");
191    println!("{}", "=".repeat(50));
192
193    // Find the two most distant cities (brute force)
194    let mut max_distance = 0.0;
195    let mut furthest_pair = ("", "");
196
197    for (i, (p1, n1, _)) in cities.iter().enumerate() {
198        for (p2, n2, _) in cities.iter().skip(i + 1) {
199            let dist = distance_between(p1, p2, DistanceMetric::Geodesic);
200            if dist > max_distance {
201                max_distance = dist;
202                furthest_pair = (n1, n2);
203            }
204        }
205    }
206
207    println!(
208        "Most distant city pair: {} ↔ {}",
209        furthest_pair.0, furthest_pair.1
210    );
211    println!("Distance: {:.2} km", max_distance / 1000.0);
212
213    // Calculate average distance between all US cities
214    let us_cities: Vec<_> = cities
215        .iter()
216        .filter(|(_, _, country)| *country == "USA")
217        .collect();
218
219    if us_cities.len() > 1 {
220        let mut total_distance = 0.0;
221        let mut count = 0;
222
223        for (i, (p1, _, _)) in us_cities.iter().enumerate() {
224            for (p2, _, _) in us_cities.iter().skip(i + 1) {
225                total_distance += distance_between(p1, p2, DistanceMetric::Haversine);
226                count += 1;
227            }
228        }
229
230        let avg_distance = total_distance / count as f64;
231        println!(
232            "\nAverage distance between US cities: {:.2} km",
233            avg_distance / 1000.0
234        );
235    }
236
237    // ========================================
238    // Summary
239    // ========================================
240    println!("\n{}", "=".repeat(50));
241    println!("Summary:");
242    println!("  - Demonstrated multiple distance metrics");
243    println!("  - Performed K-nearest-neighbor searches");
244    println!("  - Queried points within polygons");
245    println!("  - Used bounding box operations");
246    println!("  - Calculated convex hulls");
247    println!("  - Performed spatial analytics");
248    println!("\nAll spatial operations leverage the geo crate!");
249
250    Ok(())
251}
examples/bbox_database.rs (line 64)
9fn main() -> Result<(), Box<dyn Error>> {
10    println!("=== Spatio - Bounding Box Database ===\n");
11
12    let mut db = Spatio::memory()?;
13    println!("✓ Created in-memory database\n");
14
15    // ========================================
16    // 1. Store Geographic Regions
17    // ========================================
18    println!("1. Storing Geographic Regions");
19    println!("------------------------------");
20
21    // Define NYC boroughs as bounding boxes
22    let manhattan = BoundingBox2D::new(-74.0479, 40.6829, -73.9067, 40.8820);
23    let brooklyn = BoundingBox2D::new(-74.0421, 40.5707, -73.8333, 40.7395);
24    let queens = BoundingBox2D::new(-73.9626, 40.5431, -73.7004, 40.8007);
25    let bronx = BoundingBox2D::new(-73.9338, 40.7855, -73.7654, 40.9176);
26    let staten_island = BoundingBox2D::new(-74.2558, 40.4960, -74.0526, 40.6490);
27
28    // Store regions in database
29    db.insert_bbox("region:manhattan", &manhattan, None)?;
30    db.insert_bbox("region:brooklyn", &brooklyn, None)?;
31    db.insert_bbox("region:queens", &queens, None)?;
32    db.insert_bbox("region:bronx", &bronx, None)?;
33    db.insert_bbox("region:staten_island", &staten_island, None)?;
34
35    println!("   ✓ Stored 5 NYC borough boundaries");
36
37    // ========================================
38    // 2. Retrieve Stored Regions
39    // ========================================
40    println!("\n2. Retrieving Stored Regions");
41    println!("-----------------------------");
42
43    if let Some(retrieved_manhattan) = db.get_bbox("region:manhattan")? {
44        println!("   Manhattan:");
45        println!(
46            "     Area: {:.4}° × {:.4}°",
47            retrieved_manhattan.width(),
48            retrieved_manhattan.height()
49        );
50        println!(
51            "     Center: ({:.4}, {:.4})",
52            retrieved_manhattan.center().x(),
53            retrieved_manhattan.center().y()
54        );
55    }
56
57    // ========================================
58    // 3. Store POIs and Query by Region
59    // ========================================
60    println!("\n3. Store POIs and Query by Region");
61    println!("-----------------------------------");
62
63    // Store points of interest
64    db.insert_point("poi", &Point::new(-73.9855, 40.7580), b"times_square", None)?;
65    db.insert_point("poi", &Point::new(-73.9665, 40.7829), b"central_park", None)?;
66    db.insert_point("poi", &Point::new(-73.9857, 40.7484), b"empire_state", None)?;
67    db.insert_point(
68        "poi",
69        &Point::new(-73.9969, 40.7061),
70        b"brooklyn_bridge",
71        None,
72    )?;
73    db.insert_point(
74        "poi",
75        &Point::new(-73.9690, 40.6602),
76        b"prospect_park",
77        None,
78    )?;
79    db.insert_point("poi", &Point::new(-73.9799, 40.5755), b"coney_island", None)?;
80
81    println!("   ✓ Stored 6 points of interest");
82
83    // Query POIs in Manhattan
84    let manhattan_pois = db.query_within_bbox("poi", &manhattan, 100)?;
85    println!("\n   POIs in Manhattan: {}", manhattan_pois.len());
86    for (point, data) in &manhattan_pois {
87        let name = String::from_utf8_lossy(data);
88        println!("     - {} at ({:.4}, {:.4})", name, point.x(), point.y());
89    }
90
91    // Query POIs in Brooklyn
92    let brooklyn_pois = db.query_within_bbox("poi", &brooklyn, 100)?;
93    println!("\n   POIs in Brooklyn: {}", brooklyn_pois.len());
94
95    // ========================================
96    // 4. Find Intersecting Regions
97    // ========================================
98    println!("\n4. Finding Intersecting Regions");
99    println!("--------------------------------");
100
101    // Create a search area (covering parts of Manhattan and Queens)
102    let search_area = BoundingBox2D::new(-73.98, 40.72, -73.92, 40.78);
103
104    let intersecting = db.find_intersecting_bboxes("region:", &search_area)?;
105    println!(
106        "   Search area intersects with {} boroughs:",
107        intersecting.len()
108    );
109    for (key, _bbox) in &intersecting {
110        println!("     - {}", key.replace("region:", ""));
111    }
112
113    // ========================================
114    // 5. Delivery Zone Management
115    // ========================================
116    println!("\n5. Delivery Zone Management");
117    println!("----------------------------");
118
119    // Define delivery zones
120    let zone_a = BoundingBox2D::new(-74.02, 40.70, -73.98, 40.74);
121    let zone_b = BoundingBox2D::new(-74.00, 40.72, -73.96, 40.76);
122    let zone_c = BoundingBox2D::new(-73.98, 40.74, -73.94, 40.78);
123
124    db.insert_bbox("delivery:zone_a", &zone_a, None)?;
125    db.insert_bbox("delivery:zone_b", &zone_b, None)?;
126    db.insert_bbox("delivery:zone_c", &zone_c, None)?;
127
128    println!("   ✓ Created 3 delivery zones");
129
130    // Check which zones overlap
131    let overlapping_with_a = db.find_intersecting_bboxes("delivery:", &zone_a)?;
132    println!(
133        "\n   Zone A overlaps with {} zones (including itself)",
134        overlapping_with_a.len()
135    );
136
137    // ========================================
138    // 6. Service Area Lookup
139    // ========================================
140    println!("\n6. Service Area Lookup");
141    println!("-----------------------");
142
143    // Check if various locations are in service areas
144    let locations = vec![
145        ("Customer 1", Point::new(-74.00, 40.72)),
146        ("Customer 2", Point::new(-73.97, 40.75)),
147        ("Customer 3", Point::new(-74.05, 40.68)),
148    ];
149
150    for (name, location) in &locations {
151        let mut in_zone = false;
152        for (zone_key, zone_bbox) in &overlapping_with_a {
153            if zone_bbox.contains_point(location) {
154                println!(
155                    "   {} at ({:.4}, {:.4}) is in {}",
156                    name,
157                    location.x(),
158                    location.y(),
159                    zone_key.replace("delivery:", "")
160                );
161                in_zone = true;
162                break;
163            }
164        }
165        if !in_zone {
166            println!(
167                "   {} at ({:.4}, {:.4}) is outside all zones",
168                name,
169                location.x(),
170                location.y()
171            );
172        }
173    }
174
175    // ========================================
176    // 7. Geofencing Example
177    // ========================================
178    println!("\n7. Geofencing Example");
179    println!("----------------------");
180
181    // Define restricted areas
182    let airport_zone = BoundingBox2D::new(-73.82, 40.63, -73.76, 40.66);
183    db.insert_bbox("restricted:jfk_airport", &airport_zone, None)?;
184
185    let military_zone = BoundingBox2D::new(-74.08, 40.60, -74.03, 40.64);
186    db.insert_bbox("restricted:military", &military_zone, None)?;
187
188    println!("   ✓ Defined 2 restricted zones");
189
190    // Check if drone locations are in restricted areas
191    let drone_locations = vec![
192        ("Drone 1", Point::new(-73.79, 40.64)),
193        ("Drone 2", Point::new(-74.00, 40.70)),
194    ];
195
196    for (drone, location) in &drone_locations {
197        let restricted = db.find_intersecting_bboxes(
198            "restricted:",
199            &BoundingBox2D::new(
200                location.x() - 0.001,
201                location.y() - 0.001,
202                location.x() + 0.001,
203                location.y() + 0.001,
204            ),
205        )?;
206
207        if !restricted.is_empty() {
208            println!(
209                "   ⚠ {} at ({:.4}, {:.4}) is in restricted area: {}",
210                drone,
211                location.x(),
212                location.y(),
213                restricted[0].0.replace("restricted:", "")
214            );
215        } else {
216            println!(
217                "   ✓ {} at ({:.4}, {:.4}) is in safe area",
218                drone,
219                location.x(),
220                location.y()
221            );
222        }
223    }
224
225    // ========================================
226    // 8. Spatial Analytics
227    // ========================================
228    println!("\n8. Spatial Analytics");
229    println!("---------------------");
230
231    // Calculate coverage area
232    let mut total_width = 0.0;
233    let mut total_height = 0.0;
234    let mut count = 0;
235
236    let all_regions = vec![
237        ("Manhattan", &manhattan),
238        ("Brooklyn", &brooklyn),
239        ("Queens", &queens),
240        ("Bronx", &bronx),
241        ("Staten Island", &staten_island),
242    ];
243
244    for (name, bbox) in &all_regions {
245        total_width += bbox.width();
246        total_height += bbox.height();
247        count += 1;
248        println!(
249            "   {} coverage: {:.4}° × {:.4}°",
250            name,
251            bbox.width(),
252            bbox.height()
253        );
254    }
255
256    let avg_width = total_width / count as f64;
257    let avg_height = total_height / count as f64;
258
259    println!(
260        "\n   Average borough size: {:.4}° × {:.4}°",
261        avg_width, avg_height
262    );
263
264    // ========================================
265    // 9. Database Statistics
266    // ========================================
267    println!("\n9. Database Statistics");
268    println!("-----------------------");
269
270    let stats = db.stats();
271    println!("   Total keys: {}", stats.key_count);
272    println!("   Total operations: {}", stats.operations_count);
273
274    // Count different types of data
275    let poi_count = manhattan_pois.len() + brooklyn_pois.len();
276    println!("   Stored POIs: {}", poi_count);
277    println!("   Stored regions: 5");
278    println!("   Delivery zones: 3");
279    println!("   Restricted zones: 2");
280
281    println!("\n=== Bounding Box Database Integration Complete! ===");
282    println!("\nKey Features Demonstrated:");
283    println!("  • Store and retrieve bounding boxes");
284    println!("  • Query POIs within regions");
285    println!("  • Find intersecting regions");
286    println!("  • Delivery zone management");
287    println!("  • Service area lookups");
288    println!("  • Geofencing and restricted areas");
289    println!("  • Spatial analytics");
290
291    Ok(())
292}
Source

pub fn x(&self) -> f64

Get the x coordinate (longitude).

Examples found in repository?
examples/spatial_queries.rs (line 98)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("=== Spatio - Spatial Queries ===\n");
5
6    let mut db = Spatio::memory()?;
7    println!("✓ Created in-memory database\n");
8
9    // === SETUP: Insert World Cities ===
10    println!("Setting up test data...");
11
12    let cities = vec![
13        ("New York", Point::new(-74.0060, 40.7128)),
14        ("London", Point::new(-0.1278, 51.5074)),
15        ("Paris", Point::new(2.3522, 48.8566)),
16        ("Berlin", Point::new(13.4050, 52.5200)),
17        ("Madrid", Point::new(-3.7038, 40.4168)),
18        ("Rome", Point::new(12.4964, 41.9028)),
19        ("Tokyo", Point::new(139.6503, 35.6762)),
20        ("Sydney", Point::new(151.2093, -33.8688)),
21        ("Mumbai", Point::new(72.8777, 19.0760)),
22        ("Cairo", Point::new(31.2357, 30.0444)),
23        ("São Paulo", Point::new(-46.6333, -23.5505)),
24        ("Mexico City", Point::new(-99.1332, 19.4326)),
25    ];
26
27    for (name, point) in &cities {
28        db.insert_point("world_cities", point, name.as_bytes(), None)?;
29    }
30    println!("   Added {} cities to spatial index\n", cities.len());
31
32    // === 1. RADIUS QUERIES ===
33    println!("1. Radius-Based Queries (query_within_radius)");
34    println!("----------------------------------------------");
35
36    let london = Point::new(-0.1278, 51.5074);
37
38    // Find cities within 500km of London
39    let nearby_500km = db.query_within_radius("world_cities", &london, 500_000.0, 10)?;
40    println!("   Cities within 500km of London: {}", nearby_500km.len());
41    for (_, data, _) in &nearby_500km {
42        println!("     - {}", String::from_utf8_lossy(data));
43    }
44
45    // Find cities within 2000km of London
46    let nearby_2000km = db.query_within_radius("world_cities", &london, 2_000_000.0, 10)?;
47    println!(
48        "\n   Cities within 2000km of London: {}",
49        nearby_2000km.len()
50    );
51    for (_, data, _) in &nearby_2000km {
52        println!("     - {}", String::from_utf8_lossy(data));
53    }
54
55    // Use limit to get only closest N cities
56    let closest_3 = db.query_within_radius("world_cities", &london, f64::INFINITY, 3)?;
57    println!("\n   Closest 3 cities to London:");
58    for (i, (_, data, _)) in closest_3.iter().enumerate() {
59        println!("     {}. {}", i + 1, String::from_utf8_lossy(data));
60    }
61    println!();
62
63    // === 2. EXISTENCE CHECKS ===
64    println!("2. Existence Checks (contains_point)");
65    println!("-------------------------------------");
66
67    let has_nearby_500km = db.intersects_radius("world_cities", &london, 500_000.0)?;
68    let has_nearby_100km = db.intersects_radius("world_cities", &london, 100_000.0)?;
69
70    println!("   Any cities within 500km of London? {}", has_nearby_500km);
71    println!("   Any cities within 100km of London? {}", has_nearby_100km);
72
73    // === 3. COUNTING POINTS ===
74    println!("3. Counting Points (count_within_radius)");
75    println!("----------------------------------------");
76
77    let count_500km = db.count_within_radius("world_cities", &london, 500_000.0)?;
78    let count_1000km = db.count_within_radius("world_cities", &london, 1_000_000.0)?;
79    let count_2000km = db.count_within_radius("world_cities", &london, 2_000_000.0)?;
80
81    println!("   Cities within 500km of London: {}", count_500km);
82    println!("   Cities within 1000km of London: {}", count_1000km);
83    println!("   Cities within 2000km of London: {}", count_2000km);
84    println!();
85
86    // === 4. BOUNDING BOX QUERIES ===
87    println!("4. Bounding Box Queries");
88    println!("-----------------------");
89
90    // European bounding box (min_lon, min_lat, max_lon, max_lat)
91    println!("   European region (lon: -10 to 20, lat: 40 to 60):");
92    let europe_cities = db.find_within_bounds("world_cities", -10.0, 40.0, 20.0, 60.0, 20)?;
93    println!("     Found {} cities:", europe_cities.len());
94    for (point, data) in &europe_cities {
95        println!(
96            "       - {} at ({:.2}°, {:.2}°)",
97            String::from_utf8_lossy(data),
98            point.x(),
99            point.y()
100        );
101    }
102
103    // Asia-Pacific region
104    println!("\n   Asia-Pacific region (lon: 70 to 180, lat: -40 to 40):");
105    let asia_cities = db.find_within_bounds("world_cities", 70.0, -40.0, 180.0, 40.0, 20)?;
106    println!("     Found {} cities:", asia_cities.len());
107    for (_, data) in &asia_cities {
108        println!("       - {}", String::from_utf8_lossy(data));
109    }
110
111    // Americas region
112    println!("\n   Americas region (lon: -130 to -30, lat: -60 to 60):");
113    let americas_cities = db.find_within_bounds("world_cities", -130.0, -60.0, -30.0, 60.0, 20)?;
114    println!("     Found {} cities:", americas_cities.len());
115    for (_, data) in &americas_cities {
116        println!("       - {}", String::from_utf8_lossy(data));
117    }
118    println!();
119
120    // === 5. BOUNDING BOX INTERSECTION ===
121    println!("5. Bounding Box Intersection (intersects_bounds)");
122    println!("------------------------------------------------");
123
124    let has_european = db.intersects_bounds("world_cities", -10.0, 40.0, 20.0, 60.0)?;
125    let has_antarctica = db.intersects_bounds("world_cities", -180.0, -90.0, 180.0, -60.0)?;
126
127    println!("   European region has cities? {}", has_european);
128    println!("   Antarctica region has cities? {}", has_antarctica);
129    println!();
130
131    // === 6. MULTIPLE NAMESPACES ===
132    println!("6. Multiple Namespaces");
133    println!("----------------------");
134
135    // Add some landmarks in London
136    let london_landmarks = vec![
137        ("Big Ben", Point::new(-0.1245, 51.4994)),
138        ("Tower Bridge", Point::new(-0.0754, 51.5055)),
139        ("London Eye", Point::new(-0.1195, 51.5033)),
140        ("Buckingham Palace", Point::new(-0.1419, 51.5014)),
141    ];
142
143    for (name, point) in &london_landmarks {
144        db.insert_point("landmarks", point, name.as_bytes(), None)?;
145    }
146
147    println!("   Added {} London landmarks", london_landmarks.len());
148
149    // Query different namespaces from same location
150    let center_london = Point::new(-0.1278, 51.5074);
151
152    let nearby_cities = db.query_within_radius("world_cities", &center_london, 10_000.0, 10)?;
153    let nearby_landmarks = db.query_within_radius("landmarks", &center_london, 10_000.0, 10)?;
154
155    println!("   Within 10km of center London:");
156    println!("     Cities: {}", nearby_cities.len());
157    println!("     Landmarks: {}", nearby_landmarks.len());
158
159    println!("\n   Landmarks within 2km:");
160    let close_landmarks = db.query_within_radius("landmarks", &center_london, 2_000.0, 10)?;
161    for (_, data, _) in &close_landmarks {
162        println!("     - {}", String::from_utf8_lossy(data));
163    }
164    println!();
165
166    // === 7. QUERY LIMITS ===
167    println!("7. Query Result Limiting");
168    println!("------------------------");
169
170    let all_cities = db.query_within_radius("world_cities", &london, f64::INFINITY, 100)?;
171    let top_5 = db.query_within_radius("world_cities", &london, f64::INFINITY, 5)?;
172    let top_3 = db.query_within_radius("world_cities", &london, f64::INFINITY, 3)?;
173
174    println!("   Total cities in database: {}", all_cities.len());
175    println!("   With limit=5: {} cities", top_5.len());
176    println!("   With limit=3: {} cities", top_3.len());
177    println!();
178
179    // === SUMMARY ===
180    let stats = db.stats();
181    println!("=== Query Summary ===");
182    println!("Database statistics:");
183    println!("  Total keys: {}", stats.key_count);
184    println!("  Operations: {}", stats.operations_count);
185
186    println!("\nSpatial query methods demonstrated:");
187    println!("  • query_within_radius - Find points within distance");
188    println!("  • contains_point - Check if points exist in radius");
189    println!("  • count_within_radius - Count points efficiently");
190    println!("  • find_within_bounds - Rectangular region queries");
191    println!("  • intersects_bounds - Check bounding box intersection");
192    println!("  • Multiple namespaces - Organize different point types");
193    println!("  • Result limiting - Control query result size");
194
195    Ok(())
196}
More examples
Hide additional examples
examples/trajectory_tracking.rs (line 50)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("=== Spatio - Trajectory Tracking ===\n");
6
7    let mut db = Spatio::memory()?;
8    println!("✓ Created in-memory database\n");
9
10    // === 1. BASIC TRAJECTORY STORAGE ===
11    println!("1. Basic Trajectory Storage");
12    println!("---------------------------");
13
14    // Create a simple delivery route
15    let delivery_route = vec![
16        TemporalPoint {
17            point: Point::new(-74.0060, 40.7128), // NYC
18            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
19        },
20        TemporalPoint {
21            point: Point::new(-74.0040, 40.7150),
22            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260), // +1 min
23        },
24        TemporalPoint {
25            point: Point::new(-74.0020, 40.7172),
26            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320), // +2 min
27        },
28        TemporalPoint {
29            point: Point::new(-74.0000, 40.7194),
30            timestamp: UNIX_EPOCH + Duration::from_secs(1640995380), // +3 min
31        },
32    ];
33
34    db.insert_trajectory("vehicle:truck001", &delivery_route, None)?;
35    println!(
36        "   Stored delivery truck trajectory with {} waypoints\n",
37        delivery_route.len()
38    );
39
40    // === 2. QUERY FULL TRAJECTORY ===
41    println!("2. Query Full Trajectory");
42    println!("------------------------");
43
44    let full_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995400)?;
45    println!("   Retrieved {} waypoints:", full_path.len());
46    for (i, tp) in full_path.iter().enumerate() {
47        println!(
48            "     {}. Point ({:.4}°, {:.4}°) at timestamp {}",
49            i + 1,
50            tp.point.x(),
51            tp.point.y(),
52            tp.timestamp.duration_since(UNIX_EPOCH).unwrap().as_secs()
53        );
54    }
55    println!();
56
57    // === 3. QUERY TIME RANGE ===
58    println!("3. Query Specific Time Range");
59    println!("----------------------------");
60
61    // Get only first 2 minutes of trajectory
62    let partial_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995320)?;
63    println!("   First 2 minutes: {} waypoints", partial_path.len());
64
65    // Get only middle segment
66    let middle_segment = db.query_trajectory("vehicle:truck001", 1640995260, 1640995320)?;
67    println!("   Middle segment: {} waypoints\n", middle_segment.len());
68
69    // === 4. MULTIPLE TRAJECTORIES ===
70    println!("4. Multiple Trajectories");
71    println!("------------------------");
72
73    // Add taxi route
74    let taxi_route = vec![
75        TemporalPoint {
76            point: Point::new(-0.1278, 51.5074), // London
77            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
78        },
79        TemporalPoint {
80            point: Point::new(-0.1195, 51.5033),
81            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260),
82        },
83        TemporalPoint {
84            point: Point::new(-0.1245, 51.4994),
85            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320),
86        },
87    ];
88
89    db.insert_trajectory("vehicle:taxi042", &taxi_route, None)?;
90    println!(
91        "   Stored taxi trajectory with {} waypoints",
92        taxi_route.len()
93    );
94
95    // Add bus route
96    let bus_route = vec![
97        TemporalPoint {
98            point: Point::new(2.3522, 48.8566), // Paris
99            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
100        },
101        TemporalPoint {
102            point: Point::new(2.3550, 48.8580),
103            timestamp: UNIX_EPOCH + Duration::from_secs(1640995300),
104        },
105        TemporalPoint {
106            point: Point::new(2.3580, 48.8600),
107            timestamp: UNIX_EPOCH + Duration::from_secs(1640995400),
108        },
109        TemporalPoint {
110            point: Point::new(2.3610, 48.8620),
111            timestamp: UNIX_EPOCH + Duration::from_secs(1640995500),
112        },
113        TemporalPoint {
114            point: Point::new(2.3640, 48.8640),
115            timestamp: UNIX_EPOCH + Duration::from_secs(1640995600),
116        },
117    ];
118
119    db.insert_trajectory("vehicle:bus123", &bus_route, None)?;
120    println!(
121        "   Stored bus trajectory with {} waypoints\n",
122        bus_route.len()
123    );
124
125    // === 5. QUERY DIFFERENT VEHICLES ===
126    println!("5. Query Different Vehicles");
127    println!("---------------------------");
128
129    let truck_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995400)?;
130    let taxi_path = db.query_trajectory("vehicle:taxi042", 1640995200, 1640995400)?;
131    let bus_path = db.query_trajectory("vehicle:bus123", 1640995200, 1640995700)?;
132
133    println!("   Truck waypoints: {}", truck_path.len());
134    println!("   Taxi waypoints: {}", taxi_path.len());
135    println!("   Bus waypoints: {}\n", bus_path.len());
136
137    // === 6. LONG-RUNNING TRAJECTORY ===
138    println!("6. Long-Running Trajectory (High Frequency)");
139    println!("-------------------------------------------");
140
141    // Simulate a drone with frequent position updates
142    let mut drone_path = Vec::new();
143    let start_time = 1641000000;
144
145    for i in 0..60 {
146        // 60 waypoints, 1 per second
147        drone_path.push(TemporalPoint {
148            point: Point::new(
149                -122.4194 + (i as f64 * 0.0001), // San Francisco area
150                37.7749 + (i as f64 * 0.0001),
151            ),
152            timestamp: UNIX_EPOCH + Duration::from_secs(start_time + i),
153        });
154    }
155
156    db.insert_trajectory("drone:delivery001", &drone_path, None)?;
157    println!(
158        "   Stored drone trajectory with {} waypoints",
159        drone_path.len()
160    );
161
162    // Query specific time window (10 seconds)
163    let window = db.query_trajectory("drone:delivery001", start_time, start_time + 10)?;
164    println!(
165        "   Retrieved 10-second window: {} waypoints\n",
166        window.len()
167    );
168
169    // === 7. TRAJECTORY UPDATES ===
170    println!("7. Trajectory Updates");
171    println!("---------------------");
172
173    // Add more waypoints to existing trajectory
174    let extended_route = vec![
175        TemporalPoint {
176            point: Point::new(-74.0060, 40.7128),
177            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
178        },
179        TemporalPoint {
180            point: Point::new(-74.0040, 40.7150),
181            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260),
182        },
183        TemporalPoint {
184            point: Point::new(-74.0020, 40.7172),
185            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320),
186        },
187        TemporalPoint {
188            point: Point::new(-74.0000, 40.7194),
189            timestamp: UNIX_EPOCH + Duration::from_secs(1640995380),
190        },
191        // New waypoints
192        TemporalPoint {
193            point: Point::new(-73.9980, 40.7216),
194            timestamp: UNIX_EPOCH + Duration::from_secs(1640995440),
195        },
196        TemporalPoint {
197            point: Point::new(-73.9960, 40.7238),
198            timestamp: UNIX_EPOCH + Duration::from_secs(1640995500),
199        },
200    ];
201
202    db.insert_trajectory("vehicle:truck001", &extended_route, None)?;
203    let updated_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995600)?;
204    println!(
205        "   Extended truck trajectory from 4 to {} waypoints\n",
206        updated_path.len()
207    );
208
209    // === 8. DATABASE STATISTICS ===
210    println!("8. Database Statistics");
211    println!("----------------------");
212
213    let stats = db.stats();
214    println!("   Total keys in database: {}", stats.key_count);
215    println!("   Total operations: {}\n", stats.operations_count);
216
217    // === 9. USE CASES ===
218    println!("=== Common Use Cases ===\n");
219
220    println!("Fleet Management:");
221    println!("  • Track multiple vehicles in real-time");
222    println!("  • Query historical routes for analysis");
223    println!("  • Retrieve specific time windows for incidents\n");
224
225    println!("Delivery Tracking:");
226    println!("  • Store complete delivery routes");
227    println!("  • Query progress during specific periods");
228    println!("  • Analyze route efficiency\n");
229
230    println!("Drone Operations:");
231    println!("  • High-frequency position updates");
232    println!("  • Flight path analysis");
233    println!("  • Time-based route queries\n");
234
235    println!("Asset Tracking:");
236    println!("  • Monitor movement of valuable items");
237    println!("  • Historical location queries");
238    println!("  • Route verification\n");
239
240    println!("=== Trajectory Tracking Complete! ===");
241    println!("\nKey Features Demonstrated:");
242    println!("  • Store trajectories with timestamps");
243    println!("  • Query full trajectories");
244    println!("  • Query specific time ranges");
245    println!("  • Track multiple vehicles/objects");
246    println!("  • High-frequency updates");
247    println!("  • Trajectory extensions/updates");
248
249    Ok(())
250}
examples/advanced_spatial.rs (line 111)
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15    println!("=== Advanced Spatial Operations Demo ===\n");
16
17    // Create an in-memory database
18    let mut db = Spatio::memory()?;
19
20    // ========================================
21    // 1. Distance Calculations
22    // ========================================
23    println!("1. Distance Calculations");
24    println!("{}", "=".repeat(50));
25
26    let new_york = Point::new(-74.0060, 40.7128);
27    let los_angeles = Point::new(-118.2437, 34.0522);
28    let london = Point::new(-0.1278, 51.5074);
29
30    // Calculate distances using different metrics
31    let dist_haversine = distance_between(&new_york, &los_angeles, DistanceMetric::Haversine);
32    let dist_geodesic = distance_between(&new_york, &los_angeles, DistanceMetric::Geodesic);
33    let dist_rhumb = distance_between(&new_york, &los_angeles, DistanceMetric::Rhumb);
34
35    println!("NYC to LA:");
36    println!("  Haversine:  {:.2} km", dist_haversine / 1000.0);
37    println!("  Geodesic:   {:.2} km", dist_geodesic / 1000.0);
38    println!("  Rhumb:      {:.2} km", dist_rhumb / 1000.0);
39
40    // Using the database method
41    let db_distance = db.distance_between(&new_york, &london, DistanceMetric::Haversine)?;
42    println!("\nNYC to London: {:.2} km", db_distance / 1000.0);
43
44    // ========================================
45    // 2. K-Nearest-Neighbors (KNN)
46    // ========================================
47    println!("\n2. K-Nearest-Neighbors Query");
48    println!("{}", "=".repeat(50));
49
50    // Insert major cities
51    let cities = vec![
52        (Point::new(-74.0060, 40.7128), "New York", "USA"),
53        (Point::new(-118.2437, 34.0522), "Los Angeles", "USA"),
54        (Point::new(-87.6298, 41.8781), "Chicago", "USA"),
55        (Point::new(-95.3698, 29.7604), "Houston", "USA"),
56        (Point::new(-75.1652, 39.9526), "Philadelphia", "USA"),
57        (Point::new(-122.4194, 37.7749), "San Francisco", "USA"),
58        (Point::new(-0.1278, 51.5074), "London", "UK"),
59        (Point::new(2.3522, 48.8566), "Paris", "France"),
60        (Point::new(139.6917, 35.6895), "Tokyo", "Japan"),
61    ];
62
63    for (point, name, country) in &cities {
64        let data = format!("{},{}", name, country);
65        db.insert_point("world_cities", point, data.as_bytes(), None)?;
66    }
67
68    // Find 3 nearest cities to a query point (somewhere in New Jersey)
69    let query_point = Point::new(-74.1719, 40.7357);
70    let nearest = db.knn(
71        "world_cities",
72        &query_point,
73        3,
74        500_000.0, // Search within 500km
75        DistanceMetric::Haversine,
76    )?;
77
78    println!("3 nearest cities to query point:");
79    for (i, (_point, data, distance)) in nearest.iter().enumerate() {
80        let city_info = String::from_utf8_lossy(data);
81        println!(
82            "  {}. {} ({:.2} km away)",
83            i + 1,
84            city_info,
85            distance / 1000.0
86        );
87    }
88
89    // ========================================
90    // 3. Polygon Queries
91    // ========================================
92    println!("\n3. Polygon Queries");
93    println!("{}", "=".repeat(50));
94
95    // Define a polygon covering parts of the eastern US
96    use geo::polygon;
97    let east_coast_polygon = polygon![
98        (x: -80.0, y: 35.0),  // South
99        (x: -70.0, y: 35.0),  // Southeast
100        (x: -70.0, y: 45.0),  // Northeast
101        (x: -80.0, y: 45.0),  // Northwest
102        (x: -80.0, y: 35.0),  // Close the polygon
103    ];
104    let east_coast_polygon: Polygon = east_coast_polygon.into();
105
106    let cities_in_polygon = db.query_within_polygon("world_cities", &east_coast_polygon, 100)?;
107
108    println!("Cities within East Coast polygon:");
109    for (point, data) in &cities_in_polygon {
110        let city_info = String::from_utf8_lossy(data);
111        println!("  - {} at ({:.4}, {:.4})", city_info, point.x(), point.y());
112    }
113
114    // ========================================
115    // 4. Bounding Box Operations
116    // ========================================
117    println!("\n4. Bounding Box Operations");
118    println!("{}", "=".repeat(50));
119
120    // Create a bounding box around the New York area
121    let ny_bbox = bounding_box(-74.5, 40.5, -73.5, 41.0)?;
122    println!("NY Area Bounding Box: {:?}", ny_bbox);
123
124    // Find cities in bounding box
125    let cities_in_bbox = db.find_within_bounds("world_cities", 40.5, -74.5, 41.0, -73.5, 100)?;
126    println!("\nCities in NY area bounding box:");
127    for (_point, data) in &cities_in_bbox {
128        let city_info = String::from_utf8_lossy(data);
129        println!("  - {}", city_info);
130    }
131
132    // ========================================
133    // 5. Convex Hull
134    // ========================================
135    println!("\n5. Convex Hull Calculation");
136    println!("{}", "=".repeat(50));
137
138    // Get all city points
139    let city_points: Vec<Point> = cities.iter().map(|(p, _, _)| *p).collect();
140
141    // Calculate convex hull
142    if let Some(hull) = convex_hull(&city_points) {
143        println!("Convex hull of all cities:");
144        println!("  Exterior points: {}", hull.exterior().0.len() - 1);
145        for coord in hull.exterior().0.iter().take(5) {
146            println!("    ({:.4}, {:.4})", coord.x, coord.y);
147        }
148    }
149
150    // ========================================
151    // 6. Bounding Rectangle
152    // ========================================
153    println!("\n6. Bounding Rectangle");
154    println!("{}", "=".repeat(50));
155
156    if let Some(bbox) = bounding_rect_for_points(&city_points) {
157        println!("Bounding rectangle of all cities:");
158        println!("  Min: ({:.4}, {:.4})", bbox.min().x, bbox.min().y);
159        println!("  Max: ({:.4}, {:.4})", bbox.max().x, bbox.max().y);
160        println!("  Width:  {:.2}°", bbox.max().x - bbox.min().x);
161        println!("  Height: {:.2}°", bbox.max().y - bbox.min().y);
162    }
163
164    // ========================================
165    // 7. Advanced Radius Queries
166    // ========================================
167    println!("\n7. Advanced Radius Queries");
168    println!("{}", "=".repeat(50));
169
170    // Count cities within 1000km of NYC
171    let count = db.count_within_radius("world_cities", &new_york, 1_000_000.0)?;
172    println!("Cities within 1000km of NYC: {}", count);
173
174    // Check if any cities exist within 100km
175    let has_nearby = db.intersects_radius("world_cities", &new_york, 100_000.0)?;
176    println!("Has cities within 100km of NYC: {}", has_nearby);
177
178    // Query with radius
179    let nearby = db.query_within_radius("world_cities", &new_york, 200_000.0, 10)?;
180    println!("\nCities within 200km of NYC:");
181    for (point, data, _distance) in &nearby {
182        let city_info = String::from_utf8_lossy(data);
183        let dist = distance_between(&new_york, point, DistanceMetric::Haversine);
184        println!("  - {} ({:.2} km)", city_info, dist / 1000.0);
185    }
186
187    // ========================================
188    // 8. Spatial Analytics
189    // ========================================
190    println!("\n8. Spatial Analytics");
191    println!("{}", "=".repeat(50));
192
193    // Find the two most distant cities (brute force)
194    let mut max_distance = 0.0;
195    let mut furthest_pair = ("", "");
196
197    for (i, (p1, n1, _)) in cities.iter().enumerate() {
198        for (p2, n2, _) in cities.iter().skip(i + 1) {
199            let dist = distance_between(p1, p2, DistanceMetric::Geodesic);
200            if dist > max_distance {
201                max_distance = dist;
202                furthest_pair = (n1, n2);
203            }
204        }
205    }
206
207    println!(
208        "Most distant city pair: {} ↔ {}",
209        furthest_pair.0, furthest_pair.1
210    );
211    println!("Distance: {:.2} km", max_distance / 1000.0);
212
213    // Calculate average distance between all US cities
214    let us_cities: Vec<_> = cities
215        .iter()
216        .filter(|(_, _, country)| *country == "USA")
217        .collect();
218
219    if us_cities.len() > 1 {
220        let mut total_distance = 0.0;
221        let mut count = 0;
222
223        for (i, (p1, _, _)) in us_cities.iter().enumerate() {
224            for (p2, _, _) in us_cities.iter().skip(i + 1) {
225                total_distance += distance_between(p1, p2, DistanceMetric::Haversine);
226                count += 1;
227            }
228        }
229
230        let avg_distance = total_distance / count as f64;
231        println!(
232            "\nAverage distance between US cities: {:.2} km",
233            avg_distance / 1000.0
234        );
235    }
236
237    // ========================================
238    // Summary
239    // ========================================
240    println!("\n{}", "=".repeat(50));
241    println!("Summary:");
242    println!("  - Demonstrated multiple distance metrics");
243    println!("  - Performed K-nearest-neighbor searches");
244    println!("  - Queried points within polygons");
245    println!("  - Used bounding box operations");
246    println!("  - Calculated convex hulls");
247    println!("  - Performed spatial analytics");
248    println!("\nAll spatial operations leverage the geo crate!");
249
250    Ok(())
251}
examples/bbox_database.rs (line 52)
9fn main() -> Result<(), Box<dyn Error>> {
10    println!("=== Spatio - Bounding Box Database ===\n");
11
12    let mut db = Spatio::memory()?;
13    println!("✓ Created in-memory database\n");
14
15    // ========================================
16    // 1. Store Geographic Regions
17    // ========================================
18    println!("1. Storing Geographic Regions");
19    println!("------------------------------");
20
21    // Define NYC boroughs as bounding boxes
22    let manhattan = BoundingBox2D::new(-74.0479, 40.6829, -73.9067, 40.8820);
23    let brooklyn = BoundingBox2D::new(-74.0421, 40.5707, -73.8333, 40.7395);
24    let queens = BoundingBox2D::new(-73.9626, 40.5431, -73.7004, 40.8007);
25    let bronx = BoundingBox2D::new(-73.9338, 40.7855, -73.7654, 40.9176);
26    let staten_island = BoundingBox2D::new(-74.2558, 40.4960, -74.0526, 40.6490);
27
28    // Store regions in database
29    db.insert_bbox("region:manhattan", &manhattan, None)?;
30    db.insert_bbox("region:brooklyn", &brooklyn, None)?;
31    db.insert_bbox("region:queens", &queens, None)?;
32    db.insert_bbox("region:bronx", &bronx, None)?;
33    db.insert_bbox("region:staten_island", &staten_island, None)?;
34
35    println!("   ✓ Stored 5 NYC borough boundaries");
36
37    // ========================================
38    // 2. Retrieve Stored Regions
39    // ========================================
40    println!("\n2. Retrieving Stored Regions");
41    println!("-----------------------------");
42
43    if let Some(retrieved_manhattan) = db.get_bbox("region:manhattan")? {
44        println!("   Manhattan:");
45        println!(
46            "     Area: {:.4}° × {:.4}°",
47            retrieved_manhattan.width(),
48            retrieved_manhattan.height()
49        );
50        println!(
51            "     Center: ({:.4}, {:.4})",
52            retrieved_manhattan.center().x(),
53            retrieved_manhattan.center().y()
54        );
55    }
56
57    // ========================================
58    // 3. Store POIs and Query by Region
59    // ========================================
60    println!("\n3. Store POIs and Query by Region");
61    println!("-----------------------------------");
62
63    // Store points of interest
64    db.insert_point("poi", &Point::new(-73.9855, 40.7580), b"times_square", None)?;
65    db.insert_point("poi", &Point::new(-73.9665, 40.7829), b"central_park", None)?;
66    db.insert_point("poi", &Point::new(-73.9857, 40.7484), b"empire_state", None)?;
67    db.insert_point(
68        "poi",
69        &Point::new(-73.9969, 40.7061),
70        b"brooklyn_bridge",
71        None,
72    )?;
73    db.insert_point(
74        "poi",
75        &Point::new(-73.9690, 40.6602),
76        b"prospect_park",
77        None,
78    )?;
79    db.insert_point("poi", &Point::new(-73.9799, 40.5755), b"coney_island", None)?;
80
81    println!("   ✓ Stored 6 points of interest");
82
83    // Query POIs in Manhattan
84    let manhattan_pois = db.query_within_bbox("poi", &manhattan, 100)?;
85    println!("\n   POIs in Manhattan: {}", manhattan_pois.len());
86    for (point, data) in &manhattan_pois {
87        let name = String::from_utf8_lossy(data);
88        println!("     - {} at ({:.4}, {:.4})", name, point.x(), point.y());
89    }
90
91    // Query POIs in Brooklyn
92    let brooklyn_pois = db.query_within_bbox("poi", &brooklyn, 100)?;
93    println!("\n   POIs in Brooklyn: {}", brooklyn_pois.len());
94
95    // ========================================
96    // 4. Find Intersecting Regions
97    // ========================================
98    println!("\n4. Finding Intersecting Regions");
99    println!("--------------------------------");
100
101    // Create a search area (covering parts of Manhattan and Queens)
102    let search_area = BoundingBox2D::new(-73.98, 40.72, -73.92, 40.78);
103
104    let intersecting = db.find_intersecting_bboxes("region:", &search_area)?;
105    println!(
106        "   Search area intersects with {} boroughs:",
107        intersecting.len()
108    );
109    for (key, _bbox) in &intersecting {
110        println!("     - {}", key.replace("region:", ""));
111    }
112
113    // ========================================
114    // 5. Delivery Zone Management
115    // ========================================
116    println!("\n5. Delivery Zone Management");
117    println!("----------------------------");
118
119    // Define delivery zones
120    let zone_a = BoundingBox2D::new(-74.02, 40.70, -73.98, 40.74);
121    let zone_b = BoundingBox2D::new(-74.00, 40.72, -73.96, 40.76);
122    let zone_c = BoundingBox2D::new(-73.98, 40.74, -73.94, 40.78);
123
124    db.insert_bbox("delivery:zone_a", &zone_a, None)?;
125    db.insert_bbox("delivery:zone_b", &zone_b, None)?;
126    db.insert_bbox("delivery:zone_c", &zone_c, None)?;
127
128    println!("   ✓ Created 3 delivery zones");
129
130    // Check which zones overlap
131    let overlapping_with_a = db.find_intersecting_bboxes("delivery:", &zone_a)?;
132    println!(
133        "\n   Zone A overlaps with {} zones (including itself)",
134        overlapping_with_a.len()
135    );
136
137    // ========================================
138    // 6. Service Area Lookup
139    // ========================================
140    println!("\n6. Service Area Lookup");
141    println!("-----------------------");
142
143    // Check if various locations are in service areas
144    let locations = vec![
145        ("Customer 1", Point::new(-74.00, 40.72)),
146        ("Customer 2", Point::new(-73.97, 40.75)),
147        ("Customer 3", Point::new(-74.05, 40.68)),
148    ];
149
150    for (name, location) in &locations {
151        let mut in_zone = false;
152        for (zone_key, zone_bbox) in &overlapping_with_a {
153            if zone_bbox.contains_point(location) {
154                println!(
155                    "   {} at ({:.4}, {:.4}) is in {}",
156                    name,
157                    location.x(),
158                    location.y(),
159                    zone_key.replace("delivery:", "")
160                );
161                in_zone = true;
162                break;
163            }
164        }
165        if !in_zone {
166            println!(
167                "   {} at ({:.4}, {:.4}) is outside all zones",
168                name,
169                location.x(),
170                location.y()
171            );
172        }
173    }
174
175    // ========================================
176    // 7. Geofencing Example
177    // ========================================
178    println!("\n7. Geofencing Example");
179    println!("----------------------");
180
181    // Define restricted areas
182    let airport_zone = BoundingBox2D::new(-73.82, 40.63, -73.76, 40.66);
183    db.insert_bbox("restricted:jfk_airport", &airport_zone, None)?;
184
185    let military_zone = BoundingBox2D::new(-74.08, 40.60, -74.03, 40.64);
186    db.insert_bbox("restricted:military", &military_zone, None)?;
187
188    println!("   ✓ Defined 2 restricted zones");
189
190    // Check if drone locations are in restricted areas
191    let drone_locations = vec![
192        ("Drone 1", Point::new(-73.79, 40.64)),
193        ("Drone 2", Point::new(-74.00, 40.70)),
194    ];
195
196    for (drone, location) in &drone_locations {
197        let restricted = db.find_intersecting_bboxes(
198            "restricted:",
199            &BoundingBox2D::new(
200                location.x() - 0.001,
201                location.y() - 0.001,
202                location.x() + 0.001,
203                location.y() + 0.001,
204            ),
205        )?;
206
207        if !restricted.is_empty() {
208            println!(
209                "   ⚠ {} at ({:.4}, {:.4}) is in restricted area: {}",
210                drone,
211                location.x(),
212                location.y(),
213                restricted[0].0.replace("restricted:", "")
214            );
215        } else {
216            println!(
217                "   ✓ {} at ({:.4}, {:.4}) is in safe area",
218                drone,
219                location.x(),
220                location.y()
221            );
222        }
223    }
224
225    // ========================================
226    // 8. Spatial Analytics
227    // ========================================
228    println!("\n8. Spatial Analytics");
229    println!("---------------------");
230
231    // Calculate coverage area
232    let mut total_width = 0.0;
233    let mut total_height = 0.0;
234    let mut count = 0;
235
236    let all_regions = vec![
237        ("Manhattan", &manhattan),
238        ("Brooklyn", &brooklyn),
239        ("Queens", &queens),
240        ("Bronx", &bronx),
241        ("Staten Island", &staten_island),
242    ];
243
244    for (name, bbox) in &all_regions {
245        total_width += bbox.width();
246        total_height += bbox.height();
247        count += 1;
248        println!(
249            "   {} coverage: {:.4}° × {:.4}°",
250            name,
251            bbox.width(),
252            bbox.height()
253        );
254    }
255
256    let avg_width = total_width / count as f64;
257    let avg_height = total_height / count as f64;
258
259    println!(
260        "\n   Average borough size: {:.4}° × {:.4}°",
261        avg_width, avg_height
262    );
263
264    // ========================================
265    // 9. Database Statistics
266    // ========================================
267    println!("\n9. Database Statistics");
268    println!("-----------------------");
269
270    let stats = db.stats();
271    println!("   Total keys: {}", stats.key_count);
272    println!("   Total operations: {}", stats.operations_count);
273
274    // Count different types of data
275    let poi_count = manhattan_pois.len() + brooklyn_pois.len();
276    println!("   Stored POIs: {}", poi_count);
277    println!("   Stored regions: 5");
278    println!("   Delivery zones: 3");
279    println!("   Restricted zones: 2");
280
281    println!("\n=== Bounding Box Database Integration Complete! ===");
282    println!("\nKey Features Demonstrated:");
283    println!("  • Store and retrieve bounding boxes");
284    println!("  • Query POIs within regions");
285    println!("  • Find intersecting regions");
286    println!("  • Delivery zone management");
287    println!("  • Service area lookups");
288    println!("  • Geofencing and restricted areas");
289    println!("  • Spatial analytics");
290
291    Ok(())
292}
examples/bounding_boxes.rs (line 42)
10fn main() -> Result<(), Box<dyn Error>> {
11    println!("=== Spatio - Bounding Box Examples ===\n");
12
13    // Create an in-memory database
14    let mut db = Spatio::memory()?;
15    println!("✓ Created in-memory database\n");
16
17    // ========================================
18    // 1. Basic 2D Bounding Box Operations
19    // ========================================
20    println!("1. Basic 2D Bounding Box");
21    println!("-------------------------");
22
23    // Create a bounding box for Manhattan
24    let manhattan = BoundingBox2D::new(
25        -74.0479, 40.6829, // Southwest corner (Battery Park)
26        -73.9067, 40.8820, // Northeast corner (Inwood)
27    );
28
29    println!("   Manhattan bounding box:");
30    println!(
31        "     Min: ({:.4}, {:.4})",
32        manhattan.min_x(),
33        manhattan.min_y()
34    );
35    println!(
36        "     Max: ({:.4}, {:.4})",
37        manhattan.max_x(),
38        manhattan.max_y()
39    );
40    println!(
41        "     Center: ({:.4}, {:.4})",
42        manhattan.center().x(),
43        manhattan.center().y()
44    );
45    println!(
46        "     Width: {:.4}°, Height: {:.4}°",
47        manhattan.width(),
48        manhattan.height()
49    );
50
51    // Check if points are within Manhattan
52    let times_square = Point::new(-73.9855, 40.7580);
53    let brooklyn_bridge = Point::new(-73.9969, 40.7061);
54    let statue_of_liberty = Point::new(-74.0445, 40.6892);
55    let jfk_airport = Point::new(-73.7781, 40.6413);
56
57    println!("\n   Point containment checks:");
58    println!(
59        "     Times Square: {}",
60        manhattan.contains_point(&times_square)
61    );
62    println!(
63        "     Brooklyn Bridge: {}",
64        manhattan.contains_point(&brooklyn_bridge)
65    );
66    println!(
67        "     Statue of Liberty: {}",
68        manhattan.contains_point(&statue_of_liberty)
69    );
70    println!(
71        "     JFK Airport: {}",
72        manhattan.contains_point(&jfk_airport)
73    );
74
75    // ========================================
76    // 2. Bounding Box Intersection
77    // ========================================
78    println!("\n2. Bounding Box Intersection");
79    println!("-----------------------------");
80
81    // Create bounding boxes for different NYC boroughs
82    let manhattan_bbox = BoundingBox2D::new(-74.0479, 40.6829, -73.9067, 40.8820);
83    let brooklyn_bbox = BoundingBox2D::new(-74.0421, 40.5707, -73.8333, 40.7395);
84    let queens_bbox = BoundingBox2D::new(-73.9626, 40.5431, -73.7004, 40.8007);
85
86    println!(
87        "   Manhattan ∩ Brooklyn: {}",
88        manhattan_bbox.intersects(&brooklyn_bbox)
89    );
90    println!(
91        "   Manhattan ∩ Queens: {}",
92        manhattan_bbox.intersects(&queens_bbox)
93    );
94    println!(
95        "   Brooklyn ∩ Queens: {}",
96        brooklyn_bbox.intersects(&queens_bbox)
97    );
98
99    // ========================================
100    // 3. Expanding Bounding Boxes
101    // ========================================
102    println!("\n3. Expanding Bounding Boxes");
103    println!("----------------------------");
104
105    let central_park = BoundingBox2D::new(-73.9812, 40.7644, -73.9492, 40.8003);
106    println!("   Central Park original:");
107    println!(
108        "     Width: {:.4}°, Height: {:.4}°",
109        central_park.width(),
110        central_park.height()
111    );
112
113    // Expand by 0.01 degrees (~1 km)
114    let expanded = central_park.expand(0.01);
115    println!("\n   Expanded by 0.01°:");
116    println!(
117        "     Width: {:.4}°, Height: {:.4}°",
118        expanded.width(),
119        expanded.height()
120    );
121    println!(
122        "     Growth: {:.4}° in each direction",
123        (expanded.width() - central_park.width()) / 2.0
124    );
125
126    // ========================================
127    // 4. 3D Bounding Boxes
128    // ========================================
129    println!("\n4. 3D Bounding Boxes");
130    println!("--------------------");
131
132    // Create a 3D bounding box for a tall building's footprint with height
133    let one_world_trade = BoundingBox3D::new(
134        -74.0134, 40.7127, 0.0, // Ground level southwest
135        -74.0118, 40.7143, 541.0, // Top level northeast (541m height)
136    );
137
138    println!("   One World Trade Center:");
139    println!(
140        "     Footprint: {:.4}° × {:.4}°",
141        one_world_trade.width(),
142        one_world_trade.height()
143    );
144    println!("     Height: {:.1} meters", one_world_trade.depth());
145    println!(
146        "     Volume: {:.6} cubic degrees×meters",
147        one_world_trade.volume()
148    );
149
150    let (cx, cy, cz) = one_world_trade.center();
151    println!("     Center: ({:.4}, {:.4}, {:.1}m)", cx, cy, cz);
152
153    // Check if points at different altitudes are within the building
154    println!("\n   Altitude containment checks:");
155    println!(
156        "     Ground level (0m): {}",
157        one_world_trade.contains_point(-74.0126, 40.7135, 0.0)
158    );
159    println!(
160        "     Mid-level (270m): {}",
161        one_world_trade.contains_point(-74.0126, 40.7135, 270.0)
162    );
163    println!(
164        "     Top (540m): {}",
165        one_world_trade.contains_point(-74.0126, 40.7135, 540.0)
166    );
167    println!(
168        "     Above (600m): {}",
169        one_world_trade.contains_point(-74.0126, 40.7135, 600.0)
170    );
171
172    // ========================================
173    // 5. 3D to 2D Projection
174    // ========================================
175    println!("\n5. 3D to 2D Projection");
176    println!("----------------------");
177
178    let building_3d = BoundingBox3D::new(-74.0, 40.7, 0.0, -73.9, 40.8, 200.0);
179    let building_2d = building_3d.to_2d();
180
181    println!("   3D Bounding Box:");
182    println!(
183        "     Dimensions: {:.4}° × {:.4}° × {:.1}m",
184        building_3d.width(),
185        building_3d.height(),
186        building_3d.depth()
187    );
188
189    println!("\n   Projected to 2D:");
190    println!(
191        "     Dimensions: {:.4}° × {:.4}°",
192        building_2d.width(),
193        building_2d.height()
194    );
195
196    // ========================================
197    // 6. Temporal Bounding Boxes
198    // ========================================
199    println!("\n6. Temporal Bounding Boxes");
200    println!("--------------------------");
201
202    // Track how a delivery zone changes over time
203    let morning_zone = BoundingBox2D::new(-74.01, 40.71, -73.99, 40.73);
204    let afternoon_zone = BoundingBox2D::new(-74.02, 40.70, -73.98, 40.74);
205
206    let morning_time = SystemTime::now();
207    let afternoon_time = SystemTime::now();
208
209    let temporal_morning = TemporalBoundingBox2D::new(morning_zone.clone(), morning_time);
210    let temporal_afternoon = TemporalBoundingBox2D::new(afternoon_zone.clone(), afternoon_time);
211
212    println!("   Morning delivery zone:");
213    println!(
214        "     Area: {:.4}° × {:.4}°",
215        temporal_morning.bbox().width(),
216        temporal_morning.bbox().height()
217    );
218
219    println!("\n   Afternoon delivery zone:");
220    println!(
221        "     Area: {:.4}° × {:.4}°",
222        temporal_afternoon.bbox().width(),
223        temporal_afternoon.bbox().height()
224    );
225
226    println!(
227        "     Expansion: {:.4}° wider, {:.4}° taller",
228        afternoon_zone.width() - morning_zone.width(),
229        afternoon_zone.height() - morning_zone.height()
230    );
231
232    // ========================================
233    // 7. Storing Bounding Boxes in Database
234    // ========================================
235    println!("\n7. Storing Bounding Boxes");
236    println!("-------------------------");
237
238    // Serialize and store bounding boxes
239    let bbox_json = serde_json::to_vec(&manhattan)?;
240    db.insert("zones:manhattan", bbox_json, None)?;
241
242    let bbox3d_json = serde_json::to_vec(&one_world_trade)?;
243    db.insert("buildings:wtc", bbox3d_json, None)?;
244
245    println!("   ✓ Stored Manhattan bounding box");
246    println!("   ✓ Stored One World Trade Center 3D box");
247
248    // Retrieve and deserialize
249    if let Some(data) = db.get("zones:manhattan")? {
250        let retrieved: BoundingBox2D = serde_json::from_slice(&data)?;
251        println!("\n   Retrieved Manhattan box:");
252        println!(
253            "     Center: ({:.4}, {:.4})",
254            retrieved.center().x(),
255            retrieved.center().y()
256        );
257    }
258
259    // ========================================
260    // 8. Practical Use Cases
261    // ========================================
262    println!("\n8. Practical Use Cases");
263    println!("----------------------");
264
265    // Geofencing
266    let delivery_area = BoundingBox2D::new(-74.02, 40.70, -73.98, 40.75);
267    let current_location = Point::new(-74.00, 40.72);
268
269    if delivery_area.contains_point(&current_location) {
270        println!("   ✓ Delivery driver is within service area");
271    } else {
272        println!("   ✗ Delivery driver is outside service area");
273    }
274
275    // Airspace management
276    let airspace = BoundingBox3D::new(
277        -74.1, 40.6, 0.0, // Ground level
278        -73.8, 40.9, 3000.0, // 3000m ceiling
279    );
280    let drone_altitude = 150.0; // meters
281    let drone_location = (-74.0, 40.75, drone_altitude);
282
283    if airspace.contains_point(drone_location.0, drone_location.1, drone_location.2) {
284        println!("   ✓ Drone is within authorized airspace");
285    }
286
287    // Region overlap detection
288    let zone_a = BoundingBox2D::new(-74.05, 40.70, -74.00, 40.75);
289    let zone_b = BoundingBox2D::new(-74.02, 40.72, -73.97, 40.77);
290
291    if zone_a.intersects(&zone_b) {
292        println!("   ⚠ Service zones A and B overlap - coordination needed");
293    }
294
295    println!("\n=== Bounding Box Examples Complete! ===");
296    println!("\nKey Features Demonstrated:");
297    println!("  • Create and manipulate 2D/3D bounding boxes");
298    println!("  • Check point containment");
299    println!("  • Detect box intersections");
300    println!("  • Expand regions");
301    println!("  • Project 3D to 2D");
302    println!("  • Track temporal changes");
303    println!("  • Serialize and store in database");
304    println!("  • Geofencing and airspace management");
305
306    Ok(())
307}
Source

pub fn y(&self) -> f64

Get the y coordinate (latitude).

Examples found in repository?
examples/spatial_queries.rs (line 99)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("=== Spatio - Spatial Queries ===\n");
5
6    let mut db = Spatio::memory()?;
7    println!("✓ Created in-memory database\n");
8
9    // === SETUP: Insert World Cities ===
10    println!("Setting up test data...");
11
12    let cities = vec![
13        ("New York", Point::new(-74.0060, 40.7128)),
14        ("London", Point::new(-0.1278, 51.5074)),
15        ("Paris", Point::new(2.3522, 48.8566)),
16        ("Berlin", Point::new(13.4050, 52.5200)),
17        ("Madrid", Point::new(-3.7038, 40.4168)),
18        ("Rome", Point::new(12.4964, 41.9028)),
19        ("Tokyo", Point::new(139.6503, 35.6762)),
20        ("Sydney", Point::new(151.2093, -33.8688)),
21        ("Mumbai", Point::new(72.8777, 19.0760)),
22        ("Cairo", Point::new(31.2357, 30.0444)),
23        ("São Paulo", Point::new(-46.6333, -23.5505)),
24        ("Mexico City", Point::new(-99.1332, 19.4326)),
25    ];
26
27    for (name, point) in &cities {
28        db.insert_point("world_cities", point, name.as_bytes(), None)?;
29    }
30    println!("   Added {} cities to spatial index\n", cities.len());
31
32    // === 1. RADIUS QUERIES ===
33    println!("1. Radius-Based Queries (query_within_radius)");
34    println!("----------------------------------------------");
35
36    let london = Point::new(-0.1278, 51.5074);
37
38    // Find cities within 500km of London
39    let nearby_500km = db.query_within_radius("world_cities", &london, 500_000.0, 10)?;
40    println!("   Cities within 500km of London: {}", nearby_500km.len());
41    for (_, data, _) in &nearby_500km {
42        println!("     - {}", String::from_utf8_lossy(data));
43    }
44
45    // Find cities within 2000km of London
46    let nearby_2000km = db.query_within_radius("world_cities", &london, 2_000_000.0, 10)?;
47    println!(
48        "\n   Cities within 2000km of London: {}",
49        nearby_2000km.len()
50    );
51    for (_, data, _) in &nearby_2000km {
52        println!("     - {}", String::from_utf8_lossy(data));
53    }
54
55    // Use limit to get only closest N cities
56    let closest_3 = db.query_within_radius("world_cities", &london, f64::INFINITY, 3)?;
57    println!("\n   Closest 3 cities to London:");
58    for (i, (_, data, _)) in closest_3.iter().enumerate() {
59        println!("     {}. {}", i + 1, String::from_utf8_lossy(data));
60    }
61    println!();
62
63    // === 2. EXISTENCE CHECKS ===
64    println!("2. Existence Checks (contains_point)");
65    println!("-------------------------------------");
66
67    let has_nearby_500km = db.intersects_radius("world_cities", &london, 500_000.0)?;
68    let has_nearby_100km = db.intersects_radius("world_cities", &london, 100_000.0)?;
69
70    println!("   Any cities within 500km of London? {}", has_nearby_500km);
71    println!("   Any cities within 100km of London? {}", has_nearby_100km);
72
73    // === 3. COUNTING POINTS ===
74    println!("3. Counting Points (count_within_radius)");
75    println!("----------------------------------------");
76
77    let count_500km = db.count_within_radius("world_cities", &london, 500_000.0)?;
78    let count_1000km = db.count_within_radius("world_cities", &london, 1_000_000.0)?;
79    let count_2000km = db.count_within_radius("world_cities", &london, 2_000_000.0)?;
80
81    println!("   Cities within 500km of London: {}", count_500km);
82    println!("   Cities within 1000km of London: {}", count_1000km);
83    println!("   Cities within 2000km of London: {}", count_2000km);
84    println!();
85
86    // === 4. BOUNDING BOX QUERIES ===
87    println!("4. Bounding Box Queries");
88    println!("-----------------------");
89
90    // European bounding box (min_lon, min_lat, max_lon, max_lat)
91    println!("   European region (lon: -10 to 20, lat: 40 to 60):");
92    let europe_cities = db.find_within_bounds("world_cities", -10.0, 40.0, 20.0, 60.0, 20)?;
93    println!("     Found {} cities:", europe_cities.len());
94    for (point, data) in &europe_cities {
95        println!(
96            "       - {} at ({:.2}°, {:.2}°)",
97            String::from_utf8_lossy(data),
98            point.x(),
99            point.y()
100        );
101    }
102
103    // Asia-Pacific region
104    println!("\n   Asia-Pacific region (lon: 70 to 180, lat: -40 to 40):");
105    let asia_cities = db.find_within_bounds("world_cities", 70.0, -40.0, 180.0, 40.0, 20)?;
106    println!("     Found {} cities:", asia_cities.len());
107    for (_, data) in &asia_cities {
108        println!("       - {}", String::from_utf8_lossy(data));
109    }
110
111    // Americas region
112    println!("\n   Americas region (lon: -130 to -30, lat: -60 to 60):");
113    let americas_cities = db.find_within_bounds("world_cities", -130.0, -60.0, -30.0, 60.0, 20)?;
114    println!("     Found {} cities:", americas_cities.len());
115    for (_, data) in &americas_cities {
116        println!("       - {}", String::from_utf8_lossy(data));
117    }
118    println!();
119
120    // === 5. BOUNDING BOX INTERSECTION ===
121    println!("5. Bounding Box Intersection (intersects_bounds)");
122    println!("------------------------------------------------");
123
124    let has_european = db.intersects_bounds("world_cities", -10.0, 40.0, 20.0, 60.0)?;
125    let has_antarctica = db.intersects_bounds("world_cities", -180.0, -90.0, 180.0, -60.0)?;
126
127    println!("   European region has cities? {}", has_european);
128    println!("   Antarctica region has cities? {}", has_antarctica);
129    println!();
130
131    // === 6. MULTIPLE NAMESPACES ===
132    println!("6. Multiple Namespaces");
133    println!("----------------------");
134
135    // Add some landmarks in London
136    let london_landmarks = vec![
137        ("Big Ben", Point::new(-0.1245, 51.4994)),
138        ("Tower Bridge", Point::new(-0.0754, 51.5055)),
139        ("London Eye", Point::new(-0.1195, 51.5033)),
140        ("Buckingham Palace", Point::new(-0.1419, 51.5014)),
141    ];
142
143    for (name, point) in &london_landmarks {
144        db.insert_point("landmarks", point, name.as_bytes(), None)?;
145    }
146
147    println!("   Added {} London landmarks", london_landmarks.len());
148
149    // Query different namespaces from same location
150    let center_london = Point::new(-0.1278, 51.5074);
151
152    let nearby_cities = db.query_within_radius("world_cities", &center_london, 10_000.0, 10)?;
153    let nearby_landmarks = db.query_within_radius("landmarks", &center_london, 10_000.0, 10)?;
154
155    println!("   Within 10km of center London:");
156    println!("     Cities: {}", nearby_cities.len());
157    println!("     Landmarks: {}", nearby_landmarks.len());
158
159    println!("\n   Landmarks within 2km:");
160    let close_landmarks = db.query_within_radius("landmarks", &center_london, 2_000.0, 10)?;
161    for (_, data, _) in &close_landmarks {
162        println!("     - {}", String::from_utf8_lossy(data));
163    }
164    println!();
165
166    // === 7. QUERY LIMITS ===
167    println!("7. Query Result Limiting");
168    println!("------------------------");
169
170    let all_cities = db.query_within_radius("world_cities", &london, f64::INFINITY, 100)?;
171    let top_5 = db.query_within_radius("world_cities", &london, f64::INFINITY, 5)?;
172    let top_3 = db.query_within_radius("world_cities", &london, f64::INFINITY, 3)?;
173
174    println!("   Total cities in database: {}", all_cities.len());
175    println!("   With limit=5: {} cities", top_5.len());
176    println!("   With limit=3: {} cities", top_3.len());
177    println!();
178
179    // === SUMMARY ===
180    let stats = db.stats();
181    println!("=== Query Summary ===");
182    println!("Database statistics:");
183    println!("  Total keys: {}", stats.key_count);
184    println!("  Operations: {}", stats.operations_count);
185
186    println!("\nSpatial query methods demonstrated:");
187    println!("  • query_within_radius - Find points within distance");
188    println!("  • contains_point - Check if points exist in radius");
189    println!("  • count_within_radius - Count points efficiently");
190    println!("  • find_within_bounds - Rectangular region queries");
191    println!("  • intersects_bounds - Check bounding box intersection");
192    println!("  • Multiple namespaces - Organize different point types");
193    println!("  • Result limiting - Control query result size");
194
195    Ok(())
196}
More examples
Hide additional examples
examples/trajectory_tracking.rs (line 51)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("=== Spatio - Trajectory Tracking ===\n");
6
7    let mut db = Spatio::memory()?;
8    println!("✓ Created in-memory database\n");
9
10    // === 1. BASIC TRAJECTORY STORAGE ===
11    println!("1. Basic Trajectory Storage");
12    println!("---------------------------");
13
14    // Create a simple delivery route
15    let delivery_route = vec![
16        TemporalPoint {
17            point: Point::new(-74.0060, 40.7128), // NYC
18            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
19        },
20        TemporalPoint {
21            point: Point::new(-74.0040, 40.7150),
22            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260), // +1 min
23        },
24        TemporalPoint {
25            point: Point::new(-74.0020, 40.7172),
26            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320), // +2 min
27        },
28        TemporalPoint {
29            point: Point::new(-74.0000, 40.7194),
30            timestamp: UNIX_EPOCH + Duration::from_secs(1640995380), // +3 min
31        },
32    ];
33
34    db.insert_trajectory("vehicle:truck001", &delivery_route, None)?;
35    println!(
36        "   Stored delivery truck trajectory with {} waypoints\n",
37        delivery_route.len()
38    );
39
40    // === 2. QUERY FULL TRAJECTORY ===
41    println!("2. Query Full Trajectory");
42    println!("------------------------");
43
44    let full_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995400)?;
45    println!("   Retrieved {} waypoints:", full_path.len());
46    for (i, tp) in full_path.iter().enumerate() {
47        println!(
48            "     {}. Point ({:.4}°, {:.4}°) at timestamp {}",
49            i + 1,
50            tp.point.x(),
51            tp.point.y(),
52            tp.timestamp.duration_since(UNIX_EPOCH).unwrap().as_secs()
53        );
54    }
55    println!();
56
57    // === 3. QUERY TIME RANGE ===
58    println!("3. Query Specific Time Range");
59    println!("----------------------------");
60
61    // Get only first 2 minutes of trajectory
62    let partial_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995320)?;
63    println!("   First 2 minutes: {} waypoints", partial_path.len());
64
65    // Get only middle segment
66    let middle_segment = db.query_trajectory("vehicle:truck001", 1640995260, 1640995320)?;
67    println!("   Middle segment: {} waypoints\n", middle_segment.len());
68
69    // === 4. MULTIPLE TRAJECTORIES ===
70    println!("4. Multiple Trajectories");
71    println!("------------------------");
72
73    // Add taxi route
74    let taxi_route = vec![
75        TemporalPoint {
76            point: Point::new(-0.1278, 51.5074), // London
77            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
78        },
79        TemporalPoint {
80            point: Point::new(-0.1195, 51.5033),
81            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260),
82        },
83        TemporalPoint {
84            point: Point::new(-0.1245, 51.4994),
85            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320),
86        },
87    ];
88
89    db.insert_trajectory("vehicle:taxi042", &taxi_route, None)?;
90    println!(
91        "   Stored taxi trajectory with {} waypoints",
92        taxi_route.len()
93    );
94
95    // Add bus route
96    let bus_route = vec![
97        TemporalPoint {
98            point: Point::new(2.3522, 48.8566), // Paris
99            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
100        },
101        TemporalPoint {
102            point: Point::new(2.3550, 48.8580),
103            timestamp: UNIX_EPOCH + Duration::from_secs(1640995300),
104        },
105        TemporalPoint {
106            point: Point::new(2.3580, 48.8600),
107            timestamp: UNIX_EPOCH + Duration::from_secs(1640995400),
108        },
109        TemporalPoint {
110            point: Point::new(2.3610, 48.8620),
111            timestamp: UNIX_EPOCH + Duration::from_secs(1640995500),
112        },
113        TemporalPoint {
114            point: Point::new(2.3640, 48.8640),
115            timestamp: UNIX_EPOCH + Duration::from_secs(1640995600),
116        },
117    ];
118
119    db.insert_trajectory("vehicle:bus123", &bus_route, None)?;
120    println!(
121        "   Stored bus trajectory with {} waypoints\n",
122        bus_route.len()
123    );
124
125    // === 5. QUERY DIFFERENT VEHICLES ===
126    println!("5. Query Different Vehicles");
127    println!("---------------------------");
128
129    let truck_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995400)?;
130    let taxi_path = db.query_trajectory("vehicle:taxi042", 1640995200, 1640995400)?;
131    let bus_path = db.query_trajectory("vehicle:bus123", 1640995200, 1640995700)?;
132
133    println!("   Truck waypoints: {}", truck_path.len());
134    println!("   Taxi waypoints: {}", taxi_path.len());
135    println!("   Bus waypoints: {}\n", bus_path.len());
136
137    // === 6. LONG-RUNNING TRAJECTORY ===
138    println!("6. Long-Running Trajectory (High Frequency)");
139    println!("-------------------------------------------");
140
141    // Simulate a drone with frequent position updates
142    let mut drone_path = Vec::new();
143    let start_time = 1641000000;
144
145    for i in 0..60 {
146        // 60 waypoints, 1 per second
147        drone_path.push(TemporalPoint {
148            point: Point::new(
149                -122.4194 + (i as f64 * 0.0001), // San Francisco area
150                37.7749 + (i as f64 * 0.0001),
151            ),
152            timestamp: UNIX_EPOCH + Duration::from_secs(start_time + i),
153        });
154    }
155
156    db.insert_trajectory("drone:delivery001", &drone_path, None)?;
157    println!(
158        "   Stored drone trajectory with {} waypoints",
159        drone_path.len()
160    );
161
162    // Query specific time window (10 seconds)
163    let window = db.query_trajectory("drone:delivery001", start_time, start_time + 10)?;
164    println!(
165        "   Retrieved 10-second window: {} waypoints\n",
166        window.len()
167    );
168
169    // === 7. TRAJECTORY UPDATES ===
170    println!("7. Trajectory Updates");
171    println!("---------------------");
172
173    // Add more waypoints to existing trajectory
174    let extended_route = vec![
175        TemporalPoint {
176            point: Point::new(-74.0060, 40.7128),
177            timestamp: UNIX_EPOCH + Duration::from_secs(1640995200),
178        },
179        TemporalPoint {
180            point: Point::new(-74.0040, 40.7150),
181            timestamp: UNIX_EPOCH + Duration::from_secs(1640995260),
182        },
183        TemporalPoint {
184            point: Point::new(-74.0020, 40.7172),
185            timestamp: UNIX_EPOCH + Duration::from_secs(1640995320),
186        },
187        TemporalPoint {
188            point: Point::new(-74.0000, 40.7194),
189            timestamp: UNIX_EPOCH + Duration::from_secs(1640995380),
190        },
191        // New waypoints
192        TemporalPoint {
193            point: Point::new(-73.9980, 40.7216),
194            timestamp: UNIX_EPOCH + Duration::from_secs(1640995440),
195        },
196        TemporalPoint {
197            point: Point::new(-73.9960, 40.7238),
198            timestamp: UNIX_EPOCH + Duration::from_secs(1640995500),
199        },
200    ];
201
202    db.insert_trajectory("vehicle:truck001", &extended_route, None)?;
203    let updated_path = db.query_trajectory("vehicle:truck001", 1640995200, 1640995600)?;
204    println!(
205        "   Extended truck trajectory from 4 to {} waypoints\n",
206        updated_path.len()
207    );
208
209    // === 8. DATABASE STATISTICS ===
210    println!("8. Database Statistics");
211    println!("----------------------");
212
213    let stats = db.stats();
214    println!("   Total keys in database: {}", stats.key_count);
215    println!("   Total operations: {}\n", stats.operations_count);
216
217    // === 9. USE CASES ===
218    println!("=== Common Use Cases ===\n");
219
220    println!("Fleet Management:");
221    println!("  • Track multiple vehicles in real-time");
222    println!("  • Query historical routes for analysis");
223    println!("  • Retrieve specific time windows for incidents\n");
224
225    println!("Delivery Tracking:");
226    println!("  • Store complete delivery routes");
227    println!("  • Query progress during specific periods");
228    println!("  • Analyze route efficiency\n");
229
230    println!("Drone Operations:");
231    println!("  • High-frequency position updates");
232    println!("  • Flight path analysis");
233    println!("  • Time-based route queries\n");
234
235    println!("Asset Tracking:");
236    println!("  • Monitor movement of valuable items");
237    println!("  • Historical location queries");
238    println!("  • Route verification\n");
239
240    println!("=== Trajectory Tracking Complete! ===");
241    println!("\nKey Features Demonstrated:");
242    println!("  • Store trajectories with timestamps");
243    println!("  • Query full trajectories");
244    println!("  • Query specific time ranges");
245    println!("  • Track multiple vehicles/objects");
246    println!("  • High-frequency updates");
247    println!("  • Trajectory extensions/updates");
248
249    Ok(())
250}
examples/advanced_spatial.rs (line 111)
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15    println!("=== Advanced Spatial Operations Demo ===\n");
16
17    // Create an in-memory database
18    let mut db = Spatio::memory()?;
19
20    // ========================================
21    // 1. Distance Calculations
22    // ========================================
23    println!("1. Distance Calculations");
24    println!("{}", "=".repeat(50));
25
26    let new_york = Point::new(-74.0060, 40.7128);
27    let los_angeles = Point::new(-118.2437, 34.0522);
28    let london = Point::new(-0.1278, 51.5074);
29
30    // Calculate distances using different metrics
31    let dist_haversine = distance_between(&new_york, &los_angeles, DistanceMetric::Haversine);
32    let dist_geodesic = distance_between(&new_york, &los_angeles, DistanceMetric::Geodesic);
33    let dist_rhumb = distance_between(&new_york, &los_angeles, DistanceMetric::Rhumb);
34
35    println!("NYC to LA:");
36    println!("  Haversine:  {:.2} km", dist_haversine / 1000.0);
37    println!("  Geodesic:   {:.2} km", dist_geodesic / 1000.0);
38    println!("  Rhumb:      {:.2} km", dist_rhumb / 1000.0);
39
40    // Using the database method
41    let db_distance = db.distance_between(&new_york, &london, DistanceMetric::Haversine)?;
42    println!("\nNYC to London: {:.2} km", db_distance / 1000.0);
43
44    // ========================================
45    // 2. K-Nearest-Neighbors (KNN)
46    // ========================================
47    println!("\n2. K-Nearest-Neighbors Query");
48    println!("{}", "=".repeat(50));
49
50    // Insert major cities
51    let cities = vec![
52        (Point::new(-74.0060, 40.7128), "New York", "USA"),
53        (Point::new(-118.2437, 34.0522), "Los Angeles", "USA"),
54        (Point::new(-87.6298, 41.8781), "Chicago", "USA"),
55        (Point::new(-95.3698, 29.7604), "Houston", "USA"),
56        (Point::new(-75.1652, 39.9526), "Philadelphia", "USA"),
57        (Point::new(-122.4194, 37.7749), "San Francisco", "USA"),
58        (Point::new(-0.1278, 51.5074), "London", "UK"),
59        (Point::new(2.3522, 48.8566), "Paris", "France"),
60        (Point::new(139.6917, 35.6895), "Tokyo", "Japan"),
61    ];
62
63    for (point, name, country) in &cities {
64        let data = format!("{},{}", name, country);
65        db.insert_point("world_cities", point, data.as_bytes(), None)?;
66    }
67
68    // Find 3 nearest cities to a query point (somewhere in New Jersey)
69    let query_point = Point::new(-74.1719, 40.7357);
70    let nearest = db.knn(
71        "world_cities",
72        &query_point,
73        3,
74        500_000.0, // Search within 500km
75        DistanceMetric::Haversine,
76    )?;
77
78    println!("3 nearest cities to query point:");
79    for (i, (_point, data, distance)) in nearest.iter().enumerate() {
80        let city_info = String::from_utf8_lossy(data);
81        println!(
82            "  {}. {} ({:.2} km away)",
83            i + 1,
84            city_info,
85            distance / 1000.0
86        );
87    }
88
89    // ========================================
90    // 3. Polygon Queries
91    // ========================================
92    println!("\n3. Polygon Queries");
93    println!("{}", "=".repeat(50));
94
95    // Define a polygon covering parts of the eastern US
96    use geo::polygon;
97    let east_coast_polygon = polygon![
98        (x: -80.0, y: 35.0),  // South
99        (x: -70.0, y: 35.0),  // Southeast
100        (x: -70.0, y: 45.0),  // Northeast
101        (x: -80.0, y: 45.0),  // Northwest
102        (x: -80.0, y: 35.0),  // Close the polygon
103    ];
104    let east_coast_polygon: Polygon = east_coast_polygon.into();
105
106    let cities_in_polygon = db.query_within_polygon("world_cities", &east_coast_polygon, 100)?;
107
108    println!("Cities within East Coast polygon:");
109    for (point, data) in &cities_in_polygon {
110        let city_info = String::from_utf8_lossy(data);
111        println!("  - {} at ({:.4}, {:.4})", city_info, point.x(), point.y());
112    }
113
114    // ========================================
115    // 4. Bounding Box Operations
116    // ========================================
117    println!("\n4. Bounding Box Operations");
118    println!("{}", "=".repeat(50));
119
120    // Create a bounding box around the New York area
121    let ny_bbox = bounding_box(-74.5, 40.5, -73.5, 41.0)?;
122    println!("NY Area Bounding Box: {:?}", ny_bbox);
123
124    // Find cities in bounding box
125    let cities_in_bbox = db.find_within_bounds("world_cities", 40.5, -74.5, 41.0, -73.5, 100)?;
126    println!("\nCities in NY area bounding box:");
127    for (_point, data) in &cities_in_bbox {
128        let city_info = String::from_utf8_lossy(data);
129        println!("  - {}", city_info);
130    }
131
132    // ========================================
133    // 5. Convex Hull
134    // ========================================
135    println!("\n5. Convex Hull Calculation");
136    println!("{}", "=".repeat(50));
137
138    // Get all city points
139    let city_points: Vec<Point> = cities.iter().map(|(p, _, _)| *p).collect();
140
141    // Calculate convex hull
142    if let Some(hull) = convex_hull(&city_points) {
143        println!("Convex hull of all cities:");
144        println!("  Exterior points: {}", hull.exterior().0.len() - 1);
145        for coord in hull.exterior().0.iter().take(5) {
146            println!("    ({:.4}, {:.4})", coord.x, coord.y);
147        }
148    }
149
150    // ========================================
151    // 6. Bounding Rectangle
152    // ========================================
153    println!("\n6. Bounding Rectangle");
154    println!("{}", "=".repeat(50));
155
156    if let Some(bbox) = bounding_rect_for_points(&city_points) {
157        println!("Bounding rectangle of all cities:");
158        println!("  Min: ({:.4}, {:.4})", bbox.min().x, bbox.min().y);
159        println!("  Max: ({:.4}, {:.4})", bbox.max().x, bbox.max().y);
160        println!("  Width:  {:.2}°", bbox.max().x - bbox.min().x);
161        println!("  Height: {:.2}°", bbox.max().y - bbox.min().y);
162    }
163
164    // ========================================
165    // 7. Advanced Radius Queries
166    // ========================================
167    println!("\n7. Advanced Radius Queries");
168    println!("{}", "=".repeat(50));
169
170    // Count cities within 1000km of NYC
171    let count = db.count_within_radius("world_cities", &new_york, 1_000_000.0)?;
172    println!("Cities within 1000km of NYC: {}", count);
173
174    // Check if any cities exist within 100km
175    let has_nearby = db.intersects_radius("world_cities", &new_york, 100_000.0)?;
176    println!("Has cities within 100km of NYC: {}", has_nearby);
177
178    // Query with radius
179    let nearby = db.query_within_radius("world_cities", &new_york, 200_000.0, 10)?;
180    println!("\nCities within 200km of NYC:");
181    for (point, data, _distance) in &nearby {
182        let city_info = String::from_utf8_lossy(data);
183        let dist = distance_between(&new_york, point, DistanceMetric::Haversine);
184        println!("  - {} ({:.2} km)", city_info, dist / 1000.0);
185    }
186
187    // ========================================
188    // 8. Spatial Analytics
189    // ========================================
190    println!("\n8. Spatial Analytics");
191    println!("{}", "=".repeat(50));
192
193    // Find the two most distant cities (brute force)
194    let mut max_distance = 0.0;
195    let mut furthest_pair = ("", "");
196
197    for (i, (p1, n1, _)) in cities.iter().enumerate() {
198        for (p2, n2, _) in cities.iter().skip(i + 1) {
199            let dist = distance_between(p1, p2, DistanceMetric::Geodesic);
200            if dist > max_distance {
201                max_distance = dist;
202                furthest_pair = (n1, n2);
203            }
204        }
205    }
206
207    println!(
208        "Most distant city pair: {} ↔ {}",
209        furthest_pair.0, furthest_pair.1
210    );
211    println!("Distance: {:.2} km", max_distance / 1000.0);
212
213    // Calculate average distance between all US cities
214    let us_cities: Vec<_> = cities
215        .iter()
216        .filter(|(_, _, country)| *country == "USA")
217        .collect();
218
219    if us_cities.len() > 1 {
220        let mut total_distance = 0.0;
221        let mut count = 0;
222
223        for (i, (p1, _, _)) in us_cities.iter().enumerate() {
224            for (p2, _, _) in us_cities.iter().skip(i + 1) {
225                total_distance += distance_between(p1, p2, DistanceMetric::Haversine);
226                count += 1;
227            }
228        }
229
230        let avg_distance = total_distance / count as f64;
231        println!(
232            "\nAverage distance between US cities: {:.2} km",
233            avg_distance / 1000.0
234        );
235    }
236
237    // ========================================
238    // Summary
239    // ========================================
240    println!("\n{}", "=".repeat(50));
241    println!("Summary:");
242    println!("  - Demonstrated multiple distance metrics");
243    println!("  - Performed K-nearest-neighbor searches");
244    println!("  - Queried points within polygons");
245    println!("  - Used bounding box operations");
246    println!("  - Calculated convex hulls");
247    println!("  - Performed spatial analytics");
248    println!("\nAll spatial operations leverage the geo crate!");
249
250    Ok(())
251}
examples/bbox_database.rs (line 53)
9fn main() -> Result<(), Box<dyn Error>> {
10    println!("=== Spatio - Bounding Box Database ===\n");
11
12    let mut db = Spatio::memory()?;
13    println!("✓ Created in-memory database\n");
14
15    // ========================================
16    // 1. Store Geographic Regions
17    // ========================================
18    println!("1. Storing Geographic Regions");
19    println!("------------------------------");
20
21    // Define NYC boroughs as bounding boxes
22    let manhattan = BoundingBox2D::new(-74.0479, 40.6829, -73.9067, 40.8820);
23    let brooklyn = BoundingBox2D::new(-74.0421, 40.5707, -73.8333, 40.7395);
24    let queens = BoundingBox2D::new(-73.9626, 40.5431, -73.7004, 40.8007);
25    let bronx = BoundingBox2D::new(-73.9338, 40.7855, -73.7654, 40.9176);
26    let staten_island = BoundingBox2D::new(-74.2558, 40.4960, -74.0526, 40.6490);
27
28    // Store regions in database
29    db.insert_bbox("region:manhattan", &manhattan, None)?;
30    db.insert_bbox("region:brooklyn", &brooklyn, None)?;
31    db.insert_bbox("region:queens", &queens, None)?;
32    db.insert_bbox("region:bronx", &bronx, None)?;
33    db.insert_bbox("region:staten_island", &staten_island, None)?;
34
35    println!("   ✓ Stored 5 NYC borough boundaries");
36
37    // ========================================
38    // 2. Retrieve Stored Regions
39    // ========================================
40    println!("\n2. Retrieving Stored Regions");
41    println!("-----------------------------");
42
43    if let Some(retrieved_manhattan) = db.get_bbox("region:manhattan")? {
44        println!("   Manhattan:");
45        println!(
46            "     Area: {:.4}° × {:.4}°",
47            retrieved_manhattan.width(),
48            retrieved_manhattan.height()
49        );
50        println!(
51            "     Center: ({:.4}, {:.4})",
52            retrieved_manhattan.center().x(),
53            retrieved_manhattan.center().y()
54        );
55    }
56
57    // ========================================
58    // 3. Store POIs and Query by Region
59    // ========================================
60    println!("\n3. Store POIs and Query by Region");
61    println!("-----------------------------------");
62
63    // Store points of interest
64    db.insert_point("poi", &Point::new(-73.9855, 40.7580), b"times_square", None)?;
65    db.insert_point("poi", &Point::new(-73.9665, 40.7829), b"central_park", None)?;
66    db.insert_point("poi", &Point::new(-73.9857, 40.7484), b"empire_state", None)?;
67    db.insert_point(
68        "poi",
69        &Point::new(-73.9969, 40.7061),
70        b"brooklyn_bridge",
71        None,
72    )?;
73    db.insert_point(
74        "poi",
75        &Point::new(-73.9690, 40.6602),
76        b"prospect_park",
77        None,
78    )?;
79    db.insert_point("poi", &Point::new(-73.9799, 40.5755), b"coney_island", None)?;
80
81    println!("   ✓ Stored 6 points of interest");
82
83    // Query POIs in Manhattan
84    let manhattan_pois = db.query_within_bbox("poi", &manhattan, 100)?;
85    println!("\n   POIs in Manhattan: {}", manhattan_pois.len());
86    for (point, data) in &manhattan_pois {
87        let name = String::from_utf8_lossy(data);
88        println!("     - {} at ({:.4}, {:.4})", name, point.x(), point.y());
89    }
90
91    // Query POIs in Brooklyn
92    let brooklyn_pois = db.query_within_bbox("poi", &brooklyn, 100)?;
93    println!("\n   POIs in Brooklyn: {}", brooklyn_pois.len());
94
95    // ========================================
96    // 4. Find Intersecting Regions
97    // ========================================
98    println!("\n4. Finding Intersecting Regions");
99    println!("--------------------------------");
100
101    // Create a search area (covering parts of Manhattan and Queens)
102    let search_area = BoundingBox2D::new(-73.98, 40.72, -73.92, 40.78);
103
104    let intersecting = db.find_intersecting_bboxes("region:", &search_area)?;
105    println!(
106        "   Search area intersects with {} boroughs:",
107        intersecting.len()
108    );
109    for (key, _bbox) in &intersecting {
110        println!("     - {}", key.replace("region:", ""));
111    }
112
113    // ========================================
114    // 5. Delivery Zone Management
115    // ========================================
116    println!("\n5. Delivery Zone Management");
117    println!("----------------------------");
118
119    // Define delivery zones
120    let zone_a = BoundingBox2D::new(-74.02, 40.70, -73.98, 40.74);
121    let zone_b = BoundingBox2D::new(-74.00, 40.72, -73.96, 40.76);
122    let zone_c = BoundingBox2D::new(-73.98, 40.74, -73.94, 40.78);
123
124    db.insert_bbox("delivery:zone_a", &zone_a, None)?;
125    db.insert_bbox("delivery:zone_b", &zone_b, None)?;
126    db.insert_bbox("delivery:zone_c", &zone_c, None)?;
127
128    println!("   ✓ Created 3 delivery zones");
129
130    // Check which zones overlap
131    let overlapping_with_a = db.find_intersecting_bboxes("delivery:", &zone_a)?;
132    println!(
133        "\n   Zone A overlaps with {} zones (including itself)",
134        overlapping_with_a.len()
135    );
136
137    // ========================================
138    // 6. Service Area Lookup
139    // ========================================
140    println!("\n6. Service Area Lookup");
141    println!("-----------------------");
142
143    // Check if various locations are in service areas
144    let locations = vec![
145        ("Customer 1", Point::new(-74.00, 40.72)),
146        ("Customer 2", Point::new(-73.97, 40.75)),
147        ("Customer 3", Point::new(-74.05, 40.68)),
148    ];
149
150    for (name, location) in &locations {
151        let mut in_zone = false;
152        for (zone_key, zone_bbox) in &overlapping_with_a {
153            if zone_bbox.contains_point(location) {
154                println!(
155                    "   {} at ({:.4}, {:.4}) is in {}",
156                    name,
157                    location.x(),
158                    location.y(),
159                    zone_key.replace("delivery:", "")
160                );
161                in_zone = true;
162                break;
163            }
164        }
165        if !in_zone {
166            println!(
167                "   {} at ({:.4}, {:.4}) is outside all zones",
168                name,
169                location.x(),
170                location.y()
171            );
172        }
173    }
174
175    // ========================================
176    // 7. Geofencing Example
177    // ========================================
178    println!("\n7. Geofencing Example");
179    println!("----------------------");
180
181    // Define restricted areas
182    let airport_zone = BoundingBox2D::new(-73.82, 40.63, -73.76, 40.66);
183    db.insert_bbox("restricted:jfk_airport", &airport_zone, None)?;
184
185    let military_zone = BoundingBox2D::new(-74.08, 40.60, -74.03, 40.64);
186    db.insert_bbox("restricted:military", &military_zone, None)?;
187
188    println!("   ✓ Defined 2 restricted zones");
189
190    // Check if drone locations are in restricted areas
191    let drone_locations = vec![
192        ("Drone 1", Point::new(-73.79, 40.64)),
193        ("Drone 2", Point::new(-74.00, 40.70)),
194    ];
195
196    for (drone, location) in &drone_locations {
197        let restricted = db.find_intersecting_bboxes(
198            "restricted:",
199            &BoundingBox2D::new(
200                location.x() - 0.001,
201                location.y() - 0.001,
202                location.x() + 0.001,
203                location.y() + 0.001,
204            ),
205        )?;
206
207        if !restricted.is_empty() {
208            println!(
209                "   ⚠ {} at ({:.4}, {:.4}) is in restricted area: {}",
210                drone,
211                location.x(),
212                location.y(),
213                restricted[0].0.replace("restricted:", "")
214            );
215        } else {
216            println!(
217                "   ✓ {} at ({:.4}, {:.4}) is in safe area",
218                drone,
219                location.x(),
220                location.y()
221            );
222        }
223    }
224
225    // ========================================
226    // 8. Spatial Analytics
227    // ========================================
228    println!("\n8. Spatial Analytics");
229    println!("---------------------");
230
231    // Calculate coverage area
232    let mut total_width = 0.0;
233    let mut total_height = 0.0;
234    let mut count = 0;
235
236    let all_regions = vec![
237        ("Manhattan", &manhattan),
238        ("Brooklyn", &brooklyn),
239        ("Queens", &queens),
240        ("Bronx", &bronx),
241        ("Staten Island", &staten_island),
242    ];
243
244    for (name, bbox) in &all_regions {
245        total_width += bbox.width();
246        total_height += bbox.height();
247        count += 1;
248        println!(
249            "   {} coverage: {:.4}° × {:.4}°",
250            name,
251            bbox.width(),
252            bbox.height()
253        );
254    }
255
256    let avg_width = total_width / count as f64;
257    let avg_height = total_height / count as f64;
258
259    println!(
260        "\n   Average borough size: {:.4}° × {:.4}°",
261        avg_width, avg_height
262    );
263
264    // ========================================
265    // 9. Database Statistics
266    // ========================================
267    println!("\n9. Database Statistics");
268    println!("-----------------------");
269
270    let stats = db.stats();
271    println!("   Total keys: {}", stats.key_count);
272    println!("   Total operations: {}", stats.operations_count);
273
274    // Count different types of data
275    let poi_count = manhattan_pois.len() + brooklyn_pois.len();
276    println!("   Stored POIs: {}", poi_count);
277    println!("   Stored regions: 5");
278    println!("   Delivery zones: 3");
279    println!("   Restricted zones: 2");
280
281    println!("\n=== Bounding Box Database Integration Complete! ===");
282    println!("\nKey Features Demonstrated:");
283    println!("  • Store and retrieve bounding boxes");
284    println!("  • Query POIs within regions");
285    println!("  • Find intersecting regions");
286    println!("  • Delivery zone management");
287    println!("  • Service area lookups");
288    println!("  • Geofencing and restricted areas");
289    println!("  • Spatial analytics");
290
291    Ok(())
292}
examples/bounding_boxes.rs (line 43)
10fn main() -> Result<(), Box<dyn Error>> {
11    println!("=== Spatio - Bounding Box Examples ===\n");
12
13    // Create an in-memory database
14    let mut db = Spatio::memory()?;
15    println!("✓ Created in-memory database\n");
16
17    // ========================================
18    // 1. Basic 2D Bounding Box Operations
19    // ========================================
20    println!("1. Basic 2D Bounding Box");
21    println!("-------------------------");
22
23    // Create a bounding box for Manhattan
24    let manhattan = BoundingBox2D::new(
25        -74.0479, 40.6829, // Southwest corner (Battery Park)
26        -73.9067, 40.8820, // Northeast corner (Inwood)
27    );
28
29    println!("   Manhattan bounding box:");
30    println!(
31        "     Min: ({:.4}, {:.4})",
32        manhattan.min_x(),
33        manhattan.min_y()
34    );
35    println!(
36        "     Max: ({:.4}, {:.4})",
37        manhattan.max_x(),
38        manhattan.max_y()
39    );
40    println!(
41        "     Center: ({:.4}, {:.4})",
42        manhattan.center().x(),
43        manhattan.center().y()
44    );
45    println!(
46        "     Width: {:.4}°, Height: {:.4}°",
47        manhattan.width(),
48        manhattan.height()
49    );
50
51    // Check if points are within Manhattan
52    let times_square = Point::new(-73.9855, 40.7580);
53    let brooklyn_bridge = Point::new(-73.9969, 40.7061);
54    let statue_of_liberty = Point::new(-74.0445, 40.6892);
55    let jfk_airport = Point::new(-73.7781, 40.6413);
56
57    println!("\n   Point containment checks:");
58    println!(
59        "     Times Square: {}",
60        manhattan.contains_point(&times_square)
61    );
62    println!(
63        "     Brooklyn Bridge: {}",
64        manhattan.contains_point(&brooklyn_bridge)
65    );
66    println!(
67        "     Statue of Liberty: {}",
68        manhattan.contains_point(&statue_of_liberty)
69    );
70    println!(
71        "     JFK Airport: {}",
72        manhattan.contains_point(&jfk_airport)
73    );
74
75    // ========================================
76    // 2. Bounding Box Intersection
77    // ========================================
78    println!("\n2. Bounding Box Intersection");
79    println!("-----------------------------");
80
81    // Create bounding boxes for different NYC boroughs
82    let manhattan_bbox = BoundingBox2D::new(-74.0479, 40.6829, -73.9067, 40.8820);
83    let brooklyn_bbox = BoundingBox2D::new(-74.0421, 40.5707, -73.8333, 40.7395);
84    let queens_bbox = BoundingBox2D::new(-73.9626, 40.5431, -73.7004, 40.8007);
85
86    println!(
87        "   Manhattan ∩ Brooklyn: {}",
88        manhattan_bbox.intersects(&brooklyn_bbox)
89    );
90    println!(
91        "   Manhattan ∩ Queens: {}",
92        manhattan_bbox.intersects(&queens_bbox)
93    );
94    println!(
95        "   Brooklyn ∩ Queens: {}",
96        brooklyn_bbox.intersects(&queens_bbox)
97    );
98
99    // ========================================
100    // 3. Expanding Bounding Boxes
101    // ========================================
102    println!("\n3. Expanding Bounding Boxes");
103    println!("----------------------------");
104
105    let central_park = BoundingBox2D::new(-73.9812, 40.7644, -73.9492, 40.8003);
106    println!("   Central Park original:");
107    println!(
108        "     Width: {:.4}°, Height: {:.4}°",
109        central_park.width(),
110        central_park.height()
111    );
112
113    // Expand by 0.01 degrees (~1 km)
114    let expanded = central_park.expand(0.01);
115    println!("\n   Expanded by 0.01°:");
116    println!(
117        "     Width: {:.4}°, Height: {:.4}°",
118        expanded.width(),
119        expanded.height()
120    );
121    println!(
122        "     Growth: {:.4}° in each direction",
123        (expanded.width() - central_park.width()) / 2.0
124    );
125
126    // ========================================
127    // 4. 3D Bounding Boxes
128    // ========================================
129    println!("\n4. 3D Bounding Boxes");
130    println!("--------------------");
131
132    // Create a 3D bounding box for a tall building's footprint with height
133    let one_world_trade = BoundingBox3D::new(
134        -74.0134, 40.7127, 0.0, // Ground level southwest
135        -74.0118, 40.7143, 541.0, // Top level northeast (541m height)
136    );
137
138    println!("   One World Trade Center:");
139    println!(
140        "     Footprint: {:.4}° × {:.4}°",
141        one_world_trade.width(),
142        one_world_trade.height()
143    );
144    println!("     Height: {:.1} meters", one_world_trade.depth());
145    println!(
146        "     Volume: {:.6} cubic degrees×meters",
147        one_world_trade.volume()
148    );
149
150    let (cx, cy, cz) = one_world_trade.center();
151    println!("     Center: ({:.4}, {:.4}, {:.1}m)", cx, cy, cz);
152
153    // Check if points at different altitudes are within the building
154    println!("\n   Altitude containment checks:");
155    println!(
156        "     Ground level (0m): {}",
157        one_world_trade.contains_point(-74.0126, 40.7135, 0.0)
158    );
159    println!(
160        "     Mid-level (270m): {}",
161        one_world_trade.contains_point(-74.0126, 40.7135, 270.0)
162    );
163    println!(
164        "     Top (540m): {}",
165        one_world_trade.contains_point(-74.0126, 40.7135, 540.0)
166    );
167    println!(
168        "     Above (600m): {}",
169        one_world_trade.contains_point(-74.0126, 40.7135, 600.0)
170    );
171
172    // ========================================
173    // 5. 3D to 2D Projection
174    // ========================================
175    println!("\n5. 3D to 2D Projection");
176    println!("----------------------");
177
178    let building_3d = BoundingBox3D::new(-74.0, 40.7, 0.0, -73.9, 40.8, 200.0);
179    let building_2d = building_3d.to_2d();
180
181    println!("   3D Bounding Box:");
182    println!(
183        "     Dimensions: {:.4}° × {:.4}° × {:.1}m",
184        building_3d.width(),
185        building_3d.height(),
186        building_3d.depth()
187    );
188
189    println!("\n   Projected to 2D:");
190    println!(
191        "     Dimensions: {:.4}° × {:.4}°",
192        building_2d.width(),
193        building_2d.height()
194    );
195
196    // ========================================
197    // 6. Temporal Bounding Boxes
198    // ========================================
199    println!("\n6. Temporal Bounding Boxes");
200    println!("--------------------------");
201
202    // Track how a delivery zone changes over time
203    let morning_zone = BoundingBox2D::new(-74.01, 40.71, -73.99, 40.73);
204    let afternoon_zone = BoundingBox2D::new(-74.02, 40.70, -73.98, 40.74);
205
206    let morning_time = SystemTime::now();
207    let afternoon_time = SystemTime::now();
208
209    let temporal_morning = TemporalBoundingBox2D::new(morning_zone.clone(), morning_time);
210    let temporal_afternoon = TemporalBoundingBox2D::new(afternoon_zone.clone(), afternoon_time);
211
212    println!("   Morning delivery zone:");
213    println!(
214        "     Area: {:.4}° × {:.4}°",
215        temporal_morning.bbox().width(),
216        temporal_morning.bbox().height()
217    );
218
219    println!("\n   Afternoon delivery zone:");
220    println!(
221        "     Area: {:.4}° × {:.4}°",
222        temporal_afternoon.bbox().width(),
223        temporal_afternoon.bbox().height()
224    );
225
226    println!(
227        "     Expansion: {:.4}° wider, {:.4}° taller",
228        afternoon_zone.width() - morning_zone.width(),
229        afternoon_zone.height() - morning_zone.height()
230    );
231
232    // ========================================
233    // 7. Storing Bounding Boxes in Database
234    // ========================================
235    println!("\n7. Storing Bounding Boxes");
236    println!("-------------------------");
237
238    // Serialize and store bounding boxes
239    let bbox_json = serde_json::to_vec(&manhattan)?;
240    db.insert("zones:manhattan", bbox_json, None)?;
241
242    let bbox3d_json = serde_json::to_vec(&one_world_trade)?;
243    db.insert("buildings:wtc", bbox3d_json, None)?;
244
245    println!("   ✓ Stored Manhattan bounding box");
246    println!("   ✓ Stored One World Trade Center 3D box");
247
248    // Retrieve and deserialize
249    if let Some(data) = db.get("zones:manhattan")? {
250        let retrieved: BoundingBox2D = serde_json::from_slice(&data)?;
251        println!("\n   Retrieved Manhattan box:");
252        println!(
253            "     Center: ({:.4}, {:.4})",
254            retrieved.center().x(),
255            retrieved.center().y()
256        );
257    }
258
259    // ========================================
260    // 8. Practical Use Cases
261    // ========================================
262    println!("\n8. Practical Use Cases");
263    println!("----------------------");
264
265    // Geofencing
266    let delivery_area = BoundingBox2D::new(-74.02, 40.70, -73.98, 40.75);
267    let current_location = Point::new(-74.00, 40.72);
268
269    if delivery_area.contains_point(&current_location) {
270        println!("   ✓ Delivery driver is within service area");
271    } else {
272        println!("   ✗ Delivery driver is outside service area");
273    }
274
275    // Airspace management
276    let airspace = BoundingBox3D::new(
277        -74.1, 40.6, 0.0, // Ground level
278        -73.8, 40.9, 3000.0, // 3000m ceiling
279    );
280    let drone_altitude = 150.0; // meters
281    let drone_location = (-74.0, 40.75, drone_altitude);
282
283    if airspace.contains_point(drone_location.0, drone_location.1, drone_location.2) {
284        println!("   ✓ Drone is within authorized airspace");
285    }
286
287    // Region overlap detection
288    let zone_a = BoundingBox2D::new(-74.05, 40.70, -74.00, 40.75);
289    let zone_b = BoundingBox2D::new(-74.02, 40.72, -73.97, 40.77);
290
291    if zone_a.intersects(&zone_b) {
292        println!("   ⚠ Service zones A and B overlap - coordination needed");
293    }
294
295    println!("\n=== Bounding Box Examples Complete! ===");
296    println!("\nKey Features Demonstrated:");
297    println!("  • Create and manipulate 2D/3D bounding boxes");
298    println!("  • Check point containment");
299    println!("  • Detect box intersections");
300    println!("  • Expand regions");
301    println!("  • Project 3D to 2D");
302    println!("  • Track temporal changes");
303    println!("  • Serialize and store in database");
304    println!("  • Geofencing and airspace management");
305
306    Ok(())
307}
Source

pub fn lon(&self) -> f64

Get the longitude (alias for x).

Source

pub fn lat(&self) -> f64

Get the latitude (alias for y).

Source

pub fn inner(&self) -> &Point

Access the inner geo::Point.

Source

pub fn into_inner(self) -> Point

Convert into the inner geo::Point.

Source

pub fn haversine_distance(&self, other: &Point) -> f64

Calculate haversine distance to another point in meters.

Uses the haversine formula which accounts for Earth’s curvature.

§Examples
use spatio_types::geo::Point;

let nyc = Point::new(-74.0060, 40.7128);
let la = Point::new(-118.2437, 34.0522);
let distance = nyc.haversine_distance(&la);
assert!(distance > 3_900_000.0); // ~3,944 km
Source

pub fn geodesic_distance(&self, other: &Point) -> f64

Calculate geodesic distance to another point in meters.

Uses the Vincenty formula which is more accurate than haversine but slightly slower.

§Examples
use spatio_types::geo::Point;

let p1 = Point::new(-74.0060, 40.7128);
let p2 = Point::new(-74.0070, 40.7138);
let distance = p1.geodesic_distance(&p2);
Source

pub fn euclidean_distance(&self, other: &Point) -> f64

Calculate euclidean distance to another point.

This calculates straight-line distance in the coordinate space, which is only accurate for small distances.

§Examples
use spatio_types::geo::Point;

let p1 = Point::new(0.0, 0.0);
let p2 = Point::new(3.0, 4.0);
let distance = p1.euclidean_distance(&p2);
assert_eq!(distance, 5.0); // 3-4-5 triangle
Source

pub fn to_geojson(&self) -> Result<String, GeoJsonError>

Convert to GeoJSON string representation.

§Examples
use spatio_types::geo::Point;

let point = Point::new(-74.0060, 40.7128);
let json = point.to_geojson().unwrap();
assert!(json.contains("Point"));
Source

pub fn from_geojson(geojson: &str) -> Result<Point, GeoJsonError>

Parse from GeoJSON string.

§Examples
use spatio_types::geo::Point;

let json = r#"{"type":"Point","coordinates":[-74.006,40.7128]}"#;
let point = Point::from_geojson(json).unwrap();
assert_eq!(point.x(), -74.006);

Trait Implementations§

Source§

impl Clone for Point

Source§

fn clone(&self) -> Point

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Point

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Point

Source§

fn deserialize<__D>( __deserializer: __D, ) -> Result<Point, <__D as Deserializer<'de>>::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl From<(f64, f64)> for Point

Source§

fn from(_: (f64, f64)) -> Point

Converts to this type from the input type.
Source§

impl From<Point> for Point

Source§

fn from(point: Point) -> Point

Converts to this type from the input type.
Source§

impl PartialEq for Point

Source§

fn eq(&self, other: &Point) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for Point

Source§

fn serialize<__S>( &self, __serializer: __S, ) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Copy for Point

Source§

impl StructuralPartialEq for Point

Auto Trait Implementations§

§

impl Freeze for Point

§

impl RefUnwindSafe for Point

§

impl Send for Point

§

impl Sync for Point

§

impl Unpin for Point

§

impl UnwindSafe for Point

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<G1, G2> Within<G2> for G1
where G2: Contains<G1>,

Source§

fn is_within(&self, b: &G2) -> bool

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,