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::Expression;
use vortex_array::expr::case_when;
use vortex_array::expr::checked_add;
use vortex_array::expr::ext_storage;
use vortex_array::expr::get_item;
use vortex_array::expr::gt;
use vortex_array::expr::is_root;
use vortex_array::expr::lit;
use vortex_array::expr::lt;
use vortex_array::scalar::Scalar;
use vortex_array::scalar_fn::ScalarFnVTableExt;
use vortex_array::scalar_fn::fns::binary::Binary;
use vortex_array::scalar_fn::fns::literal::Literal;
use vortex_array::scalar_fn::fns::operators::Operator;
use vortex_array::stats::rewrite::StatsRewriteCtx;
use vortex_array::stats::stat;
use vortex_error::VortexExpect;
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 Expression,
ctx: &StatsRewriteCtx<'_>,
) -> VortexResult<Option<(&'a Expression, &'a Scalar)>> {
let (lhs, rhs) = (expr.child(0), expr.child(1));
let (geom, constant) = if is_root(lhs) {
(lhs, rhs)
} else if is_root(rhs) {
(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>>> {
let mut exec = ctx.session().create_execution_ctx();
Ok(single_geometry(constant, &mut exec)?.bounding_rect())
}
fn aabb_stat(geom: &Expression) -> Expression {
ext_storage(stat(geom.clone(), GeometryAabb.bind(EmptyOptions)))
}
fn min_dist_sq(aabb: &Expression, query: GeoRect<f64>) -> Expression {
let field = |name: &str| get_item(name, aabb.clone());
let gap = |q_lo: f64, q_hi: f64, lo: Expression, hi: Expression| {
maximum(
lit(0.0),
maximum(
binop(Operator::Sub, lit(q_lo), hi),
binop(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: &Expression, query: GeoRect<f64>) -> Expression {
let field = |name: &str| get_item(name, aabb.clone());
let span = |q_lo: f64, q_hi: f64, lo: Expression, hi: Expression| {
binop(
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 binop(op: Operator, a: Expression, b: Expression) -> Expression {
Binary
.try_new_expr(op, [a, b])
.vortex_expect("binary expression")
}
fn square(e: Expression) -> Expression {
binop(Operator::Mul, e.clone(), e)
}
fn maximum(a: Expression, b: Expression) -> Expression {
case_when(gt(a.clone(), b.clone()), a, b)
}
fn minimum(a: Expression, b: Expression) -> Expression {
case_when(lt(a.clone(), b.clone()), a, b)
}