geos/
to_geojson.rs

1use crate::error::{Error, GResult};
2use crate::{ConstGeometry, CoordSeq, Geom, Geometry as GGeometry, GeometryTypes};
3use geojson::{Geometry, Value};
4
5use std::convert::{TryFrom, TryInto};
6
7fn coords_seq_to_vec_position(cs: &CoordSeq) -> GResult<Vec<Vec<f64>>> {
8    let n_coords = cs.size()?;
9    let mut coords = Vec::with_capacity(n_coords);
10    for i in 0..n_coords {
11        coords.push(vec![cs.get_x(i)?, cs.get_y(i)?]);
12    }
13    Ok(coords)
14}
15
16macro_rules! impl_try_from_geojson {
17    ($ty_name:ident $(,$lt:lifetime)?) => (
18impl$(<$lt>)? TryFrom<$ty_name$(<$lt>)?> for Geometry {
19    type Error = Error;
20
21    fn try_from(other: $ty_name$(<$lt>)?) -> Result<Geometry, Self::Error> {
22        let _type = other.geometry_type();
23        match _type {
24            GeometryTypes::Point => {
25                let coord_seq = other.get_coord_seq()?;
26                Ok(Geometry::new(
27                    Value::Point(
28                        vec![
29                            coord_seq.get_x(0)?,
30                            coord_seq.get_y(0)?,
31                        ]
32                    )
33                ))
34            }
35            GeometryTypes::MultiPoint => {
36                let n_pts = other.get_num_geometries()?;
37                let mut coords = Vec::with_capacity(n_pts);
38                for i in 0..n_pts {
39                    let coord_seq = other.get_geometry_n(i)?.get_coord_seq()?;
40                    coords.push(vec![
41                        coord_seq.get_x(0)?,
42                        coord_seq.get_y(0)?,
43                    ]);
44                }
45                Ok(Geometry::new(Value::MultiPoint(coords)))
46            }
47            GeometryTypes::LineString | GeometryTypes::LinearRing => {
48                let cs = other.get_coord_seq()?;
49                let coords = coords_seq_to_vec_position(&cs)?;
50                Ok(Geometry::new(Value::LineString(coords)))
51            }
52            GeometryTypes::MultiLineString => {
53                let n_lines = other.get_num_geometries()?;
54                let mut result_lines = Vec::with_capacity(n_lines);
55                for i in 0..n_lines {
56                    let cs = other.get_geometry_n(i)?.get_coord_seq()?;
57                    result_lines.push(coords_seq_to_vec_position(&(cs))?);
58                }
59                Ok(Geometry::new(Value::MultiLineString(result_lines)))
60            }
61            GeometryTypes::Polygon => {
62                let nb_interiors = other.get_num_interior_rings()?;
63
64                let mut rings = Vec::with_capacity(nb_interiors + 1usize);
65                // Exterior ring to coordinates
66                rings.push(coords_seq_to_vec_position(&(
67                    other.get_exterior_ring()?.get_coord_seq()?))?);
68                // Interior rings to coordinates
69                for ix_interior in 0..nb_interiors {
70                    rings.push(coords_seq_to_vec_position(
71                        &(other.get_interior_ring_n(ix_interior as u32)?.get_coord_seq()?))?);
72                }
73                Ok(Geometry::new(Value::Polygon(rings)))
74            }
75            GeometryTypes::MultiPolygon => {
76                let n_polygs = other.get_num_geometries()?;
77                let mut result_polygs = Vec::with_capacity(n_polygs);
78                for i in 0..n_polygs {
79                    let polyg = other.get_geometry_n(i)?;
80                    let nb_interiors = polyg.get_num_interior_rings()?;
81
82                    let mut rings = Vec::with_capacity(nb_interiors + 1usize);
83                    // Exterior ring to coordinates
84                    rings.push(coords_seq_to_vec_position(&(
85                        polyg.get_exterior_ring()?.get_coord_seq()?))?);
86                    // Interior rings to coordinates
87                    for ix_interior in 0..nb_interiors {
88                        rings.push(coords_seq_to_vec_position(
89                            &(polyg.get_interior_ring_n(ix_interior as u32)?.get_coord_seq()?))?);
90                    }
91                    result_polygs.push(rings);
92                }
93                Ok(Geometry::new(Value::MultiPolygon(result_polygs)))
94            }
95            GeometryTypes::GeometryCollection => {
96                let n_geoms = other.get_num_geometries()?;
97                let mut result_geoms = Vec::with_capacity(n_geoms);
98                for i in 0..n_geoms {
99                    let g = other.get_geometry_n(i)?;
100                    let geojsongeom: Geometry = g.try_into()?;
101                    result_geoms.push(geojsongeom);
102                }
103                Ok(Geometry::new(Value::GeometryCollection(result_geoms)))
104            }
105            _ => unreachable!(),
106        }
107    }
108}
109    );
110}
111
112impl_try_from_geojson!(GGeometry);
113impl_try_from_geojson!(ConstGeometry, 'c);
114
115#[cfg(test)]
116mod test {
117    use crate::Geometry as GGeometry;
118    use geojson::{Geometry, Value};
119
120    use std::convert::TryInto;
121
122    #[test]
123    fn geom_to_geojson_point() {
124        let pt = "POINT(1 1)";
125        let pt = GGeometry::new_from_wkt(pt).unwrap();
126
127        let geojson_pt: Geometry = pt.try_into().unwrap();
128
129        let expected_pt = Geometry::new(Value::Point(vec![1., 1.]));
130        assert_eq!(geojson_pt, expected_pt);
131    }
132
133    #[test]
134    fn geom_to_geojson_multipoint() {
135        let pts = "MULTIPOINT((1 1), (2 2))";
136        let pts = GGeometry::new_from_wkt(pts).unwrap();
137
138        let geojson_pts: Geometry = pts.try_into().unwrap();
139
140        let expected_pts = Geometry::new(Value::MultiPoint(vec![vec![1., 1.], vec![2., 2.]]));
141        assert_eq!(geojson_pts, expected_pts);
142    }
143
144    #[test]
145    fn geom_to_geojson_line() {
146        let line = "LINESTRING(1 1, 2 2)";
147        let line = GGeometry::new_from_wkt(line).unwrap();
148
149        let geojson_line: Geometry = line.try_into().unwrap();
150
151        let expected_line = Geometry::new(Value::LineString(vec![vec![1., 1.], vec![2., 2.]]));
152        assert_eq!(geojson_line, expected_line);
153    }
154
155    #[test]
156    fn geom_to_geojson_linearring() {
157        let line = "LINEARRING(1 1, 2 1, 2 2, 1 1)";
158        let line = GGeometry::new_from_wkt(line).unwrap();
159
160        let geojson_line: Geometry = line.try_into().unwrap();
161
162        let expected_line = Geometry::new(Value::LineString(vec![
163            vec![1., 1.],
164            vec![2., 1.],
165            vec![2., 2.],
166            vec![1., 1.],
167        ]));
168        assert_eq!(geojson_line, expected_line);
169    }
170
171    #[test]
172    fn geom_to_geojson_multiline() {
173        let line = "MULTILINESTRING((1 1, 2 2), (3 3, 4 4))";
174        let line = GGeometry::new_from_wkt(line).unwrap();
175
176        let geojson_line: Geometry = line.try_into().unwrap();
177
178        let expected_line = Geometry::new(Value::MultiLineString(vec![
179            vec![vec![1., 1.], vec![2., 2.]],
180            vec![vec![3., 3.], vec![4., 4.]],
181        ]));
182        assert_eq!(geojson_line, expected_line);
183    }
184
185    #[test]
186    fn geom_to_geojson_polygon() {
187        let poly = "POLYGON((0 0, 0 3, 3 3, 3 0, 0 0) ,(0.2 0.2, 0.2 2, 2 2, 2 0.2, 0.2 0.2))";
188        let poly = GGeometry::new_from_wkt(poly).unwrap();
189
190        let geojson_polygon: Geometry = poly.try_into().unwrap();
191
192        let expected_polygon = Geometry::new(Value::Polygon(vec![
193            vec![
194                vec![0., 0.],
195                vec![0., 3.],
196                vec![3., 3.],
197                vec![3., 0.],
198                vec![0., 0.],
199            ],
200            vec![
201                vec![0.2, 0.2],
202                vec![0.2, 2.],
203                vec![2., 2.],
204                vec![2., 0.2],
205                vec![0.2, 0.2],
206            ],
207        ]));
208        assert_eq!(geojson_polygon, expected_polygon);
209    }
210
211    #[test]
212    fn geom_to_geojson_multipolygon() {
213        let poly = "MULTIPOLYGON(((0 0, 0 1, 1 1, 1 0, 0 0)))";
214        let poly = GGeometry::new_from_wkt(poly).unwrap();
215
216        let geojson_polygon: Geometry = poly.try_into().unwrap();
217
218        let expected_polygon = Geometry::new(Value::MultiPolygon(vec![vec![vec![
219            vec![0., 0.],
220            vec![0., 1.],
221            vec![1., 1.],
222            vec![1., 0.],
223            vec![0., 0.],
224        ]]]));
225        assert_eq!(geojson_polygon, expected_polygon);
226    }
227
228    #[test]
229    fn geom_to_geojson_geometry_collection() {
230        let gc = "GEOMETRYCOLLECTION(POINT(1 1), LINESTRING(1 1, 2 2))";
231        let gc = GGeometry::new_from_wkt(gc).unwrap();
232
233        let geojson_gc: Geometry = gc.try_into().unwrap();
234
235        let expected_gc = Geometry::new(Value::GeometryCollection(vec![
236            Geometry::new(Value::Point(vec![1., 1.])),
237            Geometry::new(Value::LineString(vec![vec![1., 1.], vec![2., 2.]])),
238        ]));
239        assert_eq!(geojson_gc, expected_gc);
240    }
241}