1use arrow_array::BooleanArray;
2use geo::intersects::Intersects;
3use geoarrow_array::{GeoArrowArray, GeoArrowArrayAccessor};
4use geoarrow_schema::error::{GeoArrowError, GeoArrowResult};
5
6use crate::util::downcast::downcast_geoarrow_array_two_args;
7use crate::util::to_geo::geometry_to_geo;
8
9pub fn intersects(
10 left_array: &dyn GeoArrowArray,
11 right_array: &dyn GeoArrowArray,
12) -> GeoArrowResult<BooleanArray> {
13 if left_array.len() != right_array.len() {
14 Err(GeoArrowError::InvalidGeoArrow(
15 "Input arrays must have the same length".to_string(),
16 ))
17 } else {
18 downcast_geoarrow_array_two_args!(left_array, right_array, _intersects_impl)
19 }
20}
21
22fn _intersects_impl<'a>(
23 left_array: &'a impl GeoArrowArrayAccessor<'a>,
24 right_array: &'a impl GeoArrowArrayAccessor<'a>,
25) -> GeoArrowResult<BooleanArray> {
26 let mut builder = BooleanArray::builder(left_array.len());
27
28 for (maybe_left, maybe_right) in left_array.iter().zip(right_array.iter()) {
29 match (maybe_left, maybe_right) {
30 (Some(left), Some(right)) => {
31 let left_geom = geometry_to_geo(&left?)?;
32 let right_geom = geometry_to_geo(&right?)?;
33 let intersects = left_geom.intersects(&right_geom);
34 builder.append_value(intersects);
35 }
36 _ => {
37 builder.append_null();
39 }
40 }
41 }
42
43 Ok(builder.finish())
44}
45
46#[cfg(test)]
47mod tests {
48 use geo::{Geometry, line_string, polygon};
49 use geoarrow_array::builder::GeometryBuilder;
50 use geoarrow_schema::{CoordType, GeometryType};
51
52 use super::*;
53
54 #[test]
55 fn test_intersects() {
56 let test_pairs = [
58 vec![
60 Some(Geometry::from(polygon![
61 (x: 1.0, y: 1.0),
62 (x: 2.0, y: 1.0),
63 (x: 2.0, y: 2.0),
64 (x: 1.0, y: 2.0)
65 ])),
66 Some(Geometry::from(polygon![
67 (x: 1.5, y: 1.5),
68 (x: 2.5, y: 1.5),
69 (x: 2.5, y: 2.5),
70 (x: 1.5, y: 2.5)
71 ])),
72 ],
73 vec![
75 Some(Geometry::from(polygon![
76 (x: 1.0, y: 1.0),
77 (x: 2.0, y: 1.0),
78 (x: 2.0, y: 2.0),
79 (x: 1.0, y: 2.0)
80 ])),
81 Some(Geometry::from(polygon![
82 (x: 3.0, y: 3.0),
83 (x: 4.0, y: 3.0),
84 (x: 4.0, y: 4.0),
85 (x: 3.0, y: 4.0)
86 ])),
87 ],
88 vec![
90 Some(Geometry::from(polygon![
91 (x: 2.0, y: 2.0),
92 (x: 3.0, y: 2.0),
93 (x: 3.0, y: 3.0),
94 (x: 2.0, y: 3.0)
95 ])),
96 Some(Geometry::from(polygon![
97 (x: 3.0, y: 3.0),
98 (x: 4.0, y: 3.0),
99 (x: 4.0, y: 4.0),
100 (x: 3.0, y: 4.0)
101 ])),
102 ],
103 vec![
105 Some(Geometry::from(line_string! [
106 (x: 1.0, y: 1.0),
107 (x: 2.0, y: 2.0)
108 ])),
109 Some(Geometry::from(polygon![
110 (x: 1.5, y: 1.5),
111 (x: 2.5, y: 1.5),
112 (x: 2.5, y: 2.5),
113 (x: 1.5, y: 2.5)
114 ])),
115 ],
116 vec![None, None],
118 ];
119
120 let geoms_left: Vec<_> = test_pairs.iter().map(|pair| pair[0].clone()).collect();
121 let geoms_right: Vec<_> = test_pairs.iter().map(|pair| pair[1].clone()).collect();
122
123 let typ = GeometryType::new(Default::default()).with_coord_type(CoordType::Interleaved);
124 let left_array = GeometryBuilder::from_nullable_geometries(&geoms_left, typ.clone())
125 .unwrap()
126 .finish();
127 let right_array = GeometryBuilder::from_nullable_geometries(&geoms_right, typ)
128 .unwrap()
129 .finish();
130
131 let result = intersects(&left_array, &right_array).unwrap();
132
133 let expected =
134 BooleanArray::from(vec![Some(true), Some(false), Some(true), Some(true), None]);
135
136 assert_eq!(result, expected);
137 }
138
139 #[test]
140 #[should_panic(expected = "Input arrays must have the same length")]
141 fn test_intersects_length_mismatch() {
142 let left_geom = vec![Some(Geometry::from(
143 polygon![(x: 0.0, y: 0.0), (x: 1.0, y: 0.0), (x: 1.0, y: 1.0), (x: 0.0, y: 1.0)],
144 ))];
145 let right_geom: Vec<Option<Geometry>> = vec![];
146
147 let typ = GeometryType::new(Default::default()).with_coord_type(CoordType::Interleaved);
148 let left_array = GeometryBuilder::from_nullable_geometries(&left_geom, typ.clone())
149 .unwrap()
150 .finish();
151 let right_array = GeometryBuilder::from_nullable_geometries(&right_geom, typ)
152 .unwrap()
153 .finish();
154
155 intersects(&left_array, &right_array).unwrap();
156 }
157
158 #[test]
159 fn test_intersects_empty_arrays() {
160 let typ = GeometryType::new(Default::default()).with_coord_type(CoordType::Interleaved);
161 let left_array =
162 GeometryBuilder::from_nullable_geometries(&Vec::<Option<Geometry>>::new(), typ.clone())
163 .unwrap()
164 .finish();
165 let right_array =
166 GeometryBuilder::from_nullable_geometries(&Vec::<Option<Geometry>>::new(), typ)
167 .unwrap()
168 .finish();
169
170 let result = intersects(&left_array, &right_array).unwrap();
171 assert_eq!(result.len(), 0);
172 }
173}