Skip to main content

proj_core/transform/
geo_adapters.rs

1use super::{Transform, TransformableGeometry};
2use crate::coord::Bounds;
3use crate::error::Result;
4
5#[cfg(feature = "geo-types")]
6pub(super) const DEFAULT_GEO_TYPES_RECT_DENSIFY_POINTS: usize = 21;
7
8#[cfg(feature = "geo-types")]
9fn transform_geo_coord(
10    transform: &Transform,
11    coord: geo_types::Coord<f64>,
12) -> Result<geo_types::Coord<f64>> {
13    transform.convert(coord)
14}
15
16#[cfg(feature = "geo-types")]
17fn transform_geo_coords(
18    transform: &Transform,
19    coords: Vec<geo_types::Coord<f64>>,
20) -> Result<Vec<geo_types::Coord<f64>>> {
21    coords
22        .into_iter()
23        .map(|coord| transform_geo_coord(transform, coord))
24        .collect()
25}
26
27#[cfg(feature = "geo-types")]
28pub(super) fn transform_geo_rect_with_densification(
29    transform: &Transform,
30    rect: geo_types::Rect<f64>,
31    densify_points: usize,
32) -> Result<geo_types::Rect<f64>> {
33    let min = rect.min();
34    let max = rect.max();
35    let transformed =
36        transform.transform_bounds(Bounds::new(min.x, min.y, max.x, max.y), densify_points)?;
37
38    Ok(geo_types::Rect::new(
39        geo_types::Coord {
40            x: transformed.min_x,
41            y: transformed.min_y,
42        },
43        geo_types::Coord {
44            x: transformed.max_x,
45            y: transformed.max_y,
46        },
47    ))
48}
49
50#[cfg(feature = "geo-types")]
51fn transform_geo_rect(
52    transform: &Transform,
53    rect: geo_types::Rect<f64>,
54) -> Result<geo_types::Rect<f64>> {
55    transform_geo_rect_with_densification(transform, rect, DEFAULT_GEO_TYPES_RECT_DENSIFY_POINTS)
56}
57
58#[cfg(feature = "geo-types")]
59impl TransformableGeometry for geo_types::Coord<f64> {
60    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
61        transform_geo_coord(transform, self)
62    }
63}
64
65#[cfg(feature = "geo-types")]
66impl TransformableGeometry for geo_types::Point<f64> {
67    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
68        Ok(geo_types::Point::from(transform_geo_coord(
69            transform, self.0,
70        )?))
71    }
72}
73
74#[cfg(feature = "geo-types")]
75impl TransformableGeometry for geo_types::Line<f64> {
76    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
77        Ok(geo_types::Line::new(
78            transform_geo_coord(transform, self.start)?,
79            transform_geo_coord(transform, self.end)?,
80        ))
81    }
82}
83
84#[cfg(feature = "geo-types")]
85impl TransformableGeometry for geo_types::LineString<f64> {
86    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
87        Ok(geo_types::LineString::new(transform_geo_coords(
88            transform,
89            self.into_inner(),
90        )?))
91    }
92}
93
94#[cfg(feature = "geo-types")]
95impl TransformableGeometry for geo_types::Polygon<f64> {
96    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
97        let (exterior, interiors) = self.into_inner();
98        let exterior = exterior.transform_geometry(transform)?;
99        let interiors = interiors
100            .into_iter()
101            .map(|ring| ring.transform_geometry(transform))
102            .collect::<Result<Vec<_>>>()?;
103        Ok(geo_types::Polygon::new(exterior, interiors))
104    }
105}
106
107#[cfg(feature = "geo-types")]
108impl TransformableGeometry for geo_types::MultiPoint<f64> {
109    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
110        Ok(geo_types::MultiPoint(
111            self.0
112                .into_iter()
113                .map(|point| point.transform_geometry(transform))
114                .collect::<Result<Vec<_>>>()?,
115        ))
116    }
117}
118
119#[cfg(feature = "geo-types")]
120impl TransformableGeometry for geo_types::MultiLineString<f64> {
121    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
122        Ok(geo_types::MultiLineString(
123            self.0
124                .into_iter()
125                .map(|line| line.transform_geometry(transform))
126                .collect::<Result<Vec<_>>>()?,
127        ))
128    }
129}
130
131#[cfg(feature = "geo-types")]
132impl TransformableGeometry for geo_types::MultiPolygon<f64> {
133    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
134        Ok(geo_types::MultiPolygon(
135            self.0
136                .into_iter()
137                .map(|polygon| polygon.transform_geometry(transform))
138                .collect::<Result<Vec<_>>>()?,
139        ))
140    }
141}
142
143#[cfg(feature = "geo-types")]
144impl TransformableGeometry for geo_types::GeometryCollection<f64> {
145    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
146        Ok(geo_types::GeometryCollection(
147            self.0
148                .into_iter()
149                .map(|geometry| geometry.transform_geometry(transform))
150                .collect::<Result<Vec<_>>>()?,
151        ))
152    }
153}
154
155#[cfg(feature = "geo-types")]
156impl TransformableGeometry for geo_types::Rect<f64> {
157    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
158        transform_geo_rect(transform, self)
159    }
160}
161
162#[cfg(feature = "geo-types")]
163impl TransformableGeometry for geo_types::Triangle<f64> {
164    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
165        let [v1, v2, v3] = self.to_array();
166        Ok(geo_types::Triangle(
167            transform_geo_coord(transform, v1)?,
168            transform_geo_coord(transform, v2)?,
169            transform_geo_coord(transform, v3)?,
170        ))
171    }
172}
173
174#[cfg(feature = "geo-types")]
175impl TransformableGeometry for geo_types::Geometry<f64> {
176    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
177        Ok(match self {
178            geo_types::Geometry::Point(geometry) => {
179                geo_types::Geometry::Point(geometry.transform_geometry(transform)?)
180            }
181            geo_types::Geometry::Line(geometry) => {
182                geo_types::Geometry::Line(geometry.transform_geometry(transform)?)
183            }
184            geo_types::Geometry::LineString(geometry) => {
185                geo_types::Geometry::LineString(geometry.transform_geometry(transform)?)
186            }
187            geo_types::Geometry::Polygon(geometry) => {
188                geo_types::Geometry::Polygon(geometry.transform_geometry(transform)?)
189            }
190            geo_types::Geometry::MultiPoint(geometry) => {
191                geo_types::Geometry::MultiPoint(geometry.transform_geometry(transform)?)
192            }
193            geo_types::Geometry::MultiLineString(geometry) => {
194                geo_types::Geometry::MultiLineString(geometry.transform_geometry(transform)?)
195            }
196            geo_types::Geometry::MultiPolygon(geometry) => {
197                geo_types::Geometry::MultiPolygon(geometry.transform_geometry(transform)?)
198            }
199            geo_types::Geometry::GeometryCollection(geometry) => {
200                geo_types::Geometry::GeometryCollection(geometry.transform_geometry(transform)?)
201            }
202            geo_types::Geometry::Rect(geometry) => {
203                geo_types::Geometry::Rect(geometry.transform_geometry(transform)?)
204            }
205            geo_types::Geometry::Triangle(geometry) => {
206                geo_types::Geometry::Triangle(geometry.transform_geometry(transform)?)
207            }
208        })
209    }
210}