geojson/conversion/
to_geo_types.rs

1use geo_types::{self, CoordFloat};
2
3use crate::geometry;
4
5use crate::{Error, Result};
6use crate::{Feature, FeatureCollection, GeoJson, LineStringType, PointType, PolygonType};
7use std::convert::{TryFrom, TryInto};
8
9#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
10impl<T> TryFrom<&geometry::Value> for geo_types::Point<T>
11where
12    T: CoordFloat,
13{
14    type Error = Error;
15
16    fn try_from(value: &geometry::Value) -> Result<Self> {
17        match value {
18            geometry::Value::Point(point_type) => Ok(create_geo_point(point_type)),
19            other => Err(mismatch_geom_err("Point", other)),
20        }
21    }
22}
23try_from_owned_value!(geo_types::Point<T>);
24
25#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
26impl<T> TryFrom<&geometry::Value> for geo_types::MultiPoint<T>
27where
28    T: CoordFloat,
29{
30    type Error = Error;
31
32    fn try_from(value: &geometry::Value) -> Result<Self> {
33        match value {
34            geometry::Value::MultiPoint(multi_point_type) => Ok(geo_types::MultiPoint(
35                multi_point_type
36                    .iter()
37                    .map(|point_type| create_geo_point(point_type))
38                    .collect(),
39            )),
40            other => Err(mismatch_geom_err("MultiPoint", other)),
41        }
42    }
43}
44try_from_owned_value!(geo_types::MultiPoint<T>);
45
46#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
47impl<T> TryFrom<&geometry::Value> for geo_types::LineString<T>
48where
49    T: CoordFloat,
50{
51    type Error = Error;
52
53    fn try_from(value: &geometry::Value) -> Result<Self> {
54        match value {
55            geometry::Value::LineString(multi_point_type) => {
56                Ok(create_geo_line_string(multi_point_type))
57            }
58            other => Err(mismatch_geom_err("LineString", other)),
59        }
60    }
61}
62try_from_owned_value!(geo_types::LineString<T>);
63
64#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
65impl<T> TryFrom<&geometry::Value> for geo_types::MultiLineString<T>
66where
67    T: CoordFloat,
68{
69    type Error = Error;
70
71    fn try_from(value: &geometry::Value) -> Result<Self> {
72        match value {
73            geometry::Value::MultiLineString(multi_line_string_type) => {
74                Ok(create_geo_multi_line_string(multi_line_string_type))
75            }
76            other => Err(mismatch_geom_err("MultiLineString", other)),
77        }
78    }
79}
80try_from_owned_value!(geo_types::MultiLineString<T>);
81
82#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
83impl<T> TryFrom<&geometry::Value> for geo_types::Polygon<T>
84where
85    T: CoordFloat,
86{
87    type Error = Error;
88
89    fn try_from(value: &geometry::Value) -> Result<Self> {
90        match value {
91            geometry::Value::Polygon(polygon_type) => Ok(create_geo_polygon(polygon_type)),
92            other => Err(mismatch_geom_err("Polygon", other)),
93        }
94    }
95}
96try_from_owned_value!(geo_types::Polygon<T>);
97
98#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
99impl<T> TryFrom<&geometry::Value> for geo_types::MultiPolygon<T>
100where
101    T: CoordFloat,
102{
103    type Error = Error;
104
105    fn try_from(value: &geometry::Value) -> Result<geo_types::MultiPolygon<T>> {
106        match value {
107            geometry::Value::MultiPolygon(multi_polygon_type) => {
108                Ok(create_geo_multi_polygon(multi_polygon_type))
109            }
110            other => Err(mismatch_geom_err("MultiPolygon", other)),
111        }
112    }
113}
114try_from_owned_value!(geo_types::MultiPolygon<T>);
115
116#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
117impl<T> TryFrom<&geometry::Value> for geo_types::GeometryCollection<T>
118where
119    T: CoordFloat,
120{
121    type Error = Error;
122
123    fn try_from(value: &geometry::Value) -> Result<Self> {
124        match value {
125            geometry::Value::GeometryCollection(geometries) => {
126                let geojson_geometries = geometries
127                    .iter()
128                    .map(|geometry| (&geometry.value).try_into().unwrap())
129                    .collect();
130
131                Ok(geo_types::GeometryCollection(geojson_geometries))
132            }
133            other => Err(mismatch_geom_err("GeometryCollection", other)),
134        }
135    }
136}
137try_from_owned_value!(geo_types::GeometryCollection<T>);
138
139#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
140impl<T> TryFrom<&geometry::Value> for geo_types::Geometry<T>
141where
142    T: CoordFloat,
143{
144    type Error = Error;
145
146    fn try_from(value: &geometry::Value) -> Result<Self> {
147        match value {
148            geometry::Value::Point(ref point_type) => {
149                Ok(geo_types::Geometry::Point(create_geo_point(point_type)))
150            }
151            geometry::Value::MultiPoint(ref multi_point_type) => {
152                Ok(geo_types::Geometry::MultiPoint(geo_types::MultiPoint(
153                    multi_point_type
154                        .iter()
155                        .map(|point_type| create_geo_point(point_type))
156                        .collect(),
157                )))
158            }
159            geometry::Value::LineString(ref line_string_type) => Ok(
160                geo_types::Geometry::LineString(create_geo_line_string(line_string_type)),
161            ),
162            geometry::Value::MultiLineString(ref multi_line_string_type) => {
163                Ok(geo_types::Geometry::MultiLineString(
164                    create_geo_multi_line_string(multi_line_string_type),
165                ))
166            }
167            geometry::Value::Polygon(ref polygon_type) => Ok(geo_types::Geometry::Polygon(
168                create_geo_polygon(polygon_type),
169            )),
170            geometry::Value::MultiPolygon(ref multi_polygon_type) => Ok(
171                geo_types::Geometry::MultiPolygon(create_geo_multi_polygon(multi_polygon_type)),
172            ),
173            geometry::Value::GeometryCollection(ref gc_type) => {
174                let gc = geo_types::Geometry::GeometryCollection(geo_types::GeometryCollection(
175                    gc_type
176                        .iter()
177                        .cloned()
178                        .map(|geom| geom.try_into())
179                        .collect::<Result<Vec<geo_types::Geometry<T>>>>()?,
180                ));
181                Ok(gc)
182            }
183        }
184    }
185}
186try_from_owned_value!(geo_types::Geometry<T>);
187
188macro_rules! impl_try_from_geom_value {
189    ($($kind:ident),*) => {
190        $(
191            #[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
192            impl<T> TryFrom<&$crate::Geometry> for geo_types::$kind<T>
193            where
194                T: CoordFloat,
195            {
196                type Error = Error;
197
198                fn try_from(geometry: &crate::Geometry) -> Result<Self> {
199                    Self::try_from(&geometry.value)
200                }
201            }
202
203            #[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
204            impl<T> TryFrom<$crate::Geometry> for geo_types::$kind<T>
205            where
206                T: CoordFloat,
207            {
208                type Error = Error;
209
210                fn try_from(geometry: crate::Geometry) -> Result<Self> {
211                    Self::try_from(geometry.value)
212                }
213            }
214
215            #[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
216            impl<T> TryFrom<$crate::Feature> for geo_types::$kind<T>
217            where
218                T: CoordFloat,
219            {
220                type Error = Error;
221
222                fn try_from(val: Feature) -> Result<Self> {
223                    match val.geometry {
224                        None => Err(Error::FeatureHasNoGeometry(val)),
225                        Some(geom) => geom.try_into(),
226                    }
227                }
228            }
229        )*
230    }
231}
232
233impl_try_from_geom_value![
234    Point,
235    LineString,
236    Polygon,
237    MultiPoint,
238    MultiLineString,
239    MultiPolygon,
240    Geometry,
241    GeometryCollection
242];
243
244impl<T: CoordFloat> TryFrom<&GeoJson> for geo_types::GeometryCollection<T> {
245    type Error = Error;
246
247    /// Process top-level `GeoJSON` items, returning a geo_types::GeometryCollection or an Error
248    fn try_from(gj: &GeoJson) -> Result<geo_types::GeometryCollection<T>>
249    where
250        T: CoordFloat,
251    {
252        match gj {
253            GeoJson::FeatureCollection(collection) => Ok(geo_types::GeometryCollection(
254                collection
255                    .features
256                    .iter()
257                    // Only pass on non-empty geometries
258                    .filter_map(|feature| feature.geometry.as_ref())
259                    .map(|geometry| geometry.clone().try_into())
260                    .collect::<Result<_>>()?,
261            )),
262            GeoJson::Feature(feature) => {
263                if let Some(geometry) = &feature.geometry {
264                    Ok(geo_types::GeometryCollection(vec![geometry
265                        .clone()
266                        .try_into()?]))
267                } else {
268                    Ok(geo_types::GeometryCollection(vec![]))
269                }
270            }
271            GeoJson::Geometry(geometry) => Ok(geo_types::GeometryCollection(vec![geometry
272                .clone()
273                .try_into()?])),
274        }
275    }
276}
277
278#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
279impl<T> TryFrom<FeatureCollection> for geo_types::Geometry<T>
280where
281    T: CoordFloat,
282{
283    type Error = Error;
284
285    fn try_from(val: FeatureCollection) -> Result<geo_types::Geometry<T>> {
286        Ok(geo_types::Geometry::GeometryCollection(
287            geo_types::GeometryCollection::try_from(&GeoJson::FeatureCollection(val))?,
288        ))
289    }
290}
291
292#[cfg_attr(docsrs, doc(cfg(feature = "geo-types")))]
293impl<T> TryFrom<GeoJson> for geo_types::Geometry<T>
294where
295    T: CoordFloat,
296{
297    type Error = Error;
298
299    fn try_from(val: GeoJson) -> Result<geo_types::Geometry<T>> {
300        match val {
301            GeoJson::Geometry(geom) => geom.try_into(),
302            GeoJson::Feature(feat) => feat.try_into(),
303            GeoJson::FeatureCollection(fc) => fc.try_into(),
304        }
305    }
306}
307
308fn create_geo_coordinate<T>(point_type: &PointType) -> geo_types::Coord<T>
309where
310    T: CoordFloat,
311{
312    geo_types::Coord {
313        x: T::from(point_type[0]).unwrap(),
314        y: T::from(point_type[1]).unwrap(),
315    }
316}
317
318fn create_geo_point<T>(point_type: &PointType) -> geo_types::Point<T>
319where
320    T: CoordFloat,
321{
322    geo_types::Point::new(
323        T::from(point_type[0]).unwrap(),
324        T::from(point_type[1]).unwrap(),
325    )
326}
327
328fn create_geo_line_string<T>(line_type: &LineStringType) -> geo_types::LineString<T>
329where
330    T: CoordFloat,
331{
332    geo_types::LineString(
333        line_type
334            .iter()
335            .map(|point_type| create_geo_coordinate(point_type))
336            .collect(),
337    )
338}
339
340fn create_geo_multi_line_string<T>(
341    multi_line_type: &[LineStringType],
342) -> geo_types::MultiLineString<T>
343where
344    T: CoordFloat,
345{
346    geo_types::MultiLineString(
347        multi_line_type
348            .iter()
349            .map(|point_type| create_geo_line_string(point_type))
350            .collect(),
351    )
352}
353
354fn create_geo_polygon<T>(polygon_type: &PolygonType) -> geo_types::Polygon<T>
355where
356    T: CoordFloat,
357{
358    let exterior = polygon_type
359        .first()
360        .map(|e| create_geo_line_string(e))
361        .unwrap_or_else(|| create_geo_line_string(&vec![]));
362
363    let interiors = if polygon_type.len() < 2 {
364        vec![]
365    } else {
366        polygon_type[1..]
367            .iter()
368            .map(|line_string_type| create_geo_line_string(line_string_type))
369            .collect()
370    };
371
372    geo_types::Polygon::new(exterior, interiors)
373}
374
375fn create_geo_multi_polygon<T>(multi_polygon_type: &[PolygonType]) -> geo_types::MultiPolygon<T>
376where
377    T: CoordFloat,
378{
379    geo_types::MultiPolygon(
380        multi_polygon_type
381            .iter()
382            .map(|polygon_type| create_geo_polygon(polygon_type))
383            .collect(),
384    )
385}
386
387fn mismatch_geom_err(expected_type: &'static str, found: &geometry::Value) -> Error {
388    Error::InvalidGeometryConversion {
389        expected_type,
390        found_type: found.type_name(),
391    }
392}
393
394#[cfg(test)]
395mod tests {
396    use crate::{Geometry, Value};
397    use serde_json::json;
398
399    use std::convert::TryInto;
400
401    #[test]
402    fn geojson_point_conversion_test() {
403        let coords = vec![100.0, 0.2];
404        let geojson_point = Value::Point(coords.clone());
405        let geo_point: geo_types::Point<f64> = geojson_point.try_into().unwrap();
406
407        assert_almost_eq!(geo_point.x(), coords[0], 1e-6);
408        assert_almost_eq!(geo_point.y(), coords[1], 1e-6);
409    }
410
411    #[test]
412    fn geojson_multi_point_conversion_test() {
413        let coord1 = vec![100.0, 0.2];
414        let coord2 = vec![101.0, 1.0];
415        let geojson_multi_point = Value::MultiPoint(vec![coord1.clone(), coord2.clone()]);
416        let geo_multi_point: geo_types::MultiPoint<f64> = geojson_multi_point.try_into().unwrap();
417
418        assert_almost_eq!(geo_multi_point.0[0].x(), coord1[0], 1e-6);
419        assert_almost_eq!(geo_multi_point.0[0].y(), coord1[1], 1e-6);
420        assert_almost_eq!(geo_multi_point.0[1].x(), coord2[0], 1e-6);
421        assert_almost_eq!(geo_multi_point.0[1].y(), coord2[1], 1e-6);
422    }
423
424    #[test]
425    fn geojson_line_string_conversion_test() {
426        let coord1 = vec![100.0, 0.2];
427        let coord2 = vec![101.0, 1.0];
428        let geojson_line_string = Value::LineString(vec![coord1.clone(), coord2.clone()]);
429        let geo_line_string: geo_types::LineString<f64> = geojson_line_string.try_into().unwrap();
430
431        assert_almost_eq!(geo_line_string.0[0].x, coord1[0], 1e-6);
432        assert_almost_eq!(geo_line_string.0[0].y, coord1[1], 1e-6);
433        assert_almost_eq!(geo_line_string.0[1].x, coord2[0], 1e-6);
434        assert_almost_eq!(geo_line_string.0[1].y, coord2[1], 1e-6);
435    }
436
437    #[test]
438    fn geojson_multi_line_string_conversion_test() {
439        let coord1 = vec![100.0, 0.2];
440        let coord2 = vec![101.0, 1.0];
441        let coord3 = vec![102.0, 0.8];
442        let geojson_multi_line_string = Value::MultiLineString(vec![
443            vec![coord1.clone(), coord2.clone()],
444            vec![coord2.clone(), coord3.clone()],
445        ]);
446        let geo_multi_line_string: geo_types::MultiLineString<f64> =
447            geojson_multi_line_string.try_into().unwrap();
448
449        let geo_line_string1 = &geo_multi_line_string.0[0];
450        assert_almost_eq!(geo_line_string1.0[0].x, coord1[0], 1e-6);
451        assert_almost_eq!(geo_line_string1.0[0].y, coord1[1], 1e-6);
452        assert_almost_eq!(geo_line_string1.0[1].x, coord2[0], 1e-6);
453        assert_almost_eq!(geo_line_string1.0[1].y, coord2[1], 1e-6);
454
455        let geo_line_string2 = &geo_multi_line_string.0[1];
456        assert_almost_eq!(geo_line_string2.0[0].x, coord2[0], 1e-6);
457        assert_almost_eq!(geo_line_string2.0[0].y, coord2[1], 1e-6);
458        assert_almost_eq!(geo_line_string2.0[1].x, coord3[0], 1e-6);
459        assert_almost_eq!(geo_line_string2.0[1].y, coord3[1], 1e-6);
460    }
461
462    #[test]
463    fn geojson_polygon_conversion_test() {
464        let coord1 = vec![100.0, 0.0];
465        let coord2 = vec![101.0, 1.0];
466        let coord3 = vec![101.0, 1.0];
467        let coord4 = vec![104.0, 0.2];
468        let coord5 = vec![100.9, 0.2];
469        let coord6 = vec![100.9, 0.7];
470
471        let geojson_multi_line_string_type1 = vec![
472            vec![
473                coord1.clone(),
474                coord2.clone(),
475                coord3.clone(),
476                coord1.clone(),
477            ],
478            vec![
479                coord4.clone(),
480                coord5.clone(),
481                coord6.clone(),
482                coord4.clone(),
483            ],
484        ];
485        let geojson_polygon = Value::Polygon(geojson_multi_line_string_type1);
486        let geo_polygon: geo_types::Polygon<f64> = geojson_polygon.try_into().unwrap();
487
488        let geo_line_string1 = geo_polygon.exterior();
489        assert_almost_eq!(geo_line_string1.0[0].x, coord1[0], 1e-6);
490        assert_almost_eq!(geo_line_string1.0[0].y, coord1[1], 1e-6);
491        assert_almost_eq!(geo_line_string1.0[1].x, coord2[0], 1e-6);
492        assert_almost_eq!(geo_line_string1.0[1].y, coord2[1], 1e-6);
493        assert_almost_eq!(geo_line_string1.0[2].x, coord3[0], 1e-6);
494        assert_almost_eq!(geo_line_string1.0[2].y, coord3[1], 1e-6);
495        assert_almost_eq!(geo_line_string1.0[3].x, coord1[0], 1e-6);
496        assert_almost_eq!(geo_line_string1.0[3].y, coord1[1], 1e-6);
497
498        let geo_line_string2 = &geo_polygon.interiors()[0];
499        assert_almost_eq!(geo_line_string2.0[0].x, coord4[0], 1e-6);
500        assert_almost_eq!(geo_line_string2.0[0].y, coord4[1], 1e-6);
501        assert_almost_eq!(geo_line_string2.0[1].x, coord5[0], 1e-6);
502        assert_almost_eq!(geo_line_string2.0[1].y, coord5[1], 1e-6);
503        assert_almost_eq!(geo_line_string2.0[2].x, coord6[0], 1e-6);
504        assert_almost_eq!(geo_line_string2.0[2].y, coord6[1], 1e-6);
505        assert_almost_eq!(geo_line_string2.0[3].x, coord4[0], 1e-6);
506        assert_almost_eq!(geo_line_string2.0[3].y, coord4[1], 1e-6);
507    }
508
509    #[test]
510    fn geojson_empty_polygon_conversion_test() {
511        let geojson_polygon = Value::Polygon(vec![]);
512        let geo_polygon: geo_types::Polygon<f64> = geojson_polygon.try_into().unwrap();
513
514        assert!(geo_polygon.exterior().0.is_empty());
515    }
516
517    #[test]
518    fn geojson_polygon_without_interiors_conversion_test() {
519        let coord1 = vec![100.0, 0.0];
520        let coord2 = vec![101.0, 1.0];
521        let coord3 = vec![101.0, 1.0];
522
523        let geojson_multi_line_string_type1 = vec![vec![
524            coord1.clone(),
525            coord2.clone(),
526            coord3.clone(),
527            coord1.clone(),
528        ]];
529        let geojson_polygon = Value::Polygon(geojson_multi_line_string_type1);
530        let geo_polygon: geo_types::Polygon<f64> = geojson_polygon.try_into().unwrap();
531
532        let geo_line_string1 = geo_polygon.exterior();
533        assert_almost_eq!(geo_line_string1.0[0].x, coord1[0], 1e-6);
534        assert_almost_eq!(geo_line_string1.0[0].y, coord1[1], 1e-6);
535        assert_almost_eq!(geo_line_string1.0[1].x, coord2[0], 1e-6);
536        assert_almost_eq!(geo_line_string1.0[1].y, coord2[1], 1e-6);
537        assert_almost_eq!(geo_line_string1.0[2].x, coord3[0], 1e-6);
538        assert_almost_eq!(geo_line_string1.0[2].y, coord3[1], 1e-6);
539        assert_almost_eq!(geo_line_string1.0[3].x, coord1[0], 1e-6);
540        assert_almost_eq!(geo_line_string1.0[3].y, coord1[1], 1e-6);
541
542        assert_eq!(0, geo_polygon.interiors().len());
543    }
544
545    #[test]
546    fn geojson_multi_polygon_conversion_test() {
547        let coord1 = vec![100.0, 0.0];
548        let coord2 = vec![101.0, 1.0];
549        let coord3 = vec![101.0, 1.0];
550        let coord4 = vec![104.0, 0.2];
551        let coord5 = vec![100.9, 0.2];
552        let coord6 = vec![100.9, 0.7];
553
554        let geojson_line_string_type1 = vec![
555            coord1.clone(),
556            coord2.clone(),
557            coord3.clone(),
558            coord1.clone(),
559        ];
560
561        let geojson_line_string_type2 = vec![
562            coord4.clone(),
563            coord5.clone(),
564            coord6.clone(),
565            coord4.clone(),
566        ];
567        let geojson_multi_polygon = Value::MultiPolygon(vec![
568            vec![geojson_line_string_type1],
569            vec![geojson_line_string_type2],
570        ]);
571        let geo_multi_polygon: geo_types::MultiPolygon<f64> =
572            geojson_multi_polygon.try_into().unwrap();
573
574        let geo_line_string1 = geo_multi_polygon.0[0].exterior();
575        assert_almost_eq!(geo_line_string1.0[0].x, coord1[0], 1e-6);
576        assert_almost_eq!(geo_line_string1.0[0].y, coord1[1], 1e-6);
577        assert_almost_eq!(geo_line_string1.0[1].x, coord2[0], 1e-6);
578        assert_almost_eq!(geo_line_string1.0[1].y, coord2[1], 1e-6);
579        assert_almost_eq!(geo_line_string1.0[2].x, coord3[0], 1e-6);
580        assert_almost_eq!(geo_line_string1.0[2].y, coord3[1], 1e-6);
581        assert_almost_eq!(geo_line_string1.0[3].x, coord1[0], 1e-6);
582        assert_almost_eq!(geo_line_string1.0[3].y, coord1[1], 1e-6);
583
584        let geo_line_string2 = geo_multi_polygon.0[1].exterior();
585        assert_almost_eq!(geo_line_string2.0[0].x, coord4[0], 1e-6);
586        assert_almost_eq!(geo_line_string2.0[0].y, coord4[1], 1e-6);
587        assert_almost_eq!(geo_line_string2.0[1].x, coord5[0], 1e-6);
588        assert_almost_eq!(geo_line_string2.0[1].y, coord5[1], 1e-6);
589        assert_almost_eq!(geo_line_string2.0[2].x, coord6[0], 1e-6);
590        assert_almost_eq!(geo_line_string2.0[2].y, coord6[1], 1e-6);
591        assert_almost_eq!(geo_line_string2.0[3].x, coord4[0], 1e-6);
592        assert_almost_eq!(geo_line_string2.0[3].y, coord4[1], 1e-6);
593    }
594
595    #[test]
596    fn geojson_geometry_collection_conversion_test() {
597        let coord1 = vec![100.0, 0.0];
598        let coord2 = vec![100.0, 1.0];
599        let coord3 = vec![101.0, 1.0];
600        let coord4 = vec![102.0, 0.0];
601        let coord5 = vec![101.0, 0.0];
602
603        let geojson_multi_point = Value::MultiPoint(vec![coord1.clone(), coord2.clone()]);
604        let geojson_multi_line_string = Value::MultiLineString(vec![
605            vec![coord1.clone(), coord2.clone()],
606            vec![coord2.clone(), coord3.clone()],
607        ]);
608        let geojson_multi_polygon = Value::MultiPolygon(vec![
609            vec![vec![
610                coord3.clone(),
611                coord4.clone(),
612                coord5.clone(),
613                coord3.clone(),
614            ]],
615            vec![vec![
616                coord1.clone(),
617                coord5.clone(),
618                coord3.clone(),
619                coord1.clone(),
620            ]],
621        ]);
622
623        let geojson_geometry_collection = Value::GeometryCollection(vec![
624            Geometry::new(geojson_multi_point),
625            Geometry::new(geojson_multi_line_string),
626            Geometry::new(geojson_multi_polygon),
627        ]);
628
629        let geo_geometry_collection: geo_types::GeometryCollection<f64> =
630            geojson_geometry_collection.try_into().unwrap();
631
632        assert_eq!(3, geo_geometry_collection.0.len());
633    }
634
635    #[test]
636    fn geojson_geometry_conversion() {
637        let coords = vec![100.0, 0.2];
638        let geojson_geometry = Geometry::from(Value::Point(coords.clone()));
639        let geo_geometry: geo_types::Geometry<f64> = geojson_geometry
640            .try_into()
641            .expect("Should be able to convert to geo_types::Geometry");
642        let geo_point: geo_types::Point<_> =
643            geo_geometry.try_into().expect("this should be a point");
644        assert_almost_eq!(geo_point.x(), coords[0], 1e-6);
645        assert_almost_eq!(geo_point.y(), coords[1], 1e-6);
646    }
647
648    #[test]
649    fn geojson_mismatch_geometry_conversion_test() {
650        let coord1 = vec![100.0, 0.2];
651        let coord2 = vec![101.0, 1.0];
652        let geojson_line_string = Value::LineString(vec![coord1.clone(), coord2.clone()]);
653        use std::convert::TryFrom;
654        let error = geo_types::Point::<f64>::try_from(geojson_line_string).unwrap_err();
655        assert_eq!(
656            "Expected type: `Point`, but found `LineString`",
657            format!("{}", error)
658        )
659    }
660
661    #[test]
662    fn feature_collection_with_geom_collection() {
663        let geojson_str = json!({
664            "type": "FeatureCollection",
665            "features": [
666            {
667                "type": "Feature",
668                "geometry": {
669                    "type": "GeometryCollection",
670                    "geometries": [
671                    {
672                        "type": "Polygon",
673                        "coordinates": [
674                            [
675                                [1.0, 1.0],
676                                [2.0, 2.0],
677                                [3.0, 1.0],
678                                [1.0, 1.0]
679                            ]
680                        ]
681                    }
682                    ]
683                },
684                "properties": {}
685            }
686            ]
687        })
688        .to_string();
689        let geojson: crate::GeoJson = geojson_str.parse().unwrap();
690        let mut geojson_feature_collection: crate::FeatureCollection = geojson.try_into().unwrap();
691        let feature: crate::Feature = geojson_feature_collection.features.remove(0);
692
693        use std::convert::TryFrom;
694        let geo_geom = geo_types::Geometry::try_from(feature).unwrap();
695
696        let expected =
697            geo_types::Geometry::GeometryCollection(geo_types::GeometryCollection(vec![
698                geo_types::Geometry::Polygon(geo_types::Polygon::new(
699                    geo_types::LineString::new(vec![
700                        geo_types::coord!(x: 1.0, y: 1.0),
701                        geo_types::coord!(x: 2.0, y: 2.0),
702                        geo_types::coord!(x: 3.0, y: 1.0),
703                        geo_types::coord!(x: 1.0, y: 1.0),
704                    ]),
705                    vec![],
706                )),
707            ]));
708        assert_eq!(geo_geom, expected);
709    }
710
711    #[test]
712    fn borrowed_value_conversions_test() -> crate::Result<()> {
713        let coord1 = vec![100.0, 0.2];
714        let coord2 = vec![101.0, 1.0];
715        let coord3 = vec![102.0, 0.8];
716        let coord4 = vec![104.0, 0.2];
717
718        let geojson_point = Value::Point(coord1.clone());
719        let _: geo_types::Point<f64> = (&geojson_point).try_into()?;
720
721        let geojson_multi_point = Value::MultiPoint(vec![coord1.clone(), coord2.clone()]);
722        let _: geo_types::MultiPoint<f64> = (&geojson_multi_point).try_into()?;
723
724        let geojson_line_string = Value::LineString(vec![coord1.clone(), coord2.clone()]);
725        let _: geo_types::LineString<f64> = (&geojson_line_string).try_into()?;
726
727        let geojson_multi_line_string = Value::MultiLineString(vec![
728            vec![coord1.clone(), coord2.clone()],
729            vec![coord2.clone(), coord3.clone()],
730        ]);
731        let _: geo_types::MultiLineString<f64> = (&geojson_multi_line_string).try_into()?;
732
733        let geojson_multi_line_string_type1 = vec![
734            vec![
735                coord1.clone(),
736                coord2.clone(),
737                coord3.clone(),
738                coord1.clone(),
739            ],
740            vec![
741                coord4.clone(),
742                coord1.clone(),
743                coord2.clone(),
744                coord4.clone(),
745            ],
746        ];
747        let geojson_polygon = Value::Polygon(geojson_multi_line_string_type1);
748        let _: geo_types::Polygon<f64> = (&geojson_polygon).try_into()?;
749
750        let geojson_line_string_type1 = vec![
751            coord1.clone(),
752            coord2.clone(),
753            coord3.clone(),
754            coord1.clone(),
755        ];
756
757        let geojson_line_string_type2 = vec![
758            coord4.clone(),
759            coord3.clone(),
760            coord2.clone(),
761            coord4.clone(),
762        ];
763        let geojson_multi_polygon = Value::MultiPolygon(vec![
764            vec![geojson_line_string_type1],
765            vec![geojson_line_string_type2],
766        ]);
767        let _: geo_types::MultiPolygon<f64> = (&geojson_multi_polygon).try_into()?;
768
769        let geojson_geometry_collection = Value::GeometryCollection(vec![
770            Geometry::new(geojson_multi_point),
771            Geometry::new(geojson_multi_line_string),
772            Geometry::new(geojson_multi_polygon),
773        ]);
774
775        let _: geo_types::GeometryCollection<f64> = (&geojson_geometry_collection).try_into()?;
776
777        Ok(())
778    }
779}