Skip to main content

proj_core/transform/
geo_adapters.rs

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