geoarrow_expr_geo/
simplify.rs

1use std::sync::Arc;
2
3use geo::Simplify;
4use geo_traits::to_geo::{ToGeoLineString, ToGeoMultiLineString, ToGeoMultiPolygon, ToGeoPolygon};
5use geoarrow_array::array::{
6    LineStringArray, MultiLineStringArray, MultiPolygonArray, PolygonArray,
7};
8use geoarrow_array::builder::{
9    GeometryBuilder, LineStringBuilder, MultiLineStringBuilder, MultiPolygonBuilder, PolygonBuilder,
10};
11use geoarrow_array::cast::AsGeoArrowArray;
12use geoarrow_array::{GeoArrowArray, GeoArrowArrayAccessor, IntoArrow, downcast_geoarrow_array};
13use geoarrow_schema::error::GeoArrowResult;
14use geoarrow_schema::{GeoArrowType, GeometryType};
15
16use crate::util::copy_geoarrow_array_ref;
17use crate::util::to_geo::geometry_to_geo;
18
19pub fn simplify(array: &dyn GeoArrowArray, epsilon: f64) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
20    use GeoArrowType::*;
21    match array.data_type() {
22        Point(_) | MultiPoint(_) | GeometryCollection(_) | Rect(_) => {
23            Ok(copy_geoarrow_array_ref(array))
24        }
25        LineString(_) => simplify_linestring(array.as_line_string(), epsilon),
26        Polygon(_) => simplify_polygon(array.as_polygon(), epsilon),
27        MultiLineString(_) => simplify_multi_linestring(array.as_multi_line_string(), epsilon),
28        MultiPolygon(_) => simplify_multi_polygon(array.as_multi_polygon(), epsilon),
29        _ => downcast_geoarrow_array!(array, simplify_geometry_impl, epsilon),
30    }
31}
32
33fn simplify_linestring(
34    array: &LineStringArray,
35    epsilon: f64,
36) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
37    let mut builder = LineStringBuilder::new(array.extension_type().clone());
38
39    for item in array.iter() {
40        if let Some(geom) = item {
41            let geo_geom = geom?.to_line_string();
42            builder.push_line_string(Some(&geo_geom.simplify(epsilon)))?;
43        } else {
44            builder.push_line_string(None::<&geo::LineString>.as_ref())?;
45        }
46    }
47
48    Ok(Arc::new(builder.finish()))
49}
50
51fn simplify_polygon(array: &PolygonArray, epsilon: f64) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
52    let mut builder = PolygonBuilder::new(array.extension_type().clone());
53
54    for item in array.iter() {
55        if let Some(geom) = item {
56            let geo_geom = geom?.to_polygon();
57            builder.push_polygon(Some(&geo_geom.simplify(epsilon)))?;
58        } else {
59            builder.push_polygon(None::<&geo::Polygon>.as_ref())?;
60        }
61    }
62
63    Ok(Arc::new(builder.finish()))
64}
65
66fn simplify_multi_linestring(
67    array: &MultiLineStringArray,
68    epsilon: f64,
69) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
70    let mut builder = MultiLineStringBuilder::new(array.extension_type().clone());
71
72    for item in array.iter() {
73        if let Some(geom) = item {
74            let geo_geom = geom?.to_multi_line_string();
75            builder.push_multi_line_string(Some(&geo_geom.simplify(epsilon)))?;
76        } else {
77            builder.push_multi_line_string(None::<&geo::MultiLineString>.as_ref())?;
78        }
79    }
80
81    Ok(Arc::new(builder.finish()))
82}
83
84fn simplify_multi_polygon(
85    array: &MultiPolygonArray,
86    epsilon: f64,
87) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
88    let mut builder = MultiPolygonBuilder::new(array.extension_type().clone());
89
90    for item in array.iter() {
91        if let Some(geom) = item {
92            let geo_geom = geom?.to_multi_polygon();
93            builder.push_multi_polygon(Some(&geo_geom.simplify(epsilon)))?;
94        } else {
95            builder.push_multi_polygon(None::<&geo::MultiPolygon>.as_ref())?;
96        }
97    }
98
99    Ok(Arc::new(builder.finish()))
100}
101
102fn simplify_geometry_impl<'a>(
103    array: &'a impl GeoArrowArrayAccessor<'a>,
104    epsilon: f64,
105) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
106    let geom_typ = GeometryType::new(array.data_type().metadata().clone());
107    let mut builder = GeometryBuilder::new(geom_typ);
108
109    for item in array.iter() {
110        if let Some(geom) = item {
111            let geo_geom = geometry_to_geo(&geom?)?;
112            let simplified_geom = simplify_geometry(&geo_geom, epsilon);
113            builder.push_geometry(Some(&simplified_geom))?;
114        } else {
115            builder.push_geometry(None::<&geo::Geometry>.as_ref())?;
116        }
117    }
118
119    Ok(Arc::new(builder.finish()))
120}
121
122fn simplify_geometry(geom: &geo::Geometry, epsilon: f64) -> geo::Geometry {
123    match geom {
124        geo::Geometry::LineString(g) => geo::Geometry::LineString(g.simplify(epsilon)),
125        geo::Geometry::Polygon(g) => geo::Geometry::Polygon(g.simplify(epsilon)),
126        geo::Geometry::MultiLineString(g) => geo::Geometry::MultiLineString(g.simplify(epsilon)),
127        geo::Geometry::MultiPolygon(g) => geo::Geometry::MultiPolygon(g.simplify(epsilon)),
128        _ => geom.clone(),
129    }
130}