oxirs_tdb/index/spatial/mod.rs
1//! Geospatial indexing for RDF triple stores
2//!
3//! Provides GeoSPARQL-compatible spatial indexing using R*-tree data structure.
4//! Supports efficient querying of spatial relationships:
5//! - Distance queries (within radius)
6//! - Containment queries (point in polygon)
7//! - Intersection queries (bounding box overlaps)
8//! - Nearest neighbor queries
9//!
10//! ## Features
11//!
12//! - **R*-tree index** - Optimized spatial index with low false positive rate
13//! - **GeoSPARQL support** - Standard geospatial query language
14//! - **WKT parsing** - Well-Known Text geometry format
15//! - **GeoJSON support** - JSON-based geometry encoding
16//! - **Efficient range queries** - O(log n) spatial lookups
17//!
18//! ## Example
19//!
20//! ```rust,ignore
21//! use oxirs_tdb::index::spatial::{SpatialIndex, Point, BoundingBox};
22//! use oxirs_tdb::dictionary::NodeId;
23//!
24//! let mut index = SpatialIndex::new();
25//!
26//! // Index a point
27//! let point = Point::new(40.7128, -74.0060); // New York City
28//! let node_id = NodeId::new(1);
29//! index.insert(node_id, point.into());
30//!
31//! // Query nearby points (within 10km)
32//! let center = Point::new(40.7589, -73.9851); // Times Square
33//! let radius_meters = 10_000.0;
34//! let nearby = index.within_distance(center, radius_meters);
35//! ```
36
37pub mod functions;
38pub mod geometry;
39pub mod rtree;
40
41pub use functions::*;
42pub use geometry::{BoundingBox, Geometry, LineString, Point, Polygon};
43pub use rtree::SpatialIndex;
44
45use crate::dictionary::NodeId;
46use crate::error::{Result, TdbError};
47use serde::{Deserialize, Serialize};
48
49/// Spatial query types
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub enum SpatialQuery {
52 /// Find all geometries within distance of a point
53 WithinDistance {
54 /// Center point
55 center: Point,
56 /// Distance in meters
57 distance: f64,
58 },
59 /// Find all geometries intersecting a bounding box
60 IntersectsBBox {
61 /// Bounding box
62 bbox: BoundingBox,
63 },
64 /// Find geometries containing a point
65 Contains {
66 /// Point to test
67 point: Point,
68 },
69 /// K nearest neighbors
70 KNearestNeighbors {
71 /// Query point
72 point: Point,
73 /// Number of neighbors
74 k: usize,
75 },
76}
77
78/// Spatial query result
79#[derive(Debug, Clone)]
80pub struct SpatialQueryResult {
81 /// Node ID of the matching geometry
82 pub node_id: NodeId,
83 /// Geometry
84 pub geometry: Geometry,
85 /// Distance from query point (if applicable)
86 pub distance: Option<f64>,
87}
88
89/// Spatial index statistics
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct SpatialStats {
92 /// Total geometries indexed
93 pub geometry_count: usize,
94 /// Points count
95 pub points_count: usize,
96 /// Polygons count
97 pub polygons_count: usize,
98 /// LineStrings count
99 pub linestrings_count: usize,
100 /// R-tree depth
101 pub rtree_depth: usize,
102 /// R-tree node count
103 pub rtree_node_count: usize,
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn test_spatial_module_exports() {
112 // Test that all exports are accessible
113 let _point = Point::new(0.0, 0.0);
114 let _bbox = BoundingBox::new(0.0, 0.0, 1.0, 1.0);
115 let _index = SpatialIndex::new();
116 }
117
118 #[test]
119 fn test_spatial_query_types() {
120 let query = SpatialQuery::WithinDistance {
121 center: Point::new(40.7128, -74.0060),
122 distance: 1000.0,
123 };
124 assert!(matches!(query, SpatialQuery::WithinDistance { .. }));
125
126 let query2 = SpatialQuery::IntersectsBBox {
127 bbox: BoundingBox::new(0.0, 0.0, 1.0, 1.0),
128 };
129 assert!(matches!(query2, SpatialQuery::IntersectsBBox { .. }));
130 }
131
132 #[test]
133 fn test_spatial_stats_creation() {
134 let stats = SpatialStats {
135 geometry_count: 100,
136 points_count: 60,
137 polygons_count: 30,
138 linestrings_count: 10,
139 rtree_depth: 4,
140 rtree_node_count: 25,
141 };
142
143 assert_eq!(stats.geometry_count, 100);
144 assert_eq!(stats.rtree_depth, 4);
145 }
146}