spatial_narrative/core/
traits.rs1use crate::core::{GeoBounds, Location, TimeRange, Timestamp};
4
5pub trait SpatialEntity {
10 fn location(&self) -> &Location;
12
13 fn bounds(&self) -> GeoBounds {
19 let loc = self.location();
20 GeoBounds::new(loc.lat, loc.lon, loc.lat, loc.lon)
21 }
22
23 fn to_geo_point(&self) -> geo_types::Point<f64> {
25 self.location().to_geo_point()
26 }
27
28 fn is_within_bounds(&self, bounds: &GeoBounds) -> bool {
30 bounds.contains(self.location())
31 }
32}
33
34pub trait TemporalEntity {
39 fn timestamp(&self) -> &Timestamp;
41
42 fn time_range(&self) -> TimeRange {
48 let ts = self.timestamp();
49 TimeRange::new(ts.clone(), ts.clone())
50 }
51
52 fn is_within_time_range(&self, range: &TimeRange) -> bool {
54 range.contains(self.timestamp())
55 }
56}
57
58#[allow(dead_code)]
63pub trait SpatiotemporalEntity: SpatialEntity + TemporalEntity {
64 fn is_within(&self, bounds: &GeoBounds, range: &TimeRange) -> bool {
66 self.is_within_bounds(bounds) && self.is_within_time_range(range)
67 }
68}
69
70impl<T: SpatialEntity + TemporalEntity> SpatiotemporalEntity for T {}
72
73use crate::core::Event;
75
76impl SpatialEntity for Event {
77 fn location(&self) -> &Location {
78 &self.location
79 }
80}
81
82impl TemporalEntity for Event {
83 fn timestamp(&self) -> &Timestamp {
84 &self.timestamp
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_event_spatial_entity() {
94 let event = Event::builder()
95 .location(Location::new(40.7128, -74.0060))
96 .timestamp(Timestamp::now())
97 .text("Test")
98 .build();
99
100 assert_eq!(event.location().lat, 40.7128);
101 assert_eq!(event.location().lon, -74.0060);
102 }
103
104 #[test]
105 fn test_event_is_within_bounds() {
106 let event = Event::builder()
107 .location(Location::new(40.7128, -74.0060))
108 .timestamp(Timestamp::now())
109 .text("NYC Event")
110 .build();
111
112 let nyc_bounds = GeoBounds::new(40.0, -75.0, 41.0, -73.0);
113 let la_bounds = GeoBounds::new(33.0, -119.0, 35.0, -117.0);
114
115 assert!(event.is_within_bounds(&nyc_bounds));
116 assert!(!event.is_within_bounds(&la_bounds));
117 }
118
119 #[test]
120 fn test_event_temporal_entity() {
121 let event = Event::builder()
122 .location(Location::new(40.0, -74.0))
123 .timestamp(Timestamp::parse("2024-03-15T12:00:00Z").unwrap())
124 .text("Test")
125 .build();
126
127 let march = TimeRange::month(2024, 3);
128 let april = TimeRange::month(2024, 4);
129
130 assert!(event.is_within_time_range(&march));
131 assert!(!event.is_within_time_range(&april));
132 }
133
134 #[test]
135 fn test_event_spatiotemporal() {
136 let event = Event::builder()
137 .location(Location::new(40.7128, -74.0060))
138 .timestamp(Timestamp::parse("2024-03-15T12:00:00Z").unwrap())
139 .text("NYC in March")
140 .build();
141
142 let nyc_bounds = GeoBounds::new(40.0, -75.0, 41.0, -73.0);
143 let march = TimeRange::month(2024, 3);
144 let april = TimeRange::month(2024, 4);
145
146 assert!(event.is_within(&nyc_bounds, &march));
147 assert!(!event.is_within(&nyc_bounds, &april));
148 }
149}