1use crate::error::{Error, GResult};
2use crate::{CoordDimensions, CoordSeq, Geometry as GGeometry};
3use geojson::{Geometry, Value};
4
5use std::convert::{TryFrom, TryInto};
6use std::iter;
7
8#[allow(clippy::needless_lifetimes)]
9fn create_coord_seq_from_vec<'a, 'b>(coords: &'a [Vec<f64>]) -> Result<CoordSeq, Error> {
10 create_coord_seq(coords.iter(), coords.len())
11}
12
13#[allow(clippy::needless_lifetimes)]
14fn create_coord_seq<'a, 'b, It>(points: It, len: usize) -> Result<CoordSeq, Error>
15where
16 It: Iterator<Item = &'a Vec<f64>>,
17{
18 let mut coord_seq =
19 CoordSeq::new(len as u32, CoordDimensions::TwoD).expect("failed to create CoordSeq");
20
21 for (i, p) in points.enumerate() {
22 coord_seq.set_x(i, p[0])?;
23 coord_seq.set_y(i, p[1])?;
24 }
25 Ok(coord_seq)
26}
27
28#[allow(clippy::needless_lifetimes)]
31fn create_closed_coord_seq_from_vec<'a, 'b>(points: &'a [Vec<f64>]) -> Result<CoordSeq, Error> {
32 let nb_points = points.len();
33 let is_closed = nb_points > 0 && points.first() == points.last();
35 let need_closing = nb_points > 0 && (!is_closed || nb_points == 3);
38 if need_closing {
39 create_coord_seq(points.iter().chain(iter::once(&points[0])), nb_points + 1)
40 } else {
41 create_coord_seq(points.iter(), nb_points)
42 }
43}
44
45impl<'a, 'b> TryFrom<&'a Geometry> for GGeometry {
46 type Error = Error;
47
48 fn try_from(other: &'a Geometry) -> Result<GGeometry, Self::Error> {
49 match other.value {
50 Value::Point(ref c) => GGeometry::create_point(create_coord_seq(iter::once(c), 1)?),
51 Value::MultiPoint(ref pts) => {
52 let ggpts = pts
53 .iter()
54 .map(|pt| GGeometry::create_point(create_coord_seq(iter::once(pt), 1)?))
55 .collect::<GResult<Vec<GGeometry>>>()?;
56 GGeometry::create_multipoint(ggpts)
57 }
58 Value::LineString(ref line) => {
59 let coord_seq = create_coord_seq_from_vec(line.as_slice())?;
60 GGeometry::create_line_string(coord_seq)
61 }
62 Value::MultiLineString(ref lines) => {
63 let gglines = lines
64 .iter()
65 .map(|line| {
66 let coord_seq = create_coord_seq_from_vec(line.as_slice())?;
67 GGeometry::create_line_string(coord_seq)
68 })
69 .collect::<GResult<Vec<GGeometry>>>()?;
70 GGeometry::create_multiline_string(gglines)
71 }
72 Value::Polygon(ref rings) => {
73 let exterior_ring = GGeometry::create_linear_ring(
74 create_closed_coord_seq_from_vec(rings[0].as_slice())?,
75 )?;
76 let interiors = rings
77 .iter()
78 .skip(1)
79 .map(|r| {
80 GGeometry::create_linear_ring(create_closed_coord_seq_from_vec(
81 r.as_slice(),
82 )?)
83 })
84 .collect::<GResult<Vec<GGeometry>>>()?;
85 GGeometry::create_polygon(exterior_ring, interiors)
86 }
87 Value::MultiPolygon(ref polygons) => {
88 let ggpolys = polygons
89 .iter()
90 .map(|rings| {
91 let exterior_ring = GGeometry::create_linear_ring(
92 create_closed_coord_seq_from_vec(rings[0].as_slice())?,
93 )?;
94 let interiors = rings
95 .iter()
96 .skip(1)
97 .map(|r| {
98 GGeometry::create_linear_ring(create_closed_coord_seq_from_vec(
99 r.as_slice(),
100 )?)
101 })
102 .collect::<GResult<Vec<GGeometry>>>()?;
103 GGeometry::create_polygon(exterior_ring, interiors)
104 })
105 .collect::<GResult<Vec<GGeometry>>>()?;
106 GGeometry::create_multipolygon(ggpolys)
107 }
108 Value::GeometryCollection(ref geoms) => {
109 let _geoms = geoms
110 .iter()
111 .map(|geom| geom.try_into())
112 .collect::<GResult<Vec<GGeometry>>>()?;
113 GGeometry::create_geometry_collection(_geoms)
114 }
115 }
116 }
117}
118
119impl TryFrom<Geometry> for GGeometry {
120 type Error = Error;
121
122 fn try_from(other: Geometry) -> Result<GGeometry, Self::Error> {
123 GGeometry::try_from(&other)
124 }
125}
126
127#[cfg(test)]
128mod test {
129 use crate::{Geom, Geometry as GGeometry};
130 use geojson::{Geometry, Value};
131
132 use std::convert::TryInto;
133
134 #[test]
135 fn geom_from_geojson_point() {
136 let geojson_pt = Geometry::new(Value::Point(vec![1., 1.]));
137 let gpoint: GGeometry = (&geojson_pt).try_into().unwrap();
138
139 assert_eq!(gpoint.to_wkt_precision(0), Ok("POINT (1 1)".to_string()));
140 let tmp: GGeometry = geojson_pt.try_into().unwrap();
142 assert_eq!(tmp.to_wkt_precision(0), Ok("POINT (1 1)".to_string()),);
143 }
144
145 #[test]
146 fn geom_from_geojson_multipoint() {
147 let geojson_pts = Geometry::new(Value::MultiPoint(vec![vec![1., 1.], vec![2., 2.]]));
148 let gpts: GGeometry = (&geojson_pts).try_into().unwrap();
149 assert_eq!(
150 gpts.to_wkt_precision(0),
151 Ok("MULTIPOINT (1 1, 2 2)".to_string()),
152 );
153 let tmp: GGeometry = geojson_pts.try_into().unwrap();
155 assert_eq!(
156 tmp.to_wkt_precision(0),
157 Ok("MULTIPOINT (1 1, 2 2)".to_string()),
158 );
159 }
160
161 #[test]
162 fn geom_from_geojson_line() {
163 let geojson_line = Geometry::new(Value::LineString(vec![vec![1., 1.], vec![2., 2.]]));
164 let gline: GGeometry = (&geojson_line).try_into().unwrap();
165 assert_eq!(
166 gline.to_wkt_precision(0),
167 Ok("LINESTRING (1 1, 2 2)".to_string()),
168 );
169 let tmp: GGeometry = geojson_line.try_into().unwrap();
171 assert_eq!(
172 tmp.to_wkt_precision(0),
173 Ok("LINESTRING (1 1, 2 2)".to_string()),
174 );
175 }
176
177 #[test]
178 fn geom_from_geojson_multiline() {
179 let geojson_lines = Geometry::new(Value::MultiLineString(vec![
180 vec![vec![1., 1.], vec![2., 2.]],
181 vec![vec![3., 3.], vec![4., 4.]],
182 ]));
183 let glines: GGeometry = (&geojson_lines).try_into().unwrap();
184 assert_eq!(
185 glines.to_wkt_precision(0),
186 Ok("MULTILINESTRING ((1 1, 2 2), (3 3, 4 4))".to_string()),
187 );
188 let tmp: GGeometry = geojson_lines.try_into().unwrap();
190 assert_eq!(
191 tmp.to_wkt_precision(0),
192 Ok("MULTILINESTRING ((1 1, 2 2), (3 3, 4 4))".to_string()),
193 );
194 }
195
196 #[test]
197 fn geom_from_geojson_polygon() {
198 let geojson_polygon = Geometry::new(Value::Polygon(vec![
199 vec![
200 vec![0., 0.],
201 vec![0., 3.],
202 vec![3., 3.],
203 vec![3., 0.],
204 vec![0., 0.],
205 ],
206 vec![
207 vec![0.2, 0.2],
208 vec![0.2, 2.],
209 vec![2., 2.],
210 vec![2., 0.2],
211 vec![0.2, 0.2],
212 ],
213 ]));
214 let gpolygon: GGeometry = (&geojson_polygon).try_into().unwrap();
215 assert_eq!(
216 gpolygon.to_wkt_precision(1),
217 Ok("POLYGON ((0.0 0.0, 0.0 3.0, 3.0 3.0, 3.0 0.0, 0.0 0.0), (0.2 0.2, 0.2 2.0, 2.0 2.0, 2.0 0.2, 0.2 0.2))"
218 .to_string()),
219 );
220 let tmp: GGeometry = geojson_polygon.try_into().unwrap();
222 assert_eq!(
223 tmp.to_wkt_precision(1),
224 Ok("POLYGON ((0.0 0.0, 0.0 3.0, 3.0 3.0, 3.0 0.0, 0.0 0.0), (0.2 0.2, 0.2 2.0, 2.0 2.0, 2.0 0.2, 0.2 0.2))"
225 .to_string()),
226 );
227 }
228
229 #[test]
230 fn geom_from_geojson_polygon_with_unclosed_interior_ring() {
231 let geojson_polygon = Geometry::new(Value::Polygon(vec![
232 vec![
233 vec![0., 0.],
234 vec![0., 3.],
235 vec![3., 3.],
236 vec![3., 0.],
237 vec![0., 0.],
238 ],
239 vec![vec![0.2, 0.2], vec![0.2, 2.], vec![2., 2.], vec![2., 0.2]],
240 ]));
241 let gpolygon: GGeometry = (&geojson_polygon).try_into().unwrap();
242 assert_eq!(
243 gpolygon.to_wkt_precision(1),
244 Ok("POLYGON ((0.0 0.0, 0.0 3.0, 3.0 3.0, 3.0 0.0, 0.0 0.0), (0.2 0.2, 0.2 2.0, 2.0 2.0, 2.0 0.2, 0.2 0.2))"
245 .to_string()),
246 );
247 let tmp: GGeometry = geojson_polygon.try_into().unwrap();
249 assert_eq!(
250 tmp.to_wkt_precision(1),
251 Ok("POLYGON ((0.0 0.0, 0.0 3.0, 3.0 3.0, 3.0 0.0, 0.0 0.0), (0.2 0.2, 0.2 2.0, 2.0 2.0, 2.0 0.2, 0.2 0.2))"
252 .to_string()),
253 );
254 }
255
256 #[test]
257 fn geom_from_geojson_multipolygon() {
258 let geojson_multipolygon = Geometry::new(Value::MultiPolygon(vec![vec![vec![
259 vec![0., 0.],
260 vec![0., 1.],
261 vec![1., 1.],
262 vec![1., 0.],
263 vec![0., 0.],
264 ]]]));
265 let gmultipolygon: GGeometry = (&geojson_multipolygon).try_into().unwrap();
266 assert_eq!(
267 gmultipolygon.to_wkt_precision(0),
268 Ok("MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)))".to_string()),
269 );
270 let tmp: GGeometry = geojson_multipolygon.try_into().unwrap();
272 assert_eq!(
273 tmp.to_wkt_precision(0),
274 Ok("MULTIPOLYGON (((0 0, 0 1, 1 1, 1 0, 0 0)))".to_string()),
275 );
276 }
277
278 #[test]
279 fn geom_from_geojson_geometry_collection() {
280 let geojson_gc = Geometry::new(Value::GeometryCollection(vec![
281 Geometry::new(Value::Point(vec![1., 1.])),
282 Geometry::new(Value::LineString(vec![vec![1., 1.], vec![2., 2.]])),
283 ]));
284 let gc: GGeometry = (&geojson_gc).try_into().unwrap();
285 assert_eq!(
286 gc.to_wkt_precision(0),
287 Ok("GEOMETRYCOLLECTION (POINT (1 1), LINESTRING (1 1, 2 2))".to_string()),
288 );
289 let tmp: GGeometry = geojson_gc.try_into().unwrap();
291 assert_eq!(
292 tmp.to_wkt_precision(0),
293 Ok("GEOMETRYCOLLECTION (POINT (1 1), LINESTRING (1 1, 2 2))".to_string()),
294 );
295 }
296}