use crate::core::{GeoBounds, Location, TimeRange, Timestamp};
pub trait SpatialEntity {
fn location(&self) -> &Location;
fn bounds(&self) -> GeoBounds {
let loc = self.location();
GeoBounds::new(loc.lat, loc.lon, loc.lat, loc.lon)
}
fn to_geo_point(&self) -> geo_types::Point<f64> {
self.location().to_geo_point()
}
fn is_within_bounds(&self, bounds: &GeoBounds) -> bool {
bounds.contains(self.location())
}
}
pub trait TemporalEntity {
fn timestamp(&self) -> &Timestamp;
fn time_range(&self) -> TimeRange {
let ts = self.timestamp();
TimeRange::new(ts.clone(), ts.clone())
}
fn is_within_time_range(&self, range: &TimeRange) -> bool {
range.contains(self.timestamp())
}
}
#[allow(dead_code)]
pub trait SpatiotemporalEntity: SpatialEntity + TemporalEntity {
fn is_within(&self, bounds: &GeoBounds, range: &TimeRange) -> bool {
self.is_within_bounds(bounds) && self.is_within_time_range(range)
}
}
impl<T: SpatialEntity + TemporalEntity> SpatiotemporalEntity for T {}
use crate::core::Event;
impl SpatialEntity for Event {
fn location(&self) -> &Location {
&self.location
}
}
impl TemporalEntity for Event {
fn timestamp(&self) -> &Timestamp {
&self.timestamp
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_spatial_entity() {
let event = Event::builder()
.location(Location::new(40.7128, -74.0060))
.timestamp(Timestamp::now())
.text("Test")
.build();
assert_eq!(event.location().lat, 40.7128);
assert_eq!(event.location().lon, -74.0060);
}
#[test]
fn test_event_is_within_bounds() {
let event = Event::builder()
.location(Location::new(40.7128, -74.0060))
.timestamp(Timestamp::now())
.text("NYC Event")
.build();
let nyc_bounds = GeoBounds::new(40.0, -75.0, 41.0, -73.0);
let la_bounds = GeoBounds::new(33.0, -119.0, 35.0, -117.0);
assert!(event.is_within_bounds(&nyc_bounds));
assert!(!event.is_within_bounds(&la_bounds));
}
#[test]
fn test_event_temporal_entity() {
let event = Event::builder()
.location(Location::new(40.0, -74.0))
.timestamp(Timestamp::parse("2024-03-15T12:00:00Z").unwrap())
.text("Test")
.build();
let march = TimeRange::month(2024, 3);
let april = TimeRange::month(2024, 4);
assert!(event.is_within_time_range(&march));
assert!(!event.is_within_time_range(&april));
}
#[test]
fn test_event_spatiotemporal() {
let event = Event::builder()
.location(Location::new(40.7128, -74.0060))
.timestamp(Timestamp::parse("2024-03-15T12:00:00Z").unwrap())
.text("NYC in March")
.build();
let nyc_bounds = GeoBounds::new(40.0, -75.0, 41.0, -73.0);
let march = TimeRange::month(2024, 3);
let april = TimeRange::month(2024, 4);
assert!(event.is_within(&nyc_bounds, &march));
assert!(!event.is_within(&nyc_bounds, &april));
}
}