spatial_queries/
spatial_queries.rs

1use spatio::{BoundingBox, Point, Spatio};
2
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Spatio - Spatio-Temporal Queries Example");
5    println!("=================================");
6
7    // Create an in-memory database
8    let db = Spatio::memory()?;
9    println!("Created spatio-temporal database");
10
11    // Add world cities with their coordinates
12    let cities = vec![
13        ("New York", Point::new(40.7128, -74.0060)),
14        ("London", Point::new(51.5074, -0.1278)),
15        ("Tokyo", Point::new(35.6762, 139.6503)),
16        ("Sydney", Point::new(-33.8688, 151.2093)),
17        ("Paris", Point::new(48.8566, 2.3522)),
18        ("Berlin", Point::new(52.5200, 13.4050)),
19        ("Mumbai", Point::new(19.0760, 72.8777)),
20        ("Cairo", Point::new(30.0444, 31.2357)),
21        ("São Paulo", Point::new(-23.5505, -46.6333)),
22        ("Mexico City", Point::new(19.4326, -99.1332)),
23    ];
24
25    // Insert cities into the database (automatically indexed)
26    for (name, point) in &cities {
27        db.insert_point("world_cities", point, name.as_bytes(), None)?;
28    }
29    println!("Added {} cities to spatial index", cities.len());
30
31    // Define a reference point (London)
32    let reference_point = Point::new(51.5074, -0.1278);
33    println!("Using London as reference point: {}", reference_point);
34
35    // Find cities within 1000km of London
36    println!("\nCities within 1000km of London:");
37    let nearby_cities =
38        db.query_within_radius("world_cities", &reference_point, 1_000_000.0, 10)?;
39
40    for (point, data) in &nearby_cities {
41        let city_name = String::from_utf8_lossy(data);
42        let distance_km = reference_point.distance_to(point) / 1000.0;
43        println!("  - {} ({:.0} km away)", city_name, distance_km);
44    }
45
46    // Find cities within 2000km of London
47    println!("\nCities within 2000km of London:");
48    let medium_range_cities =
49        db.query_within_radius("world_cities", &reference_point, 2_000_000.0, 10)?;
50
51    for (point, data) in &medium_range_cities {
52        let city_name = String::from_utf8_lossy(data);
53        let distance_km = reference_point.distance_to(point) / 1000.0;
54        println!("  - {} ({:.0} km away)", city_name, distance_km);
55    }
56
57    // Find the 3 closest cities to London (regardless of distance)
58    println!("\n3 closest cities to London:");
59    let closest_cities =
60        db.query_within_radius("world_cities", &reference_point, f64::INFINITY, 3)?;
61
62    for (i, (point, data)) in closest_cities.iter().enumerate() {
63        let city_name = String::from_utf8_lossy(data);
64        let distance_km = reference_point.distance_to(point) / 1000.0;
65        println!("  {}. {} ({:.0} km away)", i + 1, city_name, distance_km);
66    }
67
68    // Demonstrate distance calculations between specific cities
69    println!("\nDistance calculations:");
70    let nyc = Point::new(40.7128, -74.0060);
71    let tokyo = Point::new(35.6762, 139.6503);
72    let sydney = Point::new(-33.8688, 151.2093);
73
74    println!(
75        "  - New York ↔ London: {:.0} km",
76        nyc.distance_to(&reference_point) / 1000.0
77    );
78    println!(
79        "  - London ↔ Tokyo: {:.0} km",
80        reference_point.distance_to(&tokyo) / 1000.0
81    );
82    println!(
83        "  - Tokyo ↔ Sydney: {:.0} km",
84        tokyo.distance_to(&sydney) / 1000.0
85    );
86
87    // Add some points of interest in London
88    let london_poi = vec![
89        ("Tower Bridge", Point::new(51.5055, -0.0754)),
90        ("Big Ben", Point::new(51.4994, -0.1245)),
91        ("London Eye", Point::new(51.5033, -0.1195)),
92        ("Buckingham Palace", Point::new(51.5014, -0.1419)),
93        ("Hyde Park", Point::new(51.5074, -0.1657)),
94    ];
95
96    for (name, point) in &london_poi {
97        db.insert_point("london_poi", point, name.as_bytes(), None)?;
98    }
99    println!("\nAdded {} London points of interest", london_poi.len());
100
101    // Find POI within 2km of Big Ben
102    let big_ben = Point::new(51.4994, -0.1245);
103    println!("\nPoints of interest within 2km of Big Ben:");
104    let nearby_poi = db.query_within_radius("london_poi", &big_ben, 2000.0, 10)?;
105
106    for (point, data) in &nearby_poi {
107        let poi_name = String::from_utf8_lossy(data);
108        let distance_m = big_ben.distance_to(point);
109        if distance_m < 10.0 {
110            println!("  - {} (same location)", poi_name);
111        } else {
112            println!("  - {} ({:.0}m away)", poi_name, distance_m);
113        }
114    }
115
116    // Database statistics
117    let stats = db.stats()?;
118    println!("\nDatabase statistics:");
119    println!("  - Total keys: {}", stats.key_count);
120    println!("  - Operations performed: {}", stats.operations_count);
121
122    // Demonstrate new spatial query methods
123    println!("\nAdvanced Spatial Query Methods:");
124
125    // Test contains_point - check if there are any cities within 1000km of London
126    let has_nearby_cities = db.contains_point("world_cities", &reference_point, 1_000_000.0)?;
127    println!(
128        "  Cities within 1000km of London exist: {}",
129        has_nearby_cities
130    );
131
132    // Count cities within different distances from London
133    let count_500km = db.count_within_radius("world_cities", &reference_point, 500_000.0)?;
134    let count_1000km = db.count_within_radius("world_cities", &reference_point, 1_000_000.0)?;
135    let count_2000km = db.count_within_radius("world_cities", &reference_point, 2_000_000.0)?;
136
137    println!("  Cities within 500km: {}", count_500km);
138    println!("  Cities within 1000km: {}", count_1000km);
139    println!("  Cities within 2000km: {}", count_2000km);
140
141    // Test bounding box queries - European region
142    let europe_bounds = (45.0, -10.0, 60.0, 30.0); // min_lat, min_lon, max_lat, max_lon
143    let has_european_cities = db.intersects_bounds(
144        "world_cities",
145        europe_bounds.0,
146        europe_bounds.1,
147        europe_bounds.2,
148        europe_bounds.3,
149    )?;
150    println!("  European cities exist: {}", has_european_cities);
151
152    // Find all cities in European region
153    let european_cities = db.find_within_bounds(
154        "world_cities",
155        europe_bounds.0,
156        europe_bounds.1,
157        europe_bounds.2,
158        europe_bounds.3,
159        10,
160    )?;
161
162    println!("  Cities in European region:");
163    for (point, data) in &european_cities {
164        let city_name = String::from_utf8_lossy(data);
165        println!("    - {} at {}", city_name, point);
166    }
167
168    // Test bounding box around London area
169    let london_area = (51.0, -1.0, 52.0, 1.0);
170    let london_area_cities = db.find_within_bounds(
171        "world_cities",
172        london_area.0,
173        london_area.1,
174        london_area.2,
175        london_area.3,
176        5,
177    )?;
178
179    println!("  Cities in London area:");
180    for (point, data) in &london_area_cities {
181        let city_name = String::from_utf8_lossy(data);
182        println!("    - {} at {}", city_name, point);
183    }
184
185    // Demonstrate BoundingBox struct usage
186    let asia_pacific = BoundingBox::new(-50.0, 100.0, 50.0, 180.0);
187    let europe_box = BoundingBox::new(35.0, -10.0, 70.0, 40.0);
188
189    println!("  BoundingBox intersection test:");
190    println!(
191        "    - Asia-Pacific and Europe intersect: {}",
192        asia_pacific.intersects(&europe_box)
193    );
194
195    // Test point containment methods
196    println!("  Point containment tests:");
197    let central_london = Point::new(51.5074, -0.1278);
198    let tower_bridge = Point::new(51.5055, -0.0754);
199
200    println!(
201        "    - Tower Bridge within 5km of Central London: {}",
202        central_london.contains_point(&tower_bridge, 5000.0)
203    );
204    println!(
205        "    - Central London within 2km of Tower Bridge: {}",
206        tower_bridge.contains_point(&central_london, 2000.0)
207    );
208
209    println!("\nEnhanced spatial queries example completed successfully!");
210    println!("\nNew spatial query features demonstrated:");
211    println!("- contains_point: Check if points exist within a circular region");
212    println!("- count_within_radius: Count points within a radius (efficient)");
213    println!("- intersects_bounds: Check if points exist within a bounding box");
214    println!("- find_within_bounds: Find all points within a rectangular region");
215    println!("- BoundingBox: Dedicated struct for bounding box operations");
216    println!("- Point containment methods for distance-based checks");
217    println!("\nPrevious features:");
218    println!("- Automatic spatial indexing of geographic points");
219    println!("- Efficient nearby point searches with distance filtering");
220    println!("- Distance calculations between any two points");
221    println!("- Multiple namespaces (world_cities, london_poi)");
222    println!("- Flexible radius-based and count-based queries");
223
224    Ok(())
225}