Skip to main content

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}