geoarrow_expr_geo/
simplify.rs1use 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}