geoarrow_expr_geo/
relate.rs

1use arrow_array::BooleanArray;
2use geo::Relate;
3use geo::relate::IntersectionMatrix;
4use geoarrow_array::{GeoArrowArray, GeoArrowArrayAccessor};
5use geoarrow_schema::error::{GeoArrowError, GeoArrowResult};
6
7use crate::util::downcast::downcast_geoarrow_array_two_args;
8use crate::util::to_geo::geometry_to_geo;
9
10pub fn relate_boolean(
11    left_array: &dyn GeoArrowArray,
12    right_array: &dyn GeoArrowArray,
13    relate_cb: impl Fn(IntersectionMatrix) -> bool,
14) -> GeoArrowResult<BooleanArray> {
15    if left_array.len() != right_array.len() {
16        Err(GeoArrowError::InvalidGeoArrow(
17            "Input arrays must have the same length".to_string(),
18        ))
19    } else {
20        downcast_geoarrow_array_two_args!(left_array, right_array, _relate_impl, relate_cb)
21    }
22}
23
24fn _relate_impl<'a>(
25    left_array: &'a impl GeoArrowArrayAccessor<'a>,
26    right_array: &'a impl GeoArrowArrayAccessor<'a>,
27    relate_cb: impl Fn(IntersectionMatrix) -> bool,
28) -> GeoArrowResult<BooleanArray> {
29    let mut builder = BooleanArray::builder(left_array.len());
30
31    for (maybe_left, maybe_right) in left_array.iter().zip(right_array.iter()) {
32        match (maybe_left, maybe_right) {
33            (Some(left), Some(right)) => {
34                let left_geom = geometry_to_geo(&left?)?;
35                let right_geom = geometry_to_geo(&right?)?;
36                let matrix = left_geom.relate(&right_geom);
37                builder.append_value(relate_cb(matrix));
38            }
39            _ => {
40                // If either is null, the result is null
41                builder.append_null();
42            }
43        }
44    }
45
46    Ok(builder.finish())
47}