use super::node::BBox;
use crate::types::domain::DomainBound;
pub fn lt_bound(a: &DomainBound, b: &DomainBound) -> bool {
a.partial_cmp(b)
.is_some_and(|o| o == std::cmp::Ordering::Less)
}
fn le_bound(a: &DomainBound, b: &DomainBound) -> bool {
a.partial_cmp(b)
.is_some_and(|o| o != std::cmp::Ordering::Greater)
}
#[derive(Debug, Clone, Default)]
pub struct MbrQueryPredicate {
pub per_dim: Vec<DimPredicate>,
}
#[derive(Debug, Clone, Default)]
pub struct DimPredicate {
pub lo: Option<DomainBound>,
pub hi: Option<DomainBound>,
}
impl MbrQueryPredicate {
pub fn new(per_dim: Vec<DimPredicate>) -> Self {
Self { per_dim }
}
pub fn intersects(&self, bbox: &BBox) -> bool {
for (i, dp) in self.per_dim.iter().enumerate() {
if i >= bbox.arity() {
break;
}
if let Some(lo) = &dp.lo
&& lt_bound(&bbox.max[i], lo)
{
return false;
}
if let Some(hi) = &dp.hi
&& lt_bound(hi, &bbox.min[i])
{
return false;
}
let _ = le_bound; }
true
}
}
#[cfg(test)]
mod tests {
use super::*;
fn b(min: i64, max: i64) -> BBox {
BBox {
min: vec![DomainBound::Int64(min)],
max: vec![DomainBound::Int64(max)],
}
}
fn pred(lo: Option<i64>, hi: Option<i64>) -> MbrQueryPredicate {
MbrQueryPredicate::new(vec![DimPredicate {
lo: lo.map(DomainBound::Int64),
hi: hi.map(DomainBound::Int64),
}])
}
#[test]
fn fully_inside_intersects() {
assert!(pred(Some(2), Some(8)).intersects(&b(0, 10)));
}
#[test]
fn fully_outside_left() {
assert!(!pred(Some(20), Some(30)).intersects(&b(0, 10)));
}
#[test]
fn fully_outside_right() {
assert!(!pred(Some(-10), Some(-5)).intersects(&b(0, 10)));
}
#[test]
fn touching_intersects() {
assert!(pred(Some(10), Some(20)).intersects(&b(0, 10)));
}
#[test]
fn unbounded_intersects() {
assert!(pred(None, None).intersects(&b(5, 7)));
}
}