mod distance;
mod intersects;
#[cfg(test)]
mod test_harness;
pub use distance::GeoDistancePrune;
use geo::BoundingRect;
use geo::Rect as GeoRect;
pub use intersects::GeoIntersectsPrune;
use vortex_array::VortexSessionExecute;
use vortex_array::aggregate_fn::AggregateFnVTableExt;
use vortex_array::aggregate_fn::EmptyOptions;
use vortex_array::expr::BoundExpression;
use vortex_array::expr::bound::binary;
use vortex_array::expr::bound::case_when;
use vortex_array::expr::bound::checked_add;
use vortex_array::expr::bound::ext_storage;
use vortex_array::expr::bound::get_item;
use vortex_array::expr::bound::gt;
use vortex_array::expr::bound::gt_eq;
use vortex_array::expr::bound::lit;
use vortex_array::expr::bound::lt;
use vortex_array::expr::bound::lt_eq;
use vortex_array::scalar::Scalar;
use vortex_array::scalar_fn::fns::literal::Literal;
use vortex_array::scalar_fn::fns::operators::Operator;
use vortex_array::stats::bound::stat;
use vortex_array::stats::rewrite::StatsRewriteCtx;
use vortex_error::VortexResult;
use crate::aggregate_fn::GeometryAabb;
use crate::extension::is_native_geometry;
use crate::extension::single_geometry;
fn geometry_and_constant<'a>(
expr: &'a BoundExpression,
ctx: &StatsRewriteCtx<'_>,
) -> VortexResult<Option<(&'a BoundExpression, &'a Scalar)>> {
let (lhs, rhs) = (expr.child(0), expr.child(1));
let (geom, constant) = if lhs.is_root() {
(lhs, rhs)
} else if rhs.is_root() {
(rhs, lhs)
} else {
return Ok(None);
};
if !is_native_geometry(&ctx.return_dtype(geom)?) {
return Ok(None);
}
Ok(constant.as_opt::<Literal>().map(|scalar| (geom, scalar)))
}
fn query_aabb(constant: &Scalar, ctx: &StatsRewriteCtx<'_>) -> VortexResult<Option<GeoRect<f64>>> {
if constant.is_null() {
return Ok(None);
}
let mut exec = ctx.session().create_execution_ctx();
Ok(single_geometry(constant, &mut exec)?.bounding_rect())
}
fn aabb_stat(geom: &BoundExpression) -> BoundExpression {
ext_storage(stat(geom.clone(), GeometryAabb.bind(EmptyOptions)))
}
fn min_dist_sq(aabb: &BoundExpression, query: GeoRect<f64>) -> BoundExpression {
let field = |name: &str| get_item(name, aabb.clone());
let gap = |q_lo: f64, q_hi: f64, lo: BoundExpression, hi: BoundExpression| {
maximum(
lit(0.0),
maximum(
binary(Operator::Sub, lit(q_lo), hi),
binary(Operator::Sub, lo, lit(q_hi)),
),
)
};
let dx = gap(query.min().x, query.max().x, field("xmin"), field("xmax"));
let dy = gap(query.min().y, query.max().y, field("ymin"), field("ymax"));
checked_add(square(dx), square(dy))
}
fn max_dist_sq(aabb: &BoundExpression, query: GeoRect<f64>) -> BoundExpression {
let field = |name: &str| get_item(name, aabb.clone());
let span = |q_lo: f64, q_hi: f64, lo: BoundExpression, hi: BoundExpression| {
binary(
Operator::Sub,
maximum(lit(q_hi), hi),
minimum(lit(q_lo), lo),
)
};
let dx = span(query.min().x, query.max().x, field("xmin"), field("xmax"));
let dy = span(query.min().y, query.max().y, field("ymin"), field("ymax"));
checked_add(square(dx), square(dy))
}
fn square(e: BoundExpression) -> BoundExpression {
binary(Operator::Mul, e.clone(), e)
}
fn maximum(a: BoundExpression, b: BoundExpression) -> BoundExpression {
case_when(gt(a.clone(), b.clone()), a, b)
}
fn minimum(a: BoundExpression, b: BoundExpression) -> BoundExpression {
case_when(lt(a.clone(), b.clone()), a, b)
}